title |
---|
August 2022 |
This release contains breaking changes
- Operation parameters without decorators
- OkResponse is no longer a template
- Route resolution changes
- Remove
Map
type @path
may not decorate optional properties or parameters without a default value
A single undecorated (not marked @query
, @header
, @body
or @path
) operation parameter will now become a property of the request body rather than have its type define the request body. This allows defining the body with multiple unannotated parameters, which can include unannotated properties that are spread into parameters. (Previously, more than one unannotated parameter was an error.)
For example, the following used to define a request body of type string
, but now defines a request body that is an object with a property named body
of type string.
op create(body: string): void;
To get the previous behavior, the parameter now needs to be explicitly marked with @body
:
op create(@body body: string): void;
Previously, OkResponse took an argument for the body type. Now it is a simple model like the other XxxResponse types. Alone, it implies a status code of 200 with no body.
Since 200 is the default status code for non-empty bodies, you can usually replace OkResponse<T>
with simply T
.
op get(id: string): OkResponse<Pet>;
Can be:
op get(id: string): Pet;
In certain situations where the body type is not (necessarily) a model, you will need to use the new Body<T>
type. For example.
op list(): OkResponse<Pet[]>;
Can become:
op list(): OkResponse & Body<Pet[]>;
Since 200 status code is used by default, this could also be:
op list(): Pet[];
Generic models based on OkResponse<T>
may also require Body<T>
. For example:
model MyResponse<T> {
...OkResponse<T>;
@header example: string;
}
Since T is not constrainted to be a model, it might be an intrinsic type, an array, or the like, the template should be changed to use Body<T>
:
model MyResponse<T> {
...OkResponse;
...Body<T>;
@header example: string;
}
In general, the prior OkResponse<T>
is equivalent to OkResponse & Body<T>
now or, equivalently, { ...OkResponse, ...Body<T> }
. In practice there are many situations where you can leave out OkResponse altogether and use plain T
rather than Body<T>
.
See also https://typespec.io/docs/libraries/http/#request--response-bodies
Resolving operation routes now follows the following logic:
- if there is a service namespace specified
- only emit the operations and interfaces under that namespace(recursively)
- if not:
- only emit the operations and interfaces defined at the root (DO NOT look into namespaces)
- If a TypeSpec spec used a service namespace without
@serviceTitle
add the@serviceTitle
decorator to the service namespace, otherwise no routes will be emitted. - If a TypeSpec spec contains service namespaces that are not child namespaces of the service namespace, move these namespaces under the service namespace.
op test(): void;
✅ Stay the same
Before | After |
---|---|
["/"] |
["/"] |
namespace DemoService;
op test(): void;
Before | After |
---|---|
[] |
[] |
namespace DemoService;
@route("/")
op test(): void;
Before | After |
---|---|
["/"] |
[] |
Add @serviceTitle
to the namespace
@serviceTitle("DemoService")
namespace DemoService;
@route("/")
op test(): void;
@serviceTitle("My Service")
namespace Foo;
op test(): void;
✅ Stay the same
Before | After |
---|---|
["/"] |
["/"] |
import "@typespec/rest";
using TypeSpec.Http;
@serviceTitle("My Service")
namespace Foo {
@route("in-service")
op test(): void;
}
namespace MyLib {
@route("my-lib")
op test(): void;
}
Before | After |
---|---|
["/in-service", "my-lib"] |
["/in-service"] |
Make any added namespaces children of the service namespace
import "@typespec/rest";
using TypeSpec.Http;
@serviceTitle("My Service")
namespace Foo {
@route("in-service")
op test(): void;
}
namespace Foo.MyLib {
@route("my-lib")
op test(): void;
}
Map
type was removed. Usages of Map<string, T>
can be replaced with new type Record<T>
. Other usages of Map
may be replaced with object
.
model Foo {
options: Map<string, string>;
}
model Foo {
options: Record<string>;
}
model Foo {
options: Map<int32, string>;
}
model Foo {
options: object;
}
Properties and parameters marked with the @path
decorator should be required, but may be optional if they have a default value
model Foo {
@path
name?: string;
}
Was a bad practice, but was allowed in previous versions. This will now throw an error diagnostic.
model Foo {
@path
name: string;
}
model Foo {
@path
name?: string = "singleton";
}