An open API service indexing awesome lists of open source software.

https://github.com/speedapi/driver-ts

API building toolkit - TypeScript support library
https://github.com/speedapi/driver-ts

api protocol serialization typescript

Last synced: about 2 months ago
JSON representation

API building toolkit - TypeScript support library

Awesome Lists containing this project

README

        

![License](https://img.shields.io/github/license/speedapi/driver-ts)
![Version](https://img.shields.io/npm/v/@speedapi/driver)
![Coverage](https://coveralls.io/repos/github/speedapi/driver-ts/badge.svg?branch=master)
![Downloads](https://img.shields.io/npm/dt/@speedapi/driver)
![Size](https://img.shields.io/bundlephobia/minzip/@speedapi/driver)
![PRs and issues](https://img.shields.io/badge/PRs%20and%20issues-welcome-brightgreen)

# SpeedAPI wire protocol implementation
This library provides a SpeedAPI implementation for JS and TS in all major environments (browser, node, etc.). Install it with:
```console
npm i @speedapi/driver
```

Also install a transport level library according to your environment:
- `npm i @speedapi/node` for Node.JS
- don't see an appropriate transport here? [implement your own](#implementing-a-transport-layer)

You don't need additional libraries if you just use the `Serializer` class.

**If you're using a BigInt polyfill**, add this as close to entry as possible:
```typescript
import * as speedapi from "@speedapi/driver";

// if using a polyfill that provides a BigInt(string, radix) constructor
// (e.g. 'big-integer', 'bigint-polyfill'):
speedapi.repr.BigInteger.polyfillMode = "radix";

// if using a polyfill that supports BigInt("0x"):
speedapi.repr.BigInteger.polyfillMode = "0x";

// if not using a polyfill or using a polyfill that implements
// operators like native BigInts do (haven't seen one of those
// in the wild):
speedapi.repr.BigInteger.polyfillMode = "none";
// OR don't do anything, this is the default value
```

# What is SpeedAPI?
It's a platform-agnostic API and serialization tool specifically geared towards high-throughput realtime applications. You can read more about its features [here](https://github.com/speedapi/info)

# How do I use it?
There's a complete tutorial over [here](https://github.com/speedapi/info/tree/master/speedapi-tutorial).

## Implementing a transport layer
You just have to write glue code between an implementation of your desired transport protocol and SpeedAPI. The requirements for the underlying protocol are as follows:
- for datagram/packet/frame-based protocols like UDP: reliable and unordered - packets _must not_ get lost, but their order _may_ be mixed up (note that UDP doesn't fit this description as it's unreliable)
- for stream-based protocols like TCP: reliable and ordered - bytes _must not_ get lost and their order _must not_ get mixed up

You will need to write 3 or 4 classes depending on the protocol nature:
- A `Link`, `Client` and `Server` if the protocol is two-partied in nature, meaning there are only two active devices on the bus/network (e.g. UART)
- A `Link`, `Client`, `Server` and `Listener` if one server can serve multiple clients (the overwhelming majority of Internet protocols)

Note that for every client-to-server link there's a `Client` object on the client and a `Server` object on the server. There's only one `Listener` on the server.

### `Link`
This class acts as the reader/writer for SpeedAPI and should extend `Duplex`. Its only job is to read and write `Uint8Array`s. This class will be instantiated by you, therefore you can make the constructor of an arbitrary signature. Here's the skeleton for such a class:
```ts
import { Duplex } from "@speedapi/driver";
class MyLink extends Duplex {
constructor(/* pass what you need (e.g. a socket) */) { }
async write(data: Uint8Array): Promise { }
async read(cnt: number): Promise { }
async close(): Promise { }
}
```

Alternatively, you can extend from `BufferedLink` if the underlying protocol implementation is event-driven, meaning it provides a "data has arrived" callback, but not a "read me N bytes" function.

```ts
import { BufferedLink } from "@speedapi/driver/transport/universal";
class MyLink extends BufferedLink {
constructor(/* again, pass what you need */) {
someProtocol.on("bytesArrived", (data: Uint8Array) => {
// feed BufferedLink data as it arrives
this.dataArrived(data);
});
}

protected async dataWrite(data: Uint8Array): Promise { }
override async close(): Promise { }
}
```

### `Server` and `Client`
Very thin wrappers that tell SpeedAPI about your `Link` while preserving type information.

**Important**: if you omit type information (e.g. if you're using plain JS to implement these two classes), your IDE will not be able to provide suggestions.
```ts
import { SpecSpaceGen, Session } from "@speedapi/driver";
class MyClient extends Session {
constructor(specSpace: Gen /* any other arguments */) {
super(specSpace, new MyLink(/* your arguments */), "client");
}
}
class MyServer extends Session {
constructor(specSpace: Gen /* any other arguments */) {
super(specSpace, new MyLink(/* your arguments */), "server");
}
}
```

### `Listener` (optional)
The notice from before applies here as well.
```ts
class MyListener {
constructor(specSpace: Gen, /* any other arguments */, callback: (server: MyServer) => void /* optional too */) {
someProtocol.on("clientConnected", (socket) => {
const session = new MyServer(specSpace, socket /* or any other arguments per your definition */);
callback(session);
});
}

async close() { }
}
```

# Testing
**Warning**: this repository uses a `pnpm` lock file, hence you can't substitute it for `npm` below.
```
git clone https://github.com/speedapi/driver-ts
cd driver-ts
pnpm i
pip3 install susc
pnpm test
```

# TypeScript notice
This project relies _heavily_ on typing. As such, the language server gets misled into thinking that an expression type is `any` even though it's not just because the type is deeply nested. If you see a type error in your IDE that you think shouldn't be there or you're missing some autocomplete entries, try restarting your IDE and/or language server.