Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2: JSON Types #866

Merged
merged 17 commits into from
Jun 19, 2024
Merged

V2: JSON Types #866

merged 17 commits into from
Jun 19, 2024

Conversation

timostamm
Copy link
Member

@timostamm timostamm commented May 30, 2024

This PR adds an advanced feature with the plugin option json_types=true. If enabled, protoc-gen-es generates a JSON type for every Protobuf message.

Given this definition:

syntax = "proto3";

message Example {
  int32 amount = 1;
  bytes data = 2;
}

The following additional export is generated:

/**
 * JSON type for the message Example.
 */
export type ExampleJson = {
  /**
   * @generated from field: int32 amount = 1;
   */
  amount?: number;

  /**
   * @generated from field: bytes data = 2;
   */
  data?: string;
};

The JSON type matches exactly what toJson() will emit with standard serialization options, and toJson() will actually automatically return the JSON type if available:

const example = create(ExampleSchema, { amount: 123 });
const json: ExampleJson = toJson(ExampleSchema, example);

// Without json_types=true, the following would be a type error:
json.amount // number | undefined
json.data // string | undefined

For enumerations, a similar mechanism applies. We generate a union type with all JSON string values for the enum:

syntax = "proto3";

enum Format {
  FORMAT_UNSPECIFIED = 0;
  FORMAT_BINARY = 1;
  FORMAT_JSON = 2;
}
/**
 * JSON type for the enum Format.
 */
export type FormatJson = "FORMAT_UNSPECIFIED" | "FORMAT_BINARY" | "FORMAT_JSON";

With the functions enumToJson() and enumFromJson(), values can be converted between both representations. With isEnumJson(), unknown input can be narrowed down to known values. If JSON types are available, the functions are type safe:

const strVal: FormatJson = enumToJson(FormatSchema, Format.BINARY);

const enumVal: Format = enumFromJson(FormatSchema, strVal);

const someString: string = "FORMAT_BINARY";
if (isEnumJson(FormatSchema, someString)) {
  someString // FormatJson
}

Signed-off-by: Timo Stamm <ts@timostamm.de>
Generate the well-known types with JSON typings.

Signed-off-by: Timo Stamm <ts@timostamm.de>
Re-generate all, adding JSON typings.

Signed-off-by: Timo Stamm <ts@timostamm.de>
Signed-off-by: Timo Stamm <ts@timostamm.de>
Comment on lines 64 to 71
/**
* JSON type for the message docs.User.
*/
export type UserJson = {
/**
* @generated from field: string first_name = 1;
*/
firstName?: string;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A simple example for a JSON type for a message.

@mikeki
Copy link

mikeki commented Jun 5, 2024

Will there be something similar for proto3 as well?, or is the v2 meaning for the future version of this package?

@timostamm
Copy link
Member Author

@mikeki, V2 refers to version 2 of this project. You can try it out here: https://github.com/bufbuild/protobuf-es/releases/tag/v2.0.0-alpha.1

@mikeki
Copy link

mikeki commented Jun 5, 2024

@mikeki, V2 refers to version 2 of this project. You can try it out here: https://github.com/bufbuild/protobuf-es/releases/tag/v2.0.0-alpha.1

Got it! Yes these interfaces would be great. One thing I noticed is that the interface between toJson and toPlainMessage is different, and trying to access oneof and enum fields from the Message is very strange, I think the toJson interfaces are helpful for this but there might still be a gap here.

@timostamm timostamm marked this pull request as ready for review June 18, 2024 14:54
@timostamm timostamm merged commit 225def5 into v2 Jun 19, 2024
5 checks passed
@timostamm timostamm deleted the tstamm/json-types branch June 19, 2024 16:41
@timostamm timostamm mentioned this pull request Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants