TypeScript client for Svelte with Hey API and Django Ninja API
Manually setting up a frontend client that is type-safe for a Svelte application can be painful and cumbersome. I wanted a smoother way to integrate Svelte with Django. Using Hey API and Django Ninja I was able to create a type-safe frontend client for a Svelte application.
Getting started
mkdir ninja-typescript-client
cd ninja-typescript-client
Django
mkdir backend
python -m venv env
source env/bin/activate
pip install django django-ninja
Project setup in Django
django-admin startproject backend
cd backend
Validate the installation by running the development server with python manage.py runserver. Apply migrations with
python manage.py migrate.
python manage.py startapp api
cd api
touch api.py
When setting up the API, create a simple endpoint in api/api.py and define a response schema for the frontend client.
Django Ninja generates an operation id using the module and function name by default, so to get friendlier operation ids
you can override this behavior. We’ll do that because later we consume the auto-generated OpenAPI docs and rely on
predictable operation ids (for example math_add). We also use tags to group endpoints in the docs which helps the
generated client navigate the API.
# api/api.py
from ninja import NinjaAPI
from ninja import Schema
class BackendApi(NinjaAPI):
def get_openapi_operation_id(self, operation):
func_name = operation.view_func.__name__
return f"{operation.tags[0]}_{func_name}"
api = BackendApi(title="Backend API", version="1.0", description="Backend API")
class MathOperationsResponseSchema(Schema):
result: int
@api.get("/add", tags=["math"], response=MathOperationsResponseSchema)
def add(request, a: int, b: int):
return {"result": a + b}
Start the development server with python manage.py runserver and view the API docs at
http://127.0.0.1:8000/api/docs.
Before consuming the API from the frontend, configure CORS. The django-cors-headers package works well for this -
follow its installation instructions and then add allowed origins to settings.py:
# settings.py
CORS_ALLOWED_ORIGINS = [
"http://localhost:5173",
"http://127.0.0.1:5173",
]
Frontend application (Svelte and Hey API setup)
npm create vite@latest frontend -- --template svelte-ts
cd frontend
npm install @hey-api/openapi-ts -D -E
Once the Svelte project is scaffolded, configure the TypeScript client by adding openapi-ts.config.ts to the project
root. (If you prefer, @hey-api/openapi-ts also supports CLI flags instead of a config file.)
// openapi-ts.config.ts
import {defineConfig} from '@hey-api/openapi-ts';
export default defineConfig({
input: {
path: 'http://127.0.0.1:8000/api/openapi.json',
},
output: {
format: 'prettier',
lint: 'eslint',
path: './src/lib/client',
},
plugins: [
'@hey-api/schemas',
{
dates: true,
name: '@hey-api/transformers',
},
{
enums: 'javascript',
name: '@hey-api/typescript',
},
{
name: '@hey-api/sdk',
transformer: true,
},
],
});
Add a script to package.json and generate the client with npm run openapi-ts:
{
"name": "frontend",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"openapi-ts": "openapi-ts"
}
}
Using the client in Svelte
Import and use the generated client in your Svelte application. Configure the base URL for the API (in a real project you’d centralize this configuration).
// src/App.svelte
<script lang="ts">
import { onMount } from 'svelte';
import { mathAdd } from './lib/client';
import { client } from './lib/client/client.gen';
let result: number | undefined;
client.setConfig({
baseUrl: 'http://localhost:8000',
});
onMount(async () => {
result = (await mathAdd({ query: { a: 1, b: 2 } })).data?.result;
});
</script>
<p>Result: 1 + 2 = {result}</p>
That’s it! With Django Ninja exposing an OpenAPI spec and Hey API’s OpenAPI → TypeScript tooling, you get a type-safe client for your Svelte frontend with minimal manual typing.