When making fullstack applications with Rust and TypeScript (e.g. with SvelteKit), you usually have to write type definitions on both ends. This can lead to types going out of sync and is also just really annoying to deal with.
This crate aims to solve that by automatically generating TypeScript types from your Rust API endpoint definitions.
Rust crate that generates TypeScript types from utoipa API endpoint definitions. It extracts endpoint information for all defined endpoints and generates TypeScript bindings for them with the help of ts-rs.
Either add it as a dependency in your Cargo.toml:
[dependencies]
utoipa-ts = "0.1"Or do it automatically with cargo add:
cargo add utoipa-tsTo add utoipa-ts to an existing project that already uses utoipa, simply add the dependency, change all utoipa::path attributes to utoipa_ts::path, and add utoipa_ts::export!() to your codebase.
The types file can then be generated by running cargo test export_api.
The export path for utoipa_ts::export!() can be chosen with utoipa_ts::export!("your/path/here.d.ts"). If a path is not present, it will use the default value of types.d.ts. The UTOIPA_TS_PATH environment variable can also be used to set the export path. If both are present, the environment variable will have priority.
| Variable | Description | Default |
|---|---|---|
UTOIPA_TS_PATH |
The path where the generated TypeScript declaration file will be saved. | types.d.ts |
| Feature | Description |
|---|---|
| ts-format | Enables formatting of the generated TypeScript bindings. |
| ts-serde-json | Add TypeScript support for serde_json |
| ts-chrono | Add TypeScript support for chrono |
| ts-bigdecimal | Add TypeScript support for bigdecimal |
| ts-url | Add TypeScript support for url |
| ts-uuid | Add TypeScript support for uuid |
| ts-bson-uuid | Add TypeScript support for bson::oid::ObjectId and bson::uuid |
| ts-bytes | Add TypeScript support for bytes |
| ts-indexmap | Add TypeScript support for indexmap |
| ts-ordered-float | Add TypeScript support for ordered_float |
| ts-heapless | Add TypeScript support for heapless |
| ts-semver | Add TypeScript support for semver |
| ts-smol_str | Add TypeScript support for smol_str |
| ts-tokio | Add TypeScript support for tokio |
| ts-jiff | Add TypeScript support for jiff |
| ts-arrayvec | Add TypeScript support for arrayvec |
| ts-astrolabe | Add TypeScript support for astrolabe |
use utoipa::ToSchema;
#[derive(ts_rs::TS, ToSchema)]
struct Todo {
id: String,
title: String,
done: bool,
}
#[derive(ts_rs::TS, ToSchema)]
struct CreateTodo {
title: String,
}
#[utoipa_ts::path(
get,
path = "/todos",
responses(
(
status = 200,
description = "List of all todos",
body = Vec<Todo>,
content_type = "application/json",
headers(("x-total-count" = String, description = "Total number of todos"))
),
)
)]
async fn list_todos() {}
#[utoipa_ts::path(
post,
path = "/todos",
request_body = CreateTodo,
responses(
(status = 201, description = "Todo created", body = Todo),
(status = 400, description = "Invalid input")
)
)]
async fn create_todo() {}
utoipa_ts::export!("types.d.ts");
fn main() {}To generate the types.d.ts file, run the following command:
cargo test export_apiThe file contents will look like this
// This file was generated by utoipa-ts. Do not edit it manually.
export type CreateTodo = { title: string, };
export type Todo = { id: string, title: string, done: boolean, };
export type Api = {
"/todos": {
GET: {
responses: {
/** @description List of all todos */
200: {
body: Array<Todo>;
contentType: "application/json";
headers: {
/** @description Total number of todos */
"x-total-count": string;
};
};
};
};
POST: {
body: CreateTodo;
responses: {
/** @description Todo created */
201: {
body: Todo;
};
/** @description Invalid input */
400: {
body: never;
};
};
};
};
};All examples can be found in the examples directory.
The generated file only contains schema declarations and the Api type. If you
want a typed fetch client, import the utoipa-ts-client package and use the
createUtoipaTsClient function with the generated Api type.
Add the package:
bun install utoipa-ts-clientUse it:
import { createUtoipaTsClient } from "utoipa-ts-client";
import type { Api } from "./types";
const client = createUtoipaTsClient<Api>({ baseUrl: "https://api.example.com" });
const response = await client.request("/todos", "GET");
if (response.status === 200) {
response.body[0]?.title;
response.headers.typed["x-total-count"];
}This project is not affiliated with utoipa.