Technology

TypeScript / Python API Tutorial

A hands-on tutorial that walks through building simple CRUD APIs with several popular frameworks. Each framework lives in its own sub-folder and is demonstrated through a shared Next.js UI.

20 min read
Published

Complete Tutorial Code

Follow along with the complete source code for this tutorial. Includes five framework implementations — Next.js, Express, NestJS, Flask, and FastAPI — all demonstrated through a shared Next.js UI.

View on GitHub

Why Compare These Frameworks?

Choosing the right API framework is one of the most consequential decisions in a project. Next.js, Express, NestJS, Flask, and FastAPI each represent a different philosophy — from minimal and unopinionated to structured and feature-rich. This tutorial lets you build the same CRUD API in all five frameworks side by side, so you can see the trade-offs first-hand rather than just reading about them.

Framework Comparison at a Glance

Not sure which framework to reach for? Here is a quick reference across the five frameworks covered in this tutorial.

NE

Next.js

Language: TypeScriptType: Full-stack React frameworkRouting: File-system (app/api/route.ts)Validation: ZodLearning curve: Low–MediumBest for: Full-stack web apps
OpinionatedBuilt-in DIAuto-generated docsAsync support
EX

Express

Language: TypeScriptType: Minimal Node.js web frameworkRouting: Imperative (app.get(...))Validation: ZodLearning curve: LowBest for: Simple APIs, microservices, prototypes
OpinionatedBuilt-in DIAuto-generated docsAsync support
NE

NestJS

Language: TypeScriptType: Structured Node.js frameworkRouting: Decorators (@Get())Validation: ZodLearning curve: Medium–HighBest for: Large, structured backend APIs
OpinionatedBuilt-in DIAuto-generated docsAsync support
FL

Flask

Language: PythonType: Minimal Python web frameworkRouting: Decorators (@app.route(...))Validation: PydanticLearning curve: LowBest for: Python APIs, data science backends
OpinionatedBuilt-in DIAuto-generated docsAsync support
FA

FastAPI

Language: PythonType: Modern async Python web frameworkRouting: Decorators (@app.get(...))Validation: Pydantic (built-in)Learning curve: Low–MediumBest for: High-performance Python APIs, ML serving
OpinionatedBuilt-in DIAuto-generated docsAsync support

Project Structure

Each framework lives in its own sub-folder. A shared Next.js UI at port 3000 drives all five backends, so you can switch between them without leaving the browser.

ts-python-api-tutorial/
├── nextjs/          # Next.js app (UI + API route handlers)        → port 3000
├── express/         # Express.js REST API                          → port 3001
├── nestjs/          # NestJS REST API                              → port 3002
├── flask-api/       # Flask REST API (Python, managed with UV)     → port 3003
├── fastapi-api/     # FastAPI REST API (Python, managed with UV)   → port 3004
├── docs/            # Per-tab documentation
│   ├── nextjs.md
│   ├── express.md
│   ├── nestjs.md
│   ├── advanced-nestjs.md
│   └── flask.md
└── scripts/
    └── start-servers.sh  # Starts all tutorial servers (Ctrl-C to stop all)

Prerequisites

  • Node.js ≥ 20.9 (required by Next.js 16)
  • npm — comes with Node.js
  • Python ≥ 3.9 and UV — for the Flask and FastAPI tabs

Install UV if you don't have it:

curl -LsSf https://astral.sh/uv/install.sh | sh

Quick Start

  1. 1
    Clone the repository:
    git clone https://github.com/audoir/ts-python-api-tutorial.git
  2. 2
    Install dependencies for each framework:

    Next.js

    cd nextjs && npm install

    Express

    cd ../express && npm install

    NestJS

    cd ../nestjs && npm install

    FastAPI (Flask uses UV on first run — no manual step needed)

    cd ../fastapi-api && uv sync
  3. 3
    Run all servers from the repo root:
    ./scripts/start-servers.sh

    Then open http://localhost:3000 in your browser. The script starts every tutorial server in the background and kills them all when you press Ctrl-C.

💡 Tip — Start servers individually

cd nextjs && npm run dev http://localhost:3000

cd express && npm run dev http://localhost:3001

cd nestjs && npm run dev http://localhost:3002

cd flask-api && uv run python main.py http://localhost:3003

cd fastapi-api && uv run uvicorn main:app --host 0.0.0.0 --port 3004 --reload http://localhost:3004

💡 Tip — FastAPI interactive docs

Once the FastAPI server is running you can explore the auto-generated API documentation at:

Framework Deep Dives

Each framework has its own advantages and disadvantages. Here is a detailed breakdown to help you decide which one fits your use case.

Next.js

Next.js is a full-stack React framework. API routes live alongside your UI in the same project — no CORS, no separate deploy. File-system routing maps app/api/route.ts directly to HTTP endpoints.

✅ Advantages

  • Frontend and backend in one project — no CORS, no separate deploy
  • File-system routing is intuitive for small projects
  • Server Components reduce client-side JavaScript
  • Excellent developer experience (Turbopack, hot reload)
  • Vercel deployment is seamless

❌ Disadvantages

  • API routes are not a first-class REST framework — no built-in guards, interceptors, or DI
  • Tightly coupled to React — not suitable if you need a standalone API
  • File-system routing can become hard to navigate in very large projects
  • Harder to test API routes in isolation
  • Vendor lock-in risk if you rely on Vercel-specific features

Express

Express is the most widely used Node.js web framework. It is extremely lightweight — almost no overhead — and gives you full control over routing, middleware, and error handling. Great for microservices and simple REST APIs.

✅ Advantages

  • Extremely lightweight — almost no overhead
  • You control everything — no magic, no hidden behaviour
  • Massive ecosystem (passport, multer, helmet, …)
  • Easy to learn — the entire API surface is small
  • Great for microservices and simple REST APIs

❌ Disadvantages

  • No enforced structure — large projects can become messy quickly
  • No built-in DI, guards, interceptors, or modules
  • Error handling requires discipline (easy to forget next(err))
  • TypeScript support requires manual type annotations for req, res
  • No built-in validation — you must wire up Zod/Joi/etc. yourself

NestJS

NestJS brings Angular-style architecture to Node.js. It enforces a module-based structure with built-in dependency injection, guards, interceptors, and pipes — making it the go-to choice for large, team-maintained backend APIs.

✅ Advantages

  • Enforced structure scales well to large teams
  • Built-in DI makes testing and swapping dependencies easy
  • Guards, interceptors, pipes, and filters are first-class concepts
  • Excellent TypeScript integration
  • Built on Express — all Express middleware works

❌ Disadvantages

  • Steeper learning curve — decorators, DI, and modules take time
  • More boilerplate for simple use cases
  • Requires experimentalDecorators and emitDecoratorMetadata in TypeScript
  • Heavier than Express — more dependencies, slower cold start
  • Angular-style architecture can feel unfamiliar

Flask

Flask is the Python equivalent of Express — minimal, unopinionated, and easy to get started with. It is a natural fit for data science and ML backends where the team already writes Python.

✅ Advantages

  • Extremely simple to get started — minimal boilerplate
  • Python ecosystem — great for data science, ML, and scripting
  • Pydantic provides powerful, Pythonic validation with type hints
  • UV makes dependency management fast and reproducible
  • Easy to integrate with SQLAlchemy, Celery, and other Python libraries

❌ Disadvantages

  • No enforced structure — large projects can become disorganised
  • No built-in async support (use Flask 2+ async views or switch to FastAPI)
  • No built-in DI, guards, or interceptors
  • Slower than Node.js for pure I/O-bound workloads
  • WSGI by default — requires extra setup for production (gunicorn, nginx)

FastAPI

FastAPI is the modern, async-first Python framework. Pydantic validation is built in, auto-generated Swagger and ReDoc docs come for free, and native async/await via ASGI (uvicorn) delivers performance comparable to Node.js frameworks.

✅ Advantages

  • Pydantic validation is built-in — request bodies are validated automatically
  • Auto-generates interactive API docs (Swagger UI at /docs, ReDoc at /redoc)
  • Native async/await support via ASGI (uvicorn)
  • Type hints drive both validation and editor autocompletion
  • Very high performance — comparable to Node.js frameworks
  • UV makes dependency management fast and reproducible

❌ Disadvantages

  • Async-first design can be confusing if you mix sync and async code
  • Smaller ecosystem than Flask — fewer third-party extensions
  • Requires uvicorn (or another ASGI server) — not WSGI-compatible
  • Dependency injection system is powerful but has a learning curve
  • Less mature than Flask for non-API use cases

When to Use Which

Building a React web app and want the API in the same projectNext.js
Deploying to Vercel or a similar platformNext.js
Building a simple REST API or microservice quicklyExpress
Prototyping or learning how HTTP servers workExpress
Building a large, team-maintained backend APINestJS
You need built-in DI, guards, and interceptorsNestJS
Your team primarily writes PythonFlask or FastAPI
You need to integrate with data science / ML librariesFlask or FastAPI
You need auto-generated API docs (Swagger / OpenAPI)FastAPI
You need high-performance async Python APIsFastAPI
You are serving an ML model or building a data APIFastAPI

Core Concepts Reference

New to web APIs, or encountering an unfamiliar term in one of the tab docs? The Core Concepts reference explains the foundational ideas that appear across all five frameworks.

HTTP and REST APIs

HTTP methods, status codes, and REST conventions

CRUD

Create, Read, Update, Delete — and how they map to HTTP

Middleware

The request pipeline and (req, res, next) functions

Routing

How each framework maps URLs to handler functions

Validation and Schemas

Zod (TypeScript) and Pydantic (Python) compared

Dependency Injection

What DI is and why NestJS uses it

Decorators

@Something annotations in TypeScript and Python

Modules

NestJS module system

Guards

NestJS request authorisation

Interceptors

NestJS response transformation

CORS

Why cross-origin requests are blocked and how to allow them

WSGI vs ASGI

Python server interfaces — Flask vs FastAPI

Sync vs Async

Synchronous and asynchronous request handling

In-Memory Store

Why this tutorial uses arrays/dicts instead of a database

OpenAPI / Swagger

Auto-generated API documentation

Tab Documentation

Detailed documentation for each tab lives in the docs/ folder of the repository:

Learn More