# 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. ```haskell 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. ```haskell 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: ```haskell 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 ```typescript // 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 => { 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) => cb(JSON.parse(message.data)), raw: ws }); } }; ```