The main goal of this library is to allow typesafe communication (and to a degree, documentation) generation between TypeScript and your Rust API. Using this library, that can all be automatically derived from just the Rust code, without any external definitions like OpenAPI being needed. The steps for using this library are:
- Annotate your input and output types for these routes with the [
macro@ApiBody
] macro. - Derive [
macro@ApiError
] (or manually implementInto<ApiError
) on any errors you wish to emit. - Declare each of your API routes using this library. API handlers can just ask for whatever they need as a function parameter, including state or user info based on the incoming request.
- Once the API routes are declared, use [
Api::info()
] to obtain enough information about the API to generate fully type safe client code (the information is optimised towards generating TypeScript types/code). - Integrate this API with something like
warp
orrocket
so that yourseamless
API routes can live alongside everything else that you'd like to serve.
Have a look at the examples in the examples
directory to get a proper feel for how this library can be used, or
keep reading!
A Basic Example
Below is a basic self contained example of using this library.
# new.unwrap.block_on;
State
Most real life use cases will require some sort of state to be accessible inside a handler.
This library follows an approach a little similar to Rocket
. Any type that implements the
[handler::HandlerParam
] trait can be passed into handler functions. Using this trait, you can
inspect the request to do things like obtain user information from a session ID, or you can pull
state out of the Request
object that was placed there prior to it being handed to this library.
Here's an example:
use ;
#
#
#
#
#
# async
# new.unwrap.block_on
Note: params implementing the [handler::HandleParam
] trait must come before the optional final param
that implements [handler::HandlerBody
]. Params are resolved in order, with the first failure short circuiting
the rest.
Info
At some point, you'll probably want to get information about the shape of the API so that you can go
and generate a typed API client (this is, after all, the main selling point of this library). To do this,
use the [Api::info()
] function.
Probably the best way to see what shapes this info can take is by looking at api/info.rs
.
Here's an example:
# new.unwrap.block_on
The "shape" object can have one of the following "type" literals: String
, Number
, Boolean
, Null
, Any
, ArrayOf
, TupleOf
, ObjectOf
, Object
, OneOf
, StringLiteral
, Optional
. Some of these will come with an additional property.
See seamless/src/api/info.rs
to get a better feel for exactly what the possible responses can be.
Integrating with other libraries
Instead of passing requests in manually, you'll probably want to attach an API you define here to a library like
Rocket
or Warp
(or perhaps just plain old Hyper
) so that you can benefit from the full power and flexibility
of a well rounded HTTP library alongside your well typed seamless
API, and actually make the API available
externally.
See examples/warp.rs
and examples/rocket.rs
for examples of how you might integrate this library with those.
Essentially it boils down to being able to construct an http::Request
from whatever input the library gives you
access to, and being able to handle the http::Response
or error that's handed back from Seamless.
Limitations
Seamless is designed to make it easy to create simple RPC style JSON APIs that can be "seamlessly" typed from client to server without using external tools like OpenAPI.
- Seamless has not been optimised for building RESTful style APIs (notably, the ability to work with query params is lacking, because they do not play nicely with the type safety that this library tries to provide).
- Some of the flexiblity that
Serde
provides for manipulating how types are serialized and deserialized is not available. This library takes the approach of 'wrapping' serde using the [macro@ApiBody
] macro to deliberately restrict how you can transform types, ensuring that any transformations allowed are properly supported and lead to the correct type information being generated. - Streaming request and response bodies back from seamless is currently not supported. For simplicity, bodies are
expected to be
Vec<u8>
s so that the yare easy to work with. It's expected that JSON will be the main method by which this library inputs and outputs data, and JSON doesn't stream well naturally, so this does not seem like a big loss at present.