Path operations: FastAPI's version of a route#

← Back to FastAPI

One decorator per method, same path#

Compare this directly to solutions/notes_api.py. Its GET /notes and POST /notes were already two separate route declarations, not one function branching on request.method:

@app.route("/notes", methods=["GET"])
def list_notes():
    ...

@app.route("/notes", methods=["POST"])
def create_note():
    ...

The FastAPI version drops the methods=[...] list and folds the method straight into the decorator's name:

@app.get("/notes")
def list_notes():
    ...

@app.post("/notes")
def create_note():
    ...

Same path, "/notes", appearing on two separate decorators. FastAPI matches a path operation by path and method together, exactly the way Flask's methods=[...] did; nothing about that matching logic actually changed, only the spelling.

Running it#

Flask's app.py ended with if __name__ == "__main__": app.run(debug=True), so python app.py was the whole story. A FastAPI file usually has no such block at all; the fastapi command-line tool (installed by pip install "fastapi[standard]") finds the app object in your file and runs it for you: fastapi dev app.py starts a live server, by default at http://127.0.0.1:8000, and reloads automatically whenever you save, the same convenience debug=True gave you before.

What used to be jsonify#

Every Flask route in notes_api.py that returns actual data wraps it in jsonify(...), because Flask needs to be told explicitly "turn this Python value into a JSON response" (the one exception, delete_note's success path, returns a plain "", 204 instead, since there's no body to convert either way). A FastAPI path operation function just returns the value directly, a dict, a list, later a pydantic model, and FastAPI handles the conversion to JSON on its own, every time, without a wrapping call.

What to watch for#

  • Writing @app.route(...) out of Flask muscle memory. FastAPI has no .route(...) method; it's always a specific verb, .get, .post, .put, .delete, and so on.
  • Running a FastAPI file with plain python app.py and getting nothing. Without an app.run(...)-style call at the bottom, the file just defines things and exits; fastapi dev app.py is the separate command that actually starts the server.
  • Assuming two decorators on the same path string are somehow one route with two methods. They're two entirely separate path operations that happen to share a path; each has its own function, its own request handling, and (starting in the next note) its own request body shape.

TL;DR#

FastAPI apps are built the same way your Week 2 Flask app was, an application object, and decorators connecting a URL to a function, just split into one decorator per HTTP method instead of Flask's single @app.route(...) plus a methods list.

  • FastAPI() creates your application object, the same role Flask(__name__) played.
  • @app.get(...), @app.post(...), @app.put(...), and @app.delete(...) replace Flask's one @app.route(path, methods=[...]); the HTTP method is part of the decorator's name now, not a list you pass in.
  • A path operation function's return value becomes the JSON response automatically. A plain dict or list is enough; there's no jsonify(...) call anywhere.
  • fastapi dev app.py runs the app in development mode, FastAPI's answer to app.run(debug=True): it starts a live server and reloads on every save.
from fastapi import FastAPI

app = FastAPI()


@app.get("/notes")
def list_notes():
    return notes  # a list, not jsonify(notes): FastAPI converts it for you


@app.post("/notes")
def create_note():
    ...
fastapi dev app.py