resAPI

Type-safe HTTP contracts for ReScript

Define your API once. Share types and validation between clients and servers, on Hono, Express or Cloudflare Workers.

npm install @resapi/core @resapi/hono @resapi/sury hono sury sury-ppx

1. Describe the endpoint

A contract names the route, the params, the response and the errors the endpoint can return. Clients and servers both import it.

AccountApi.res

open ResApi

@schema type params = {id: string}
@schema type account = {id: string, name: string, balance: float}
@schema type accountError = | @as("not_found") NotFound

let getAccount =
  Endpoint.get(
    "/accounts/:id",
    ~params=SuryCodec.make(paramsSchema),
    ~response=SuryCodec.make(accountSchema),
  )->Endpoint.withErrors(SuryCodec.make(accountErrorSchema), ~status=error =>
    switch error {
    | NotFound => 404
    }
  )

2. Implement it

The handler receives decoded, validated params. Returning a field the contract doesn't have, or an error it doesn't declare, is a compile error.

App.res

open ResApiHono

let app: Router.t<unit> =
  Router.make()
  ->Router.register(
    AccountApi.getAccount->EndpointHandler.make(async (_ctx, {params}) =>
      switch accounts->Dict.get(params.id) {
      | Some(account) => Ok(account)
      | None => Error(NotFound)
      }
    ),
  )

// A router is a Hono app, so it is already a Cloudflare Worker.
let default = app

3. Call it

The client builds the URL, validates the response, and returns every outcome as a typed case.

AccountClient.res

switch await client->Client.call(AccountApi.getAccount, ~params={id: id}) {
| Ok(account) => account.name
| Error(Application({error: NotFound})) => "no such account"
| Error(_) => "request failed"
}

Why resAPI

Packages

@resapi/coreContracts, codecs and the typed client. Depends only on Fetch.
@resapi/honoHono adapter, for Node and Cloudflare Workers.
@resapi/expressExpress 5 adapter.
@resapi/surySury schemas as codecs. Hand-written codecs work too.

0.1.0 is a preview: the API may change in 0.x releases. See the changelog for tested versions and known limitations.