aisil
Lightweight framework to define APIs as types.
aisil is designed to be transport and protocol agnostic. At the moment,
however, only one transport protocol is supported (HTTP's POST /<method_name>
with json bodies). Feel free to extend the base framework with whatever fits
your requirements.
See docs at docs.rs/aisil.
- Define API
- Implement service
- Expose service
- Make client calls
- Generate spec
- Generate TS types
- Things to implement/improve
Define API
-
A method is defined as
Request→ (method name,Response) dependency in the context of an API (SeeHasMethodtrait). -
An API is defined as
ApiMetaType→[*]dependency (SeeIsApitrait), where[*]is a heterogeneous list of request types that belong to the API.
An example of an API definition with two methods:
/// Get A
;
;
/// Some example api
;
define_api!
Implement service
Expose service
As HTTP POST /<method_name>:
or as JsonRPC:
let backend = default;
new.route.with_state;
Make client calls
Use that API to make type safe client calls:
Either HTTP POST /<method_name>:
let client = new;
client.call_api.await?.unwrap;
let new_a = client.call_api.await?;
assert_eq!;
or as JsonRPC:
let client = new;
client.call_api.await?.unwrap;
let new_a = client.call_api.await?;
assert_eq!;
Generate spec
OpenAPI for HTTP POST /<method_name>:
println!;
OpenRPC for JsonRPC:
println!;
Generate TS types
println!;
Current implementation works by inlining everything, which is probably undesirable:
type Request<M> =
M extends 'get_a' ? null :
M extends 'post_a' ? boolean :
void;
type Response<M> =
M extends 'get_a' ? Result<boolean, number> :
M extends 'post_a' ? Result<null, number> :
void;
TS boilerplate would look something like this:
const callSomeApi<M> = async (req: Request<M>) => {
const raw_response = await fetch(`http://example.com/{method}`, {
method: 'POST',
body: req,
headers: { 'Content-Type': 'application/json' }
});
const json = await raw_response.json();
json as Response<M>
}
And to unwrap rust's Result:
function unwrapResult<R, E>(a: Result<R, E>): R {
if ('Ok' in a) {
return a.Ok;
} else if ('Err' in a) {
throw Error(JSON.stringify(a.Err))
} else {
throw Error('non api error')
}
}
Things to implement/improve
- Allow for non-inlined TS types generation
- Debug
tsfeature - no-std feature