protobuf-ts
protobuf-ts copied to clipboard
Dynamic types based on proto definition
Hello,
First off, thank you for contributing this work to the open-source community using protobuf on the unofficially supported NodeJS / Typescript language.
I'm integrating this library with a schema registry that contains proto definitions. Is there an example of how to create a model class to use for serialization or deserialization on the fly?
Here's the code I've got working with protobufjs doing deserialization, but I don't like how this library handles bigints, etc.
Note: this is running with Deno. Your library works fine with Deno besides the extensions issue in the imports (which is easily fixed with the search/replace script).
import { default as protobuf } from "npm:protobufjs";
const protoDefinition = "syntax = \"proto3\";\n message ExampleMessage { \n string id = 1; \n}";
const parsedMessage = protobuf.parse(protoDefinition);
const root = parsedMessage.root;
const protobufSchema = root.lookupType(
getTypeName(
parsedMessage, {
messageName: props.schemaName,
},
));
protobufSchema.decode(serializedMessage);
// helper functions
function getNestedTypeName(
parent: { [k: string]: protobuf.ReflectionObject } | undefined,
): string {
if (!parent) {
throw new Error("Invalid parent");
}
const keys = Object.keys(parent);
const reflection = parent[keys[0]];
// Traverse down the nested Namespaces until we find a message Type instance (which extends Namespace)
if (
reflection instanceof protobuf.Namespace &&
!(reflection instanceof protobuf.Type) && reflection.nested
) {
return getNestedTypeName(reflection.nested);
}
return keys[0];
}
function getTypeName(
parsedMessage: protobuf.IParserResult,
opts: { messageName?: string } = {},
) {
const root = parsedMessage.root;
const pkg = parsedMessage.package;
const name = opts && opts.messageName ? opts.messageName : getNestedTypeName(root.nested);
return `${pkg ? pkg + "." : ""}.${name}`;
}
TYIA for your help, appreciate it!
Unlike protobuf.js, protobuf-ts depends on protoc for generating code. There is no way to directly convert the string content of a proto file into usable classes for encoding/decoding messages. You could potentially invoke protoc via a subprocess, but you'd still have to do everything via the file system (source files -> protoc -> out files -> await import('../some/out-file.ts')
).
Additionally, protobuf-ts doesn't generate a single "root" (top-level proto package namespace) with messages indexed based on their package + message name. Instead it generates a number of files which match the file structure of the input proto files where each file exports message classes which match their proto message name (unless there is a naming conflict like having your proto file contain a message named const
).