1.0.1 • Published 5 months ago
elysia-protobuf v1.0.1
elysia-protobuf
Easy support protobuf integration for Elysia. To decode/encode we use @bufbuild/protobuf lib and schemas generated by ts-proto
Install
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
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
// ...
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
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:
- Install protoc
- Install ts-proto package
- Convert
.proto
to.ts
with ts-proto (see example for details):
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
- Import schemas from
./src/proto/YOUR_FILE.ts
Options
Key | Type | Default | Description |
---|---|---|---|
schemas | Schemas | {} | key - proto schema |
signature | Signature | undefined | signature settings |
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",
},
}),
);