FastAPI + React + Azure — Implementation Skill
This skill provides the concrete implementation detail for building an NHS service with the current default tech stack. It is referenced by the NHS Service Builder agent and can be swapped for an alternative (e.g. django-htmx-azure) when changing stacks.
Tech Stack
- Backend: Python 3.12 with FastAPI and Uvicorn — API-only (JSON)
- Frontend: React 18 with Vite and TypeScript, using nhsuk-react-components +
nhsuk-frontend CSS
- Design System: NHS.UK Frontend — all user-facing pages
- Testing: pytest + httpx (backend), Vitest (frontend) — write tests alongside features
- IaC: Terraform with
azurerm provider — see Terraform Azure Provider docs
- Hosting: Azure App Service on Linux (UK South region only)
- Secrets: Azure Key Vault, referenced via App Service configuration
- Monitoring: Azure Application Insights
Project Structure
app/
main.py # FastAPI app with CORS, middleware, health endpoint
routers/ # API route modules
middleware/ # Security, logging middleware
frontend/
src/
components/ # React components using nhsuk-react-components
pages/ # Page components
App.tsx # Root component with React Router
main.tsx # Entry point — imports nhsuk-frontend CSS
package.json
vite.config.ts
tsconfig.json
requirements.txt # Pinned Python dependencies
infra/
main.tf # Terraform resources
variables.tf # Input variables
outputs.tf # Output values
Scaffold Steps
Dependencies
- Create
requirements.txt with pinned production and dev dependencies:
fastapi, uvicorn[standard], pydantic, slowapi, python-multipart, structlog, httpx (production)
pytest, pytest-asyncio, httpx (testing)
pytest-playwright, axe-playwright-python (E2E testing — pre-installed in devcontainer, pinned here for CI)
ruff (linting)
- Pin exact versions (
==) — no loose ranges
Backend — FastAPI
- Set up FastAPI app in
app/main.py with:
- Security headers middleware (CSP, HSTS, X-Content-Type-Options)
- CORS middleware configured for the React dev server
- Rate limiting (slowapi)
GET /api/health returning { "status": "ok" } with 200
- Define routers in
app/routers/ using APIRouter(prefix="/api/v1/...", tags=[...])
- Use Pydantic models for all request/response schemas
- Use
async def for route handlers
Frontend — React + nhsuk-react-components
- Scaffold React app with Vite:
npm create vite@latest frontend -- --template react-ts
- Install:
npm install nhsuk-react-components nhsuk-frontend react-router-dom
- Import
nhsuk-frontend/dist/nhsuk.css in main.tsx
- Create NHS-branded layout with
<Header>, <Footer> from nhsuk-react-components
- Create the start page at
/
- Configure Vite to proxy
/api to FastAPI during development
Infrastructure — Terraform + Azure
- Write Terraform in
infra/ using var.app_name for resource naming:
- Resource Group, App Service Plan (Linux, B1), Linux Web App
- Key Vault with Managed Identity access policy
- Application Insights
- All in
uksouth region
- Run
terraform init && terraform plan to validate
Testing
- Write pytest tests for
/api/health using httpx AsyncClient
- Write Vitest tests for React components
- Target: 80% coverage
Build & Deploy Commands
# Backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# Frontend
cd frontend && npm ci && npm run dev
# Build for production
cd frontend && npm run build && cd ..
# Terraform
cd infra && terraform init && terraform plan -var="app_name=my-service" -out=tfplan
terraform apply tfplan
# Deploy to Azure
zip -r app.zip app/ frontend/dist/ requirements.txt
az webapp deploy \
--resource-group "rg-${APP_NAME}-dev" \
--name "app-${APP_NAME}-dev" \
--src-path app.zip --type zip
# Verify
curl https://app-${APP_NAME}-dev.azurewebsites.net/api/health
Troubleshooting
- If
terraform apply fails, read the error, fix the HCL, and re-run
- If
pytest fails, fix the code (not the test) unless the test is wrong
- If the Azure deployment fails, check logs with
az webapp log tail
- Always verify live by hitting the Azure URL with
curl
Source: marrobi/nhs-alpha-workshop — distributed by TomeVault.
1---2name: fastapi-react-azure3description: Use when scaffolding or building an NHS service with the FastAPI + React + Azure stack. Contains project structure, scaffold steps, and deployment commands.4---56# FastAPI + React + Azure — Implementation Skill78This skill provides the concrete implementation detail for building an NHS service with the current default tech stack. It is referenced by the NHS Service Builder agent and can be swapped for an alternative (e.g. `django-htmx-azure`) when changing stacks.910## Tech Stack1112- **Backend**: Python 3.12 with FastAPI and Uvicorn — API-only (JSON)13- **Frontend**: React 18 with Vite and TypeScript, using [nhsuk-react-components](https://github.com/NHSDigital/nhsuk-react-components) + `nhsuk-frontend` CSS14- **Design System**: [NHS.UK Frontend](https://service-manual.nhs.uk/design-system) — all user-facing pages15- **Testing**: pytest + httpx (backend), Vitest (frontend) — write tests alongside features16- **IaC**: Terraform with `azurerm` provider — see [Terraform Azure Provider docs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)17- **Hosting**: Azure App Service on Linux (UK South region only)18- **Secrets**: Azure Key Vault, referenced via App Service configuration19- **Monitoring**: Azure Application Insights2021## Project Structure2223```24app/25 main.py # FastAPI app with CORS, middleware, health endpoint26 routers/ # API route modules27 middleware/ # Security, logging middleware28frontend/29 src/30 components/ # React components using nhsuk-react-components31 pages/ # Page components32 App.tsx # Root component with React Router33 main.tsx # Entry point — imports nhsuk-frontend CSS34 package.json35 vite.config.ts36 tsconfig.json37requirements.txt # Pinned Python dependencies38infra/39 main.tf # Terraform resources40 variables.tf # Input variables41 outputs.tf # Output values42```4344## Scaffold Steps4546### Dependencies47481. Create `requirements.txt` with pinned production and dev dependencies:49 - `fastapi`, `uvicorn[standard]`, `pydantic`, `slowapi`, `python-multipart`, `structlog`, `httpx` (production)50 - `pytest`, `pytest-asyncio`, `httpx` (testing)51 - `pytest-playwright`, `axe-playwright-python` (E2E testing — pre-installed in devcontainer, pinned here for CI)52 - `ruff` (linting)53 - Pin **exact** versions (`==`) — no loose ranges5455### Backend — FastAPI56571. Set up FastAPI app in `app/main.py` with:58 - Security headers middleware (CSP, HSTS, X-Content-Type-Options)59 - CORS middleware configured for the React dev server60 - Rate limiting (slowapi)61 - `GET /api/health` returning `{ "status": "ok" }` with 200622. Define routers in `app/routers/` using `APIRouter(prefix="/api/v1/...", tags=[...])`633. Use Pydantic models for all request/response schemas644. Use `async def` for route handlers6566### Frontend — React + nhsuk-react-components67681. Scaffold React app with Vite:69 - `npm create vite@latest frontend -- --template react-ts`70 - Install: `npm install nhsuk-react-components nhsuk-frontend react-router-dom`71 - Import `nhsuk-frontend/dist/nhsuk.css` in `main.tsx`722. Create NHS-branded layout with `<Header>`, `<Footer>` from nhsuk-react-components733. Create the start page at `/`744. Configure Vite to proxy `/api` to FastAPI during development7576### Infrastructure — Terraform + Azure77781. Write Terraform in `infra/` using `var.app_name` for resource naming:79 - Resource Group, App Service Plan (Linux, B1), Linux Web App80 - Key Vault with Managed Identity access policy81 - Application Insights82 - All in `uksouth` region832. Run `terraform init && terraform plan` to validate8485### Testing86871. Write pytest tests for `/api/health` using httpx `AsyncClient`882. Write Vitest tests for React components893. Target: 80% coverage9091## Build & Deploy Commands9293```bash94# Backend95pip install -r requirements.txt96uvicorn app.main:app --reload --port 80009798# Frontend99cd frontend && npm ci && npm run dev100101# Build for production102cd frontend && npm run build && cd ..103104# Terraform105cd infra && terraform init && terraform plan -var="app_name=my-service" -out=tfplan106terraform apply tfplan107108# Deploy to Azure109zip -r app.zip app/ frontend/dist/ requirements.txt110az webapp deploy \111 --resource-group "rg-${APP_NAME}-dev" \112 --name "app-${APP_NAME}-dev" \113 --src-path app.zip --type zip114115# Verify116curl https://app-${APP_NAME}-dev.azurewebsites.net/api/health117```118119## Troubleshooting120121- If `terraform apply` fails, read the error, fix the HCL, and re-run122- If `pytest` fails, fix the code (not the test) unless the test is wrong123- If the Azure deployment fails, check logs with `az webapp log tail`124- Always verify live by hitting the Azure URL with `curl`125126---127> Source: [marrobi/nhs-alpha-workshop](https://github.com/marrobi/nhs-alpha-workshop) — distributed by [TomeVault](https://tomevault.io).128<!-- tomevault:4.0:skill_md:2026-06-16 -->