servant-aeson-generics-typescript: Generates a TypeScript client for Servant APIs

[ bsd3, library, program, web ] [ Propose Tags ]

This project leveratges aeson-generics-typescript to generate type safe API bindings in TypeScript for a given Servant API. Included here are tests that round trip by compling the TypeScript with tsc, running the client in nodejs, and checking that request response round trips with the Servant server.


[Skip to Readme]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0.0.1, 0.0.0.2
Dependencies aeson (>=2.1.2 && <2.2), aeson-generics-typescript (>=0.0.0 && <0.1), async (>=2.2.4 && <2.3), base (>=4.17.2 && <4.18), bytestring (>=0.11.5 && <0.12), conduit (>=1.3.5 && <1.4), containers (>=0.6.7 && <0.7), directory (>=1.3.7 && <1.4), filepath (>=1.4.2 && <1.5), hspec (>=2.11.7 && <2.12), hspec-wai (>=0.11.1 && <0.12), http-types (>=0.12.3 && <0.13), jose-jwt (>=0.9.6 && <0.10), process (>=1.6.17 && <1.7), QuickCheck (>=2.14.3 && <2.15), random (>=1.2.1 && <1.3), servant (>=0.20.1 && <0.21), servant-auth (>=0.4.1 && <0.5), servant-server (>=0.20 && <0.21), servant-websockets (>=2.0.0 && <2.1), split (>=0.2.4 && <0.3), string-interpolate (>=0.3.2 && <0.4), text (>=2.0.2 && <2.1), time (>=1.12.2 && <1.13), warp (>=3.3.30 && <3.4), webdriver (>=0.12.0 && <0.13) [details]
License BSD-3-Clause
Copyright 2023
Author Platonic.Systems
Maintainer info@Platonic.Systems
Category Web
Source repo head: git clone https://gitlab.com/platonic/servant-aeson-generics-typescript.git
Uploaded by fresheyeball at 2024-01-03T15:55:55Z
Distributions
Executables tests
Downloads 52 total (6 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for servant-aeson-generics-typescript-0.0.0.2

[back to package description]

Servant Aeson Generics TypeScript

This project leveratges aeson-generics-typescript to generate type safe API bindings in TypeScript for a given Servant API. Included here are tests that round trip by compling the TypeScript with tsc, running the client in nodejs, and checking that request response round trips with the Servant server.

data Foo = ...
  deriving stock (Generic)
  deriving anyclass (ToJSON, FromJSON, TypeScriptDefinition)

type API = "foo" :> Get '[JSON] Foo

Is all it takes to have a TypeScript Definition, and TypeScript client. Now you can obtain the TypeScript client as a string like so.

client :: String
client = gen @API

Support

TypeScript code generated for HTTP uses the fetch api, which works in Browsers and Nodejs. TypeScript code generated for WebSocket's only works in Browsers for the moment, as Nodejs doesn't have WebSocket support. Round trips are tested with Selenium using Chromium.

Example

You can see many examples in the tests. One provided here for documentation purposes:

data Foo = Foo { thang :: String, otherThang :: Int }
  deriving stock (Generic)
  deriving anyclass (ToJSON, FromJSON, TypeScriptDefinition)

type API
     = "foo" :> Capture "bar" Int :> Post '[JSON] Foo
  :<|> "qux" :> WebSocketConduit String Foo

client = tsClient @'[Foo] @API

will generate

// Defined in Servant.Client.TypeScriptSpec of main
interface Foo {
  // readonly tag: "Foo";
  readonly thang: string;
  readonly otherThang: number;
}
const API = {
  base: "",
  "/foo/:bar": (bar: number): Promise<Foo> => {
    const uri = `${API.base}/foo/${bar}`;
    return fetch(uri, {
      method: "POST"
    }).then(res => res.json());
  },
  "/qux": ():
    Promise<{ send : (input: string) => void
            , receive : (cb: (output: Foo) => void) => void
            , raw : WebSocket
    }> => {
      const pr = window.location.protocol === "http:" ? "ws:" : "wss:";
      const ws = new WebSocket(`${pr}//${window.location.host}${API.base}/foo/bar`);
      return Promise.resolve({
        send: (input: User) => ws.send(JSON.stringify(input)),
        receive: (cb: ((output: User) => void)) =>
          ws.onmessage = (message: MessageEvent<string>) => cb(JSON.parse(message.data)),
        raw: ws
      });
  }
};