Add @sharedRoute decorator and decouple it from @route#1798
Conversation
|
Changes in this PR will be published to the following url to try(check status of TypeSpec Pull Request Try It pipeline for publish status): Website: https://cadlwebsite.z1.web.core.windows.net/prs/1798/ |
There was a problem hiding this comment.
We need documentation for this, but I also am not clear why we are adding this decorator. Presumably you can set shared state in autoroute using the {shared: bool} object? What would this look like in the context of autoroute? If we are adding this, why are we not deprecating the old way?
I would prefer to defer merging this until next sprint.
|
This is a P0 for client generation for this sprint according to @johanste because we need a better option than the current overloads design. We decided to break this out as a separate decorator because an Here's an example adapted from a sample that Johan wants to get working:
|
| * If the namespace or interface that contains the operation is also marked with a `@route` decorator, | ||
| * it will be used as a prefix to the route URI of the operation. | ||
| * | ||
| * `@route` can only be applied to operations, namespaces, and interfaces. | ||
| * | ||
| * ```typespec | ||
| * @route("/widgets") | ||
| * op getWidget(@path id: string): Widget; | ||
| * ``` | ||
| */ | ||
| extern dec route(target: Namespace | Interface | Operation, path: string, options?: object); |
There was a problem hiding this comment.
If we are preserving the options object, we should include that in the documentation. The docstring should also include @param so that it appears in the generated docs.
There was a problem hiding this comment.
also shouldn't the options be a model expression alias instead of just object?
There was a problem hiding this comment.
Probably, I'm not that good at writing decorator signatures yet. Do you mean this:
extern dec route(target: Namespace | Interface | Operation, path: string, options?: { shared?: boolean});
There was a problem hiding this comment.
yep, or use an alias alias RouteOptions = {...} for the model expression
There was a problem hiding this comment.
the alias might be better for when we have the valueof so we can do: options?: valueof(RouteOptions)
There was a problem hiding this comment.
I added the signature for this but the error reporting on an invalid check isn't so clear. Filed issue #1832 with an example.
| @autoRoute | ||
| @sharedRoute | ||
| op get1(@path name: string): string; | ||
|
|
||
| @test | ||
| @autoRoute | ||
| op get2(@path name: string): string; | ||
| `)) as { get1: Operation; get2: Operation }; |
There was a problem hiding this comment.
Is it common to actually put @autoRoute on individual operations? Why could we not just have @autoRoute take the same options object as @route? Or just have both make use of this decorator?
There was a problem hiding this comment.
Yes, this is the pattern used in Azure.Core. The @autoRoute decorator is placed on ResourceOperation<TResource> which causes it to be applied individually to every operation which uses standard operation signatures via is.
In my earlier comment, I explained that we shouldn't conflate sharedness of routes with @route or @autoRoute because changing an operation signature to go from non-shared to shared means re-applying the original decorator instead of just adding @sharedRoute to the operation, no matter what kind of route it uses. This is the key element of how this PR is intended to affect the design.
| if (entity.kind === "Operation" && details.shared) { | ||
| setSharedRoute(context.program, entity as Operation); | ||
| } |
There was a problem hiding this comment.
I think we should deprecate this pattern if we are going with an @sharedRoute decorator
There was a problem hiding this comment.
I would also like to deprecate it if we proceed with @sharedRoute, but I'm not sure how to deprecate a parameter to a decorator at this moment. A simple diagnostic could work, I suppose.
There was a problem hiding this comment.
That, and you should be able to mark it with @deprecated in the docstring, I think. @timotheeguerin would know for sure.
There was a problem hiding this comment.
That, and you should be able to mark it with @deprecated in the docstring, I think. @timotheeguerin would know for sure.
There was a problem hiding this comment.
You can just call reportDeprecated but with a condition on the parameter being used instead of just every time for the decorator
There was a problem hiding this comment.
also if you add the type for the options
alias RouteOptions = {
@deprecated
shared?: boolean;
}
I don't think it will emit a diagnostic automatically here but we could add that support
There was a problem hiding this comment.
Possible that just calling reportDeprecated directly is better for now. Thanks!
There was a problem hiding this comment.
Even better, we should add a migration script to do this for people
There was a problem hiding this comment.
Added deprecation for the old shared option pattern.
| return path | ||
| ? { | ||
| path, | ||
| shared: entity.kind === "Operation" && isSharedRoute(program, entity as Operation), |
There was a problem hiding this comment.
The original logic simply plumbed details through without regard to whether it was an operation, interface, etc. so this change would introduce a behavioral change.
There was a problem hiding this comment.
In the original design, applying @route on a namespace or interface does not propagate the sharedness status down to the contained operations, so it never worked in practice. The new decorator just makes this explicit in that @sharedRoute can't be applied anywhere but to an operation.
There was a problem hiding this comment.
My overall thoughts are that we should either:
- Deprecate the
{shared: true}pattern on@routeand make use of@sharedRoutethe standard or: - We should not introduce a new decorator and just make
@autoRouteaccept an options object like@routedoes.
Here is the design issue where we said that the options object was the way to go. #984.
I don't know why this did not also go through design. It seems like we are treating it as a bug fix when it's really not and the current implementation would leave us with multiple ways of doing the same thing, which we try to avoid.
| ]); | ||
| }); | ||
|
|
||
| describe("shared routes", () => { |
There was a problem hiding this comment.
@markcowl also left a comment on the original post to make sure that this works for actions, so we should probably add a test that covers that as well.
There was a problem hiding this comment.
I will add a test for that and some extra validation logic.
There was a problem hiding this comment.
Added the validation logic and test to verify.
I brought it up in Thursday's design meeting and there wasn't any objection to it at that point. I asked folks to come comment on the PR if they had other feedback but only Mark has left any so far. |
|
Changes in this PR will be published to the following url to try(check status of TypeSpec Pull Request Try It pipeline for publish status): Website: https://cadlwebsite.z1.web.core.windows.net/prs/1798/ |
|
This PR is ready for another look, I've addressed all PR feedback and added tests where needed. |
41589bd to
60d7fbb
Compare
tjprescott
left a comment
There was a problem hiding this comment.
Looks good but can we also update the shared routes tests in OpenAPI3 (and Autorest on the Azure side) to use @sharedRoute instead of {shared: true}?
|
I've updated the |
|
Sent out the |
This PR decouples the concept of a shared route from the
@routedecorator by adding new@sharedRoutedecorator,setSharedRouteandgetSharedRouteaccessors. I'm also storing the state of shared routes separately so that@autoRouteoperations can also have the shared route status set independently.Note that the old
{shared: true}pattern still continues to work and we still return aggregateRoutePathinformation fromgetRoutePathso that no breaking change is introduced.Fixes #1747.
Tasks
getActionandgetCollectionActionautoRouteshared route support doesn't break openapi shared route logicautorestemitter samples