This repo was used during an early version of Atek in which schemas were written as d.ts
files and then generated using this tool. This was more complexity than we needed, so this approach has been deprecated.
Atek defines RPC and database schemas using URL IDs, various options, (in some cases) JSON Schemas. These can be somewhat tedious to define manually.
To make life easier, we use .d.ts
files to declare the schemas and API interfaces and then we generate the API code using this tsgen
tool.
A .d.ts
file should include a couple of conventions:
- It should start with a "frontmatter" which is a multi-line comment formatted in YAML. This must include an
id
andtype
value. - The
id
should be a URL without any protocol or extension. - The
type
should be "api" or "adb-record" - The metadata can (and should) also include
title
anddescription
. - If
type
is "api" then you can also indicatetransport
but tsgen doesnt make anything interesting for proxy transports. - It should export a default interface.
atek tsgen gen-file --in {dts_file_path} --out {output_folder} --env {env}
atek tsgen gen-folder --in {dts_folder_path} --out {output_folder} --env {env}
Use gen-file
to generate TS for a single dts, and gen-folder
for a folder of dts files.
Choose an --env
value based on your application:
node
A nodejs atek applicationhost
The "atek" project (you only need this if working on atek)
If using node
, you will need to install @atek-cloud/node-rpc
as the generated code depends on it.
Suppose we have a file ping-api.d.ts
.
/*
id: atek.cloud/ping-api
type: api
title: Ping API
description: Utility API used for debugging and testing liveness.
*/
export default interface PingApi {
// Ask for a pong back with the given parameter
ping (param: number): Promise<number>
}
If we run:
atek tsgen gen-file --in ping-api.d.ts --out ./gen --env host
We will get the following output:
/**
* File generated by Atek tsgen
* env=host
* DO NOT MODIFY
*/
import { URL } from 'url';
import { ApiBrokerClient } from '@atek-cloud/api-broker';
export const ID = "atek.cloud/ping-api";
export const REVISION = undefined;
export default class PingApiClient extends ApiBrokerClient {
constructor() {
super("atek.cloud/ping-api")
}
ping(param: number): Promise<number> {
return this.$rpc("ping", [param])
}
}
/**
* File generated by Atek tsgen
* env=host
* DO NOT MODIFY
*/
import { URL } from 'url';
import { ApiBrokerServer, ApiBrokerServerHandlers } from '@atek-cloud/api-broker';
export const ID = "atek.cloud/ping-api";
export const REVISION = undefined;
export const SCHEMAS = {"$schema":"http://json-schema.org/draft-07/schema#","definitions":{"PingApi":{"type":"object"},"api_PingApi_Ping":{"type":"object","properties":{"params":{"type":"array","items":{"type":"number"},"minItems":1,"maxItems":1},"returns":{"type":"number"}},"required":["params","returns"]}}};
export const EXPORT_MAP = {"methods":{"ping":"#/definitions/api_PingApi_Ping"},"events":{}};
export default class PingApiServer extends ApiBrokerServer {
ID = "atek.cloud/ping-api";
REVISION = undefined;
constructor(handlers: ApiBrokerServerHandlers) {
super(handlers, SCHEMAS, EXPORT_MAP)
}
}
You can now use these APIs to call and serve the ping API:
import PingApiClient from './gen/atek.cloud/ping-api.ts'
const api = new PingApiClient()
await api.ping(42) // => 42
import createExpressApp, * as express from 'express'
import PingApiServer from './gen/atek.cloud/ping-api.server.ts'
const apiServer = new PingApiServer({
ping (param: number): Promise<number> {
return Promise.resolve<number>(param)
}
})
const PORT = Number(process.env.ATEK_ASSIGNED_PORT)
const app = createExpressApp()
app.use(bodyParser.json())
app.post('/_api/ping', (req, res) => apiServer.handle(req, res, req.body))
app.listen(PORT, () => {
console.log(`Ping server running at: http://localhost:${PORT}/`)
})