Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallBuild a small Flask API by mapping HTTP methods and URL paths to Python functions, accepting and returning JSON, and assigning meaningful status codes. This tutorial creates an in-memory /items API, tests it without starting a server, and shows how to run it locally. Flask’s installation documentation currently lists Python 3.9 and newer as supported; check the official documentation for changes to that requirement.
What you will build
The example API stores items in memory and supports three operations:
GET /itemsreturns all items.GET /items/<id>returns one item or a JSON 404 error.POST /itemsvalidates a JSON body, creates an item, and returns it with HTTP 201.
This is a learning example, not persistent storage: the collection resets whenever the process restarts, and it is not shared between multiple application processes. The focus is route design, JSON handling, errors, and tests. Flask’s Quickstart documents the route and response mechanics used here.
Set up Flask
Use a virtual environment to keep this project’s dependencies separate from other Python projects. Flask’s installation guide recommends this workflow and documents its Python compatibility.
#1 Best Overall
- Create a project directory and enter it:
mkdir flask-api && cd flask-api. - Create a virtual environment:
python -m venv .venv. - Activate it. On macOS or Linux, run
source .venv/bin/activate. On Windows PowerShell, run.venvScriptsActivate.ps1. - Install Flask:
pip install Flask.
If the python command does not refer to a supported Python installation on your system, use the appropriate Python executable name, such as python3.
Create the API
Save this as app.py. The example uses explicit method declarations so it is clear which HTTP operations each route accepts. A Flask route accepts GET by default; other methods must be declared. Flask also supports method-specific decorators such as @app.get and @app.post.
from flask import Flask, abort, request
app = Flask(__name__)
# Teaching example only: data lives in memory and resets on restart.
items = {
1: {"id": 1, "name": "Notebook"},
2: {"id": 2, "name": "Pen"},
}
next_id = 3
@app.route("/items", methods=["GET"])
def list_items():
return list(items.values())
@app.route("/items/<int:item_id>", methods=["GET"])
def get_item(item_id):
item = items.get(item_id)
if item is None:
abort(404, description="Item not found")
return item
@app.route("/items", methods=["POST"])
def create_item():
global next_id
data = request.get_json(silent=True)
if not isinstance(data, dict):
return {"error": "Expected a JSON object"}, 400
name = data.get("name")
if not isinstance(name, str) or not name.strip():
return {"error": "'name' must be a non-empty string"}, 400
item = {"id": next_id, "name": name.strip()}
items[next_id] = item
next_id += 1
return item, 201
@app.errorhandler(404)
def not_found(error):
return {"error": error.description or "Not found"}, 404
@app.errorhandler(405)
def method_not_allowed(error):
return {"error": "Method not allowed for this endpoint"}, 405
if __name__ == "__main__":
app.run(debug=True)
Flask can convert a returned dictionary or list into a JSON response. The API reference also documents jsonify() for explicitly creating JSON responses. Values must be JSON-serializable; convert objects such as database models to dictionaries or other JSON-compatible values before returning them. See the Flask API reference.
Why validate the POST body?
A client may send malformed JSON, a JSON array instead of an object, or omit the required field. This endpoint treats those input problems as client errors and returns a 400 response with a short JSON explanation. It trims surrounding whitespace and rejects a blank name. In a larger API, define validation rules for every field and decide explicitly how to handle unknown fields, size limits, and content types.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
Why return 201 for a created item?
HTTP 201 communicates that the request created a resource. The response body contains the new representation, including its assigned ID. GET requests return the normal success status, while an unknown item produces 404 and an unsupported method produces 405. Flask’s error-handling documentation explains HTTP error handling and JSON error responses.
Call the endpoints
Start the local development server from the directory containing app.py:
flask --app app run --debug
The CLI starts the app for local work, normally at http://127.0.0.1:5000. Keep the server running in that terminal while making requests from another. The --debug option is useful during development because it enables the interactive debugger and reload behavior; do not expose it to untrusted users.
List items
curl -i http://127.0.0.1:5000/items
Expect a 200 response and a JSON array, for example [{"id":1,"name":"Notebook"},{"id":2,"name":"Pen"}].
Fetch one item
curl -i http://127.0.0.1:5000/items/1
Expect a 200 response with one JSON object. Request an ID that is not in the collection, such as /items/99, to see the JSON 404 response.
Send a POST request
curl -i -X POST http://127.0.0.1:5000/items
-H 'Content-Type: application/json'
-d '{"name":"Marker"}'
The Content-Type header tells the server that the request body is JSON. A successful request returns 201 and the created item. Omitting name, sending an empty name, or sending a non-object JSON value returns 400.
Test routes without running a server
Flask’s test client sends requests directly to the application, so a test does not need a live HTTP server. Its json request argument sets the JSON content type, and response.json gives access to the decoded response body. See Testing Flask Applications.
Create test_app.py:
import unittest
from app import app
class ItemApiTests(unittest.TestCase):
def setUp(self):
app.config["TESTING"] = True
self.client = app.test_client()
def test_list_items_returns_json(self):
response = self.client.get("/items")
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response.json, list)
self.assertEqual(response.json[0]["name"], "Notebook")
def test_missing_item_returns_json_404(self):
response = self.client.get("/items/999")
self.assertEqual(response.status_code, 404)
self.assertEqual(response.json["error"], "Item not found")
def test_post_creates_item(self):
response = self.client.post("/items", json={"name": "Marker"})
self.assertEqual(response.status_code, 201)
self.assertEqual(response.json["name"], "Marker")
self.assertIn("id", response.json)
def test_invalid_post_returns_400(self):
response = self.client.post("/items", json={"name": " "})
self.assertEqual(response.status_code, 400)
self.assertIn("error", response.json)
if __name__ == "__main__":
unittest.main()
Run the tests with python -m unittest. Because this example has mutable in-memory state, a test that creates an item can affect later tests in the same process. For a robust suite, provide a fresh application and data store per test, or reset test data in setup/teardown. Flask’s tutorial discusses structuring a project as it grows: Flask Tutorial.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Choose a route and JSON style
| Choice | Useful when | Trade-off |
|---|---|---|
One route function with methods=["GET", "POST"] |
Methods share substantial setup or logic. | Requires branching on the method and can make unrelated behavior harder to scan. |
Separate @app.get and @app.post functions |
Each operation has its own behavior, validation, and response. | May repeat small amounts of setup; Flask supports both method-specific decorators and explicit method lists. |
| Return a dict or list | The view simply returns JSON-compatible data. | Concise, but less explicit if you need to customize response headers or other response properties. |
Use jsonify() |
You want an explicit JSON response construction step. | More explicit, but not required for ordinary dict/list JSON output. |
For either style, keep URL paths resource-oriented, choose methods according to the operation, and make error response bodies consistent. A client should be able to distinguish an invalid request from a missing resource by both status and response shape.
Handle failures deliberately
- 400 Bad Request: use for malformed or invalid client input, as the POST example does.
- 404 Not Found: use when the requested resource does not exist.
- 405 Method Not Allowed: Flask returns this when a route exists but does not accept the requested method; the handler above gives it a consistent JSON body.
- 500 Internal Server Error: indicates an unexpected server-side failure. Flask documents default HTTP errors and error handlers; avoid returning internal exception details to clients.
Do not turn every failure into a successful response containing an error string. HTTP status codes are part of the API contract. For production applications, log unexpected failures privately, return a non-sensitive JSON error, and avoid masking programming errors with overly broad exception handlers. The official error-handling guide shows how to preserve HTTP status codes in JSON handlers.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Local development is not production deployment
flask --app app run and the built-in server are for development, not production traffic. The interactive debugger can execute code through its browser interface and must not be exposed publicly. Flask is a WSGI application; production deployment uses a production WSGI server and deployment configuration appropriate to the hosting environment. Follow the official deployment guidance rather than simply publishing the development server.
Before production, replace the in-memory dictionary with persistent storage, configure secrets outside source code, validate and limit inputs, define authentication and authorization where needed, and configure logging and error handling. These are application design responsibilities, not features provided automatically by a basic Flask route.
Recommended Free Tools
Best Value
Troubleshooting
flask: command not foundor not recognized: confirm the virtual environment is activated and Flask installed in it withpip show Flask. You can usepython -m flask --app app run --debugto invoke Flask through the selected Python interpreter.- Could not locate a Flask application: run the command in the directory containing
app.py, or specify the correct module with--app. - 404 on a route you expect: check the path spelling, trailing slash, and integer ID; verify the server is running the intended app.
- 405 when sending POST: ensure the route declares POST and that the request targets the correct path. The list endpoint intentionally accepts GET only.
- 400 on POST: send valid JSON with a string
namethat is not blank, and includeContent-Type: application/json. With curl, the shown-Hand-doptions provide these. - Unexpected 500: inspect the server-side traceback in the development terminal. Do not expose debug mode to diagnose a public production failure.
- Tests affect one another: the sample collection is global mutable state. Reset it for each test or redesign the app to create isolated instances and data stores.
Or skip the browser setup
If your goal is to capture how a page looks rather than build a Flask API that serves your own application data, ScreenshotNeo offers a separate website screenshot API. One GET request can return a PNG, JPEG, WebP, or PDF. The API accepts a URL and can return a clean screenshot; cookie/consent banners, newsletter popups, and chat widgets can be removed before capture, with each cleanup step configurable. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify the page verdict and billing status in headers. It also provides an MCP server for AI agents and supports 1,000 screenshots a month free without a card.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for configuration, and visit ScreenshotNeo for product details. Paid plans start at $5 for 3,000 shots.
Sign up for ScreenshotNeo free: 1,000 screenshots per month, no card required.
Frequently Asked Questions
Can I use a Flask test client without starting the development server?
Yes. Flask’s test client calls the application directly; it does not require a live server.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Does the example keep created items after the app restarts?
No. Its dictionary is in memory, so the example data resets when the process stops.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

