CodeBlanks Logo Icon CodeBlanks

FastAPI layer

Write REST endpoints with FastAPI.

FastAPI layer

The fourth layer adds an HTTP route with FastAPI. The @app.get("/tasks") decorator maps the read_tasks function to the /tasks route. The function queries the database with asyncio.run(fetch_tasks()).

from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()

@app.get("/tasks")
def read_tasks():
    return asyncio.run(fetch_tasks())

TestClient queries the app like an HTTP server; client.get("/tasks").text gives the response body. The response is converted from a Python list of dicts into structured data automatically.

Querying with TestClient

TestClient(app) queries the FastAPI app in memory. client.get("/tasks") returns a response object; .text gives the body, .status_code the status.

client = TestClient(app)
resp = client.get("/tasks")
print(resp.text)
print(resp.status_code)  # 200

The response body is the Python list converted into structured data. This lets you test the whole flow without running a server; it mimics a real HTTP request.

Practice Add the FastAPI route

The starting code contains the full previous solution (async + SQLAlchemy). Add the following:

  • from fastapi import FastAPI
  • from fastapi.testclient import TestClient
  • app = FastAPI()
  • With @app.get("/tasks") define def read_tasks(): whose body does return asyncio.run(fetch_tasks())
  • client = TestClient(app)
  • Print the response body with print(client.get("/tasks").text)

Starter code

main.py
import asyncio

async def fetch_tasks():
    return [{"id": 1, "title": "Görev 1"}, {"id": 2, "title": "Görev 2"}]

async def fetch_all():
    return await asyncio.gather(fetch_tasks(), fetch_tasks())

from sqlalchemy import create_engine, Column, Integer, String, StaticPool
from sqlalchemy.orm import declarative_base, sessionmaker

Base = declarative_base()

class Task(Base):
    __tablename__ = "tasks"
    id = Column(Integer, primary_key=True)
    title = Column(String)

engine = create_engine(
    "sqlite:///:memory:",
    connect_args={"check_same_thread": False},
    poolclass=StaticPool,
)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(Task(id=1, title="Görev 1"))
session.add(Task(id=2, title="Görev 2"))
session.commit()

async def fetch_tasks():
    return [{"id": t.id, "title": t.title} for t in session.query(Task).all()]

# bring in FastAPI from fastapi
# bring in TestClient from fastapi.testclient
# create the app by calling the FastAPI class
# bind read_tasks to the '/tasks' route via app.get, returning asyncio.run(fetch_tasks())
# query '/tasks' with TestClient and print the body

Sample solution

main.py
import asyncio

async def fetch_tasks():
    return [{"id": 1, "title": "Görev 1"}, {"id": 2, "title": "Görev 2"}]

async def fetch_all():
    return await asyncio.gather(fetch_tasks(), fetch_tasks())

from sqlalchemy import create_engine, Column, Integer, String, StaticPool
from sqlalchemy.orm import declarative_base, sessionmaker

Base = declarative_base()

class Task(Base):
    __tablename__ = "tasks"
    id = Column(Integer, primary_key=True)
    title = Column(String)

engine = create_engine(
    "sqlite:///:memory:",
    connect_args={"check_same_thread": False},
    poolclass=StaticPool,
)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(Task(id=1, title="Görev 1"))
session.add(Task(id=2, title="Görev 2"))
session.commit()

async def fetch_tasks():
    return [{"id": t.id, "title": t.title} for t in session.query(Task).all()]

from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()

@app.get("/tasks")
def read_tasks():
    return asyncio.run(fetch_tasks())

client = TestClient(app)
print(client.get("/tasks").text)

Expected output

[{"id":1,"title":"Görev 1"},{"id":2,"title":"Görev 2"}]

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does the @app.get("/tasks") decorator do?

  • Defines a decorator
  • Creates the database
  • Starts the asyncio loop
  • Maps read_tasks to the /tasks route Correct answer

Explanation: @app.get('/tasks') maps read_tasks to the /tasks route.

2 Complete the TestClient call

Question
from fastapi.testclient import TestClient

client = ____(app)
Answer
from fastapi.testclient import TestClient

client = TestClient(app)

Explanation: TestClient(app) creates a test client.

3 Match the FastAPI layer concepts

Term Meaning
FastAPI() Creates the app
@app.get Defines a route
TestClient Gives a client
.text Gives the body

All lessons in Advanced