Skip to content

ImShyMike/utoipa-ts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

utoipa-ts

crates.io docs.rs License MSRV

Why?

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.

What?

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.

Get started

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-ts

Already using utoipa?

To 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.

Configuration

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

Cargo Features

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

Examples

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_api
The 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;
        };
      };
    };
  };
};

More examples

All examples can be found in the examples directory.

TypeScript client

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-client

Use 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"];
}

Disclaimer

This project is not affiliated with utoipa.

About

Generate TypeScript API definitions from utoipa paths

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Contributors

Languages