gluer
A wrapper for Rust frameworks that eliminates redundant type and function definitions between the frontend and backend. Currently, it supports only the axum framework.
Origin of the Name
The name "gluer" is inspired by the tool's primary function, gluing together different parts of a Rust-based web application. Just as glue binds different materials together to form a cohesive whole, gluer integrates various components of the frontend and backend, ensuring they work seamlessly without redundant code.
Installation
Add this to your Cargo.toml:
[]
= "0.7.3"
Features
- Define routing and API generation as outlined in How to use.
- Everything is done on macro expansion (compile time), even the generating of the TypeScript file.
- Support
axum's types completely. - Generate a TypeScript file with:
- A custom base URL
- Functions to access the api, infers input and output types for that
- Structs as Interfaces, supports changing the generated type via the
#[meta(...)]attribute - Enums as the TypeScript equivalent, enums with values are not supported, because of the lack of that feature in TypeScript
- Types as the TypeScript equivalent
- Supports converting docstring to the TypeScript equivalent, even of fields of structs and enums
- Tuples as the TypeScript equivalent, also supports tuples in
axum's path - Supports converting rust specific types as
Resultas custom ones using thecustom = [Type, *]attribute - Generics, even multiple and nested ones, look for that here
- No extra dependencies
How to use
gluer generates an api endpoint .ts file. To use it, follow these steps:
Step 1: Define Structs and Functions
To define your structs, functions and enums, use the #[metadata] macro along with the #[meta(...)] attribute. This enables the generate! macro to find those and converting them into the TypeScript equivalent.
use ;
use metadata;
use ;
/// Define a struct with the metadata macro
/// Note: This is a docstring and will be
/// converted to the TypeScript equivalent
// Everything you want to use, even if it's just a
// dependency of struct or type, needs to be declared
// with the `#[metadata]` macro
type Result<T> = Result;
// Define an enum with the metadata macro
// Note: Enums with values are not supported
// Define the functions with the metadata macro
async
// Supports axum's input types
async
// Also tuples in paths
async
// Supports enums
async
Step 2: Add Routes
Use the route! macro with axum's Router to add routes. This enables the generate! macro to identify the route and generate corresponding functions, structs, types, and enums. Note that inline functions cannot be used because the function names in the generated TypeScript file are inferred from the handler function names.
use ;
use ;
// without `#[metadata]`, it's non-API-important
async
// done like above
async
let mut app: = new
// Add non-API-important directly on the router
.route;
// Add API-important routes with the route macro
route!;
Step 3: Generate API
Generate the API file using the generate! macro. This macro generates the TypeScript file during macro expansion (compile time). You need to specify the project_paths of your current project, which can be a root directory (represented by "src"), multiple directories, or specific files (e.g., ["dir0", "dir1", "dir2/some.rs"]). The project_paths will be scanned to retrieve project data, meaning collecting the information marked by the route! and #[metadata] macros. Additionally, you need to provide a path where the generated file will be saved, including the filename, and a base URL for the API. The base URL should not end with a slash (/); use "" for no base URL if you are utilizing axum's static file serving, or provide a URL like "http://localhost:8080" for a local server.
use generate;
// Make sure to change "tests" to "src" when copying this example into a normal project
generate!;
And now you can just simply use the router to start your server or do different things, the API should be already generated by your LSP!
Complete Example
Below is a complete example demonstrating the use of gluer with axum:
use ;
use ;
use ;
use HashMap;
/// An example of a simple function with a `Path` and `Query` extractor
async
// Generics are supported, multiple even
// Note: This is not a docstring and won't
// be converted
/// Might want to look into the `api.ts` file to see the docstring for this struct
// Even deep nested generics are supported and tagging default rust types as Custom
async
// Even tuples are supported
async
/// An example how an api error type could look like
// And types?!?
type Result<T> = Result;
type S = String;
async