typespec1-9 Exercise 3: Keeping gRPC Out of the REST Contract ================================================================== post_leak.tsp (everything in one @service namespace): import "@typespec/http"; import "@typespec/protobuf"; using Http; using TypeSpec.Protobuf; @package({ name: "post.v1" }) @TypeSpec.service(#{ title: "Post (one namespace)" }) namespace Post; model Parcel { @field(1) id: string; @field(2) weightGrams: int32; } model TrackRequest { @field(1) id: string; } @route("/parcels") interface ParcelsHttp { @route("{id}") @get read(@path id: string): Parcel; } @Protobuf.service interface Tracking { track(...TrackRequest): Parcel; } OpenAPI paths and operation ids produced (line numbers from the YAML file): 7: /: 9: operationId: Tracking_track 24: /parcels/{id}: 26: operationId: ParcelsHttp_read The Tracking.track gRPC call appears in the REST contract as a path of '/'. Nobody designed that route. The .proto has its one rpc, correctly. post_fixed.tsp (the models and the gRPC service in the namespace Post, which has @package; the REST service in its own namespace PostApi, using Post.Parcel): import "@typespec/http"; import "@typespec/protobuf"; using Http; using TypeSpec.Protobuf; @package({ name: "post.v1" }) namespace Post { model Parcel { @field(1) id: string; @field(2) weightGrams: int32; } model TrackRequest { @field(1) id: string; } @Protobuf.service interface Tracking { track(...TrackRequest): Parcel; } } @TypeSpec.service(#{ title: "Post REST" }) namespace PostApi { @route("/parcels") interface Parcels { @route("{id}") @get read(@path id: string): Post.Parcel; } } OpenAPI paths and operation ids produced: 7: /parcels/{id}: 9: operationId: Parcels_read The .proto still has exactly one rpc. WHY IT HAPPENS The HTTP library treats every operation in a @service namespace as an HTTP operation and invents a route from the verb and the parameters. A gRPC method is an operation like any other until it is somewhere the HTTP emitter does not look. WHAT I DID NOT CHECK I did not test whether the same restructuring works with the REST service in a nested namespace, or with several REST services. WHY THIS WORKS AS AN ANSWER --------------------------- It shows the one structural rule behind 'one source for several targets': share the models, separate the operations. Listing the paths is the check, because the compile succeeds either way.