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.

More blog posts