Skip to content

A type-safe API definition toolkit for Rust — define your API once and share it across client and server, with compile-time guarantees.

License

Notifications You must be signed in to change notification settings

sterrlia/rust-api-kit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rust-api-kit

crates.io version docs.rs docs CI build Dependency Status Minimum Supported Rust Version

✨ Features

  • Define your API in one place (routes, requests, responses)
  • Compile-time checked request/response
  • Built for full Rust stacks — server and client
  • Async support
  • Logging using tracing crate

🛠️ Getting Started

1. Define Your API in a Shared Crate

  • One error response variant for each route
  • One shared error response for group of routes
#[derive(Serialize, Deserialize)]
pub struct LoginRequest {
    pub username: String,
    pub password: String,
}

#[derive(Serialize, Deserialize)]
pub struct LoginResponse {
    pub user_id: i32,
    pub token: String,
}

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum LoginErrorResponse {
    AccessDenied,
}

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum UnexpectedErrorResponse {
    InternalServerError,
}

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AuthenticatedUnexpectedErrorResponse {
    InternalServerError,
    InvalidAuthToken,
    AuthTokenMissing
}

define_http_routes! {
    group (
        path "api";
        auth BearerToken;
        error AuthenticatedUnexpectedErrorResponse;

        GET "get-messages" GetMessagesRequest => GetMessagesResponse | GetMessagesErrorResponse;
        GET "get-users" GetUsersRequest => GetUsersResponse | GetUsersErrorResponse;
    );

    group (
        path "api";
        error UnexpectedErrorResponse;

        POST "login" LoginRequest => LoginResponse | LoginErrorResponse;
    );
}

2. Use it in the server (only axum integration available)

  • Currently does not check route implementations, only adds route paths defined in macro
    pub type UnauthenticatedResponse<T, E> = Response<T, E, UnexpectedErrorResponse>;

    pub async fn login(
        extract::State(state): extract::State<state::ServiceState>,
        Json(input): Json<LoginRequest>,
    ) -> UnauthenticatedResponse<LoginResponse, LoginErrorResponse> {
    }

    let http_api_routes = generate_routes! {
        LoginRequest => login,
        GetUsersRequest => get_users,
        GetMessagesRequest => get_messages,
    };

    let app = Router::new()
        .merge(http_api_routes);

3. Use http client in the frontend app

Response is nested result, on first level you can match error response shared with other routes on second level you can match successful response and error response which belongs to that route

use rust_api_kit::http::client::{HttpClient, BasicHttpClientTrait}

pub fn login(&self, username: String, password: String) -> anyhow::Result<UserData> {
    let request = LoginRequest {
        username,
        password,
    }

    let response = self.http_client.request(request).await??; // LoginResponse

    UserData {
        user_id: response.user_id,
        token: response.token
    }
}

More examples

My messenger project: https://github.com/sterrlia/nultr

Status

  • This project is built for educations purposes
  • It is intended for use in my personal projects only, cause I don't think someone would find it useful

Alternatives

What can be added in future

  1. Trait for custom response types
  2. Improved logging
  3. More auth variants
  4. Headers
  5. Integrations with backend frameworks
  6. Server route implementation checking
  7. Websocket client
  8. OpenAPI definitions generation
  9. Code generation from OpenAPI definitions
  10. etc.

About

A type-safe API definition toolkit for Rust — define your API once and share it across client and server, with compile-time guarantees.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages