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

https://github.com/ilyhalight/elysia-protobuf

Easy support protobuf integration for Elysia
https://github.com/ilyhalight/elysia-protobuf

elysia protobuf

Last synced: 7 months ago
JSON representation

Easy support protobuf integration for Elysia

Awesome Lists containing this project

README

          

# elysia-protobuf

Easy support protobuf integration for Elysia. To decode/encode we use [@bufbuild/protobuf](https://github.com/bufbuild/protobuf-es) lib and schemas generated by [ts-proto](https://github.com/stephenh/ts-proto)

## Install

```bash
bun install elysia-protobuf
```

## Before starting

Lib is incompatible with default elysia body/response validation! Don't mix it with `parse: "protobuf"`!

## Usage

**✅ Do**: Use requestSchema field and import decode from context

```ts
import Elysia from "elysia";
import {
protobuf,
ProtoRequestError,
ProtoResponseError,
} from "elysia-protobuf";
import {
RequestMessage,
ResponseMessage,
ResponseStatus,
} from "./proto/message";

const app = new Elysia()
.use(
protobuf({
schemas: {
"post.request": RequestMessage,
"post.response": ResponseMessage,
},
// (optional) verify body with signature
signature: {
enabled: true,
secret: "test123",
headerName: "x-signature",
},
}),
)
.post(
"/post",
async ({ body, decode, headers }) => {
// decode uint8array with your schema
const data = await decode("post.request", body, headers);
console.log(data);
return {
status: ResponseStatus.SOME,
inlineTags: data.tags.join(", "),
};
},
{
// parse body as arrayBuffer -> Uint8Array
parse: "protobuf",
// encode response with protobuf schema
responseSchema: "post.response",
},
)
.listen(3000);
```

**❌ Don't**: Use default body/response elysia validation with protobuf parser

```ts
// ...
const app = new Elysia()
.use(
protobuf({
schemas: {
"post.request": RequestMessage,
"post.response": ResponseMessage,
},
}),
)
.post(
"/post",
async ({ body, decode }) => {
// decode uint8array with your schema
const data = await decode("post.request", body);
console.log(data);
return {
status: ResponseStatus.SOME,
inlineTags: data.tags.join(", "),
};
},
{
parse: "protobuf",
responseSchema: "post.response",
// ! ❌ INCOMPATIBLE with this plugin
// body: t.Object({
// title: t.String(),
// updatedAt: t.Optional(t.Number()),
// tags: t.Array(t.String()),
// }),
// Doubtful But Okay
// body: t.Uint8Array(),
},
)
.post(
"/json",
({ body }) => {
return body;
},
{
// OK if parse mode isn't protobuf
body: t.Object({
title: t.String(),
updatedAt: t.Optional(t.Number()),
tags: t.Array(t.String()),
}),
},
)
.listen(3000);
```

You can handle plugin errors with onError event

```ts
import { protobuf, ProtoRequestError, ProtoResponseError } from "../../src";
// ...

const app = new Elysia()
.use(
protobuf({
schemas: {
"post.request": RequestMessage,
"post.response": ResponseMessage,
},
}),
)
.error({
PROTO_RESPONSE_ERROR: ProtoResponseError,
PROTO_REQUEST_ERROR: ProtoRequestError,
})
.onError(({ code, error, set }) => {
// something like that
switch (code) {
case "PROTO_REQUEST_ERROR": {
set.status = 400;
break;
}
case "PROTO_RESPONSE_ERROR": {
set.status = 500;
break;
}
}

return {
message: (error as Error).message,
};
});
// ...
```

### Create protobuf schema:

1. Install [protoc](https://github.com/protocolbuffers/protobuf/releases)
2. Install [ts-proto](https://github.com/stephenh/ts-proto) package
3. Convert `.proto` to `.ts` with ts-proto (see [example](./example/) for details):

```bash
protoc --plugin=.\\node_modules\\.bin\\protoc-gen-ts_proto --ts_proto_opt=esModuleInterop=true --ts_proto_opt=importSuffix=.js --ts_proto_out=./src ./proto/*.proto
```

4. Import schemas from `./src/proto/YOUR_FILE.ts`

## Options

| Key | Type | Default | Description |
| --------- | --------- | --------- | ------------------ |
| schemas | Schemas | {} | key - proto schema |
| signature | Signature | undefined | signature settings |

```ts
new Elysia().use(
protobuf({
schemas: {
// any string key: proto schema
"post.request": RequestMessage,
"post.response": ResponseMessage,
},
signature: {
// disabled by default
enabled: true,
secret: "changeme",
headerName: "x-signature",
},
}),
);
```