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

feat: Add generic metadata parameter to the generic service definition interface. #530

Merged
merged 5 commits into from
Mar 15, 2022

Conversation

fizx
Copy link
Collaborator

@fizx fizx commented Mar 8, 2022

If you're using generic service definitions, the lack of a way to pass headers/metadata can be a blocker. Here we add an optional parameter to the interface that is generated.

};

export interface HeroService {
FindOneHero(request: HeroById, metadata?: GenericMetadata): Promise<Hero>;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the new field!

bidirectionalStreamingRequest(service: string, method: string, data: Observable<Uint8Array>): Observable<Uint8Array>;
}

export interface Strings {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Types used in the new field.

export interface Strings {
values: string[];
}
type GenericMetadata = { [key: string]: Strings };
Copy link
Owner

@stephenh stephenh Mar 8, 2022

Choose a reason for hiding this comment

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

I'm not super-close to how like specific frameworks like GRPC handle metadata, but just naively I was thinking that even this generic type is probably making assumptions about the shape of the metadata, right?

I.e. that it must be a key -> { values: string[] } structure...

Does that come from somewhere official like a protobuf spec?

If it doesn't I was wondering if we could make this even "more generic" by allowing the user to really specify their own type. At first I was thinking a generic, like:

interface HeroService<M> {
  findHero(input, metadata: M) {}
}

But then the user would have to pass <M> around; but then I thought we could just take the M type directly, like change:

--ts_proto_opt=addGenericMetadata=true

To be:

--ts_proto_opt=metadataType=Foo@./some-file

Using ts-proto's imp syntax.

And the output would be:

import { Foo } from "./some-file";

interface HeroService {
  findHero(input, metadata: Foo) {}
}

Which seems like it'd accomplish truly-custom metadata types (so they could potentially be strongly typed, and so "generic" as in "per company" and not "generic" as in "just strings"), without the overhead of always typing out HeroService<FooMetadata>.

Wdyt?

Copy link
Collaborator Author

@fizx fizx Mar 9, 2022

Choose a reason for hiding this comment

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

The shape of the data is pretty locked into Map<string, string[]> semantics, but we represent as key -> { values: string[] } because you can't build a Map<string, string[]> in protobuf, and we're pretty self-referential about this sort of thing. So perhaps there's just enough variability to justify a custom type :)

I agree with you that the generic approach is a little clunky, and the last approach you settled on is pretty good.

I think we prefer an optional metadata: metadata?: Foo so that server implementers only have to think about metadata if they truly need it. Not sure your thoughts there.

Copy link
Owner

Choose a reason for hiding this comment

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

So perhaps there's just enough variability to justify a custom type

:-)

Ah yeah, I guess if the metadata is coming in over the wire, in an extra/baggage type property, it makes sense it's basically HTTP header style key/value(s). I was thinking maybe a server could inject "other things" like logging or something, but that wouldn't be metadata, so n/m I guess...

the last approach you settled on is pretty good.

Cool!

I think we prefer an optional metadata:

Ah yeah, I agree that's fine with me & what we do now. I was being kind of lazy typing it out, but was also thinking that, well, if the user has gone to the trouble of setting ts-proto_opt=metadataType=Foo@... then "surely" (?) for their specific code output they'd probably be fine / actually prefer a required metadata param, but honestly I'm not sure / was just guessing. Whatever you want to do is great.

@fizx fizx changed the title Add generic metadata parameter to the generic service definition interface. feat: Add generic metadata parameter to the generic service definition interface. Mar 14, 2022
@fizx fizx requested a review from stephenh March 14, 2022 23:06
Copy link
Owner

@stephenh stephenh left a comment

Choose a reason for hiding this comment

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

Looks great @fizx , thanks!

@stephenh stephenh merged commit 0f5525a into stephenh:main Mar 15, 2022
stephenh pushed a commit that referenced this pull request Mar 15, 2022
# [1.110.0](v1.109.1...v1.110.0) (2022-03-15)

### Features

* Add generic metadata parameter to the generic service definition interface. ([#530](#530)) ([0f5525a](0f5525a))
@stephenh
Copy link
Owner

🎉 This PR is included in version 1.110.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants