Emitter operation
The OpenAPI emitter is designed to translate TypeSpec language elements into their corresponding OpenAPI expressions. Hereās how it works:
Server Details
If the TypeSpec file includes an (Http) @server
decorator, the OpenAPI emitter will create a servers
object. This object will contain the server URL, description, and variables as defined in the decorator.
You can use multiple @server
decorators to generate multiple entries in the servers
object.
Operations
Every TypeSpec operation is converted into an OpenAPI operation by the emitter.
The HTTP method for the operation can be explicitly defined using an (Http) @get
, @post
, @put
, @patch
, or @delete
decorator on the operation. If not explicitly defined, the HTTP method is inferred from the operation name and signature.
The operationās path is derived from the (Http) @route
decorator on the operation. The @route
decorator can also be applied to a namespace and/or an interface (a group of operations). If specified, the route for the enclosing namespace(s) and interface are prefixed to the operation route.
The OpenAPI Operation object fields are set as described below.
Description
The description field is populated from the (built-in) @doc
decorator on the TypeSpec operation. If @doc
is not present, the description field is omitted.
Summary
The summary field is populated from the (built-in) @summary
decorator on the TypeSpec operation. If @summary
is not present, the summary field is omitted.
Operation ID
The operation ID can be explicitly defined using the (OpenAPI) @operationId
decorator. If not explicitly defined, the operation ID is simply the operation name, prefixed with ā<interfacename>ā when the operation is within an interface.
Parameters and Request Body
The parameters of the TypeSpec operation are translated into the parameter list and request body for the OpenAPI operation.
The in
field of a parameter is defined using an (Http) @query
, @header
, or @path
decorator. A parameter without one of these decorators is assumed to be passed in the request body.
The request body parameter can also be explicitly defined with an (Http) @body
decorator. If @body
is not explicitly defined, the set of parameters that are not marked @header
, @query
, or @path
form the request body, which is defined as required. If the request body should be optional, it must be declared as an optional property with the @body
decorator.
The content of a (built-in) @doc
decorator on a parameter will be set in the description.
The TypeSpec parameter type will be translated into an appropriate OpenAPI schema for the parameter.
Similarly, the type of the body parameter(s) will be translated into an appropriate OpenAPI schema for the request body. The request body will use the āapplication/jsonā media type unless the body model includes an explicit content-type
header.
For more advanced details, see metadata.
Responses
The return type(s) of the TypeSpec operation are translated into responses for the OpenAPI operation. The status code for a response can be defined as a property in the return type model with the (Http) @statusCode
decorator (the property name is ignored). If the (built-in) @error
decorator is specified on a return type, this return type becomes the ādefaultā response for the operation. The media type for a response will be āapplication/jsonā unless the return type model includes an explicit content-type
header. Models with different status codes and/or media types can be combined to describe complex response designs.
When a return type model has a property explicitly decorated with an (Http) @body
decorator, this is considered as the response body. In the absence of an explicit @body
, the properties that are not marked @statusCode
or @header
form the response body.
For more advanced details, see metadata.
Tags
Any tags specified with the (built-in) @tag
decorator on the operation, interface, or enclosing namespace(s) are included in the OpenAPI operationās tags array.
Deprecated
If the (built-in) #deprecated
directive is specified on the operation, then the operationās deprecated field is set to true.
External Documentation
If the TypeSpec operation has an (OpenAPI) @externalDocs
decorator, this will generate an externalDocs field in the OpenAPI operation.
Specification Extensions
Any extensions specified on the TypeSpec operation with the (OpenAPI) @extension
decorator are included in the emitted OpenAPI operation.
Models and Enums
Models and enums are converted into schemas in the generated OpenAPI definition. Intrinsic types in TypeSpec are represented with a JSON Schema type that closely matches the semantics of the TypeSpec type.
Inline defined models will result in an inline schema. Explicitly declared models will be defined in the components/schemas
section with the TypeSpec name qualified by any enclosing namespaces.
A special case is an instantiation of a model template, it is treated as an inline model unless the model template has a (built-in) @friendlyName
decorator, in which case the schema is defined in components/schemas
with the friendly-name.
The following table shows how TypeSpec types are translated to JSON Schema types:
TypeSpec type | OpenAPI type /format | Notes |
---|---|---|
int32 | type: integer, format: int32 | |
int64 | type: integer, format: int64 | |
float32 | type: number, format: float | |
float64 | type: number, format: double | |
string | type: string | |
bytes | type: string, format: byte | for content-type == āapplication/jsonā or ātext/plainā |
bytes | type: string, format: binary | for ābinaryā content types, e.g. āapplication/octet-streamā, āimage/jpegā |
boolean | type: boolean | |
plainDate | type: string, format: date | |
utcDateTime | type: string, format: date-time | RFC 3339 date in coordinated universal time (UTC) |
offsetDateTime | type: string, format: date-time | RFC 3339 date with timezone offset |
See encoding and format for other ways to encode these types.
There are several decorators that can modify or add metadata to the definitions produced in the generated OpenAPI.
For a numeric element (integer or float):
Decorator | Library | OpenAPI/JSON Schema keyword | Notes |
---|---|---|---|
@minValue(value) | built-in | minimum: value | |
@maxValue(value) | built-in | maximum: value |
For any element defined as a string
or a type that extends from string
:
Decorator | Library | OpenAPI/JSON Schema keyword | Notes |
---|---|---|---|
@format(name) | built-in | format: name | Used when format is not determined by type or another decorator |
@minLength(value) | built-in | minLength: value | |
@maxLength(value) | built-in | maxLength: value | |
@pattern(regex) | built-in | pattern: regex | |
@secret | built-in | format: password |
For an array type:
Decorator | Library | OpenAPI/JSON Schema keyword | Notes |
---|---|---|---|
@minItems(value) | built-in | minItems: value | |
@maxItems(value) | built-in | maxItems: value |
The OpenAPI emitter provides an @useRef
decorator which will replace the TypeSpec model type in emitter output with a reference to a pre-existing named OpenAPI schema. This can be useful for ācommonā schemas.
Example:
Enums can be defined in TypeSpec with the enum
statement, e.g.:
The union operator can also be used to define the enum values inline, e.g.:
The OpenAPI emitter converts both of these into a schema definition containing an āenumā with the list of defined values.
Model Composition
TypeSpec provides several mechanisms for model composition and extension. The following describes how these are handled in the OpenAPI emitter.
Spread
The spread operator does not convey any semantic relationship between the source and target models, so the OpenAPI emitter treats this as if the properties of the source model were explicitly included in the target model at the position where the spread appears.
Extends
When one model extends another model, this is intended to convey an inheritance relationship. While OpenAPI has no formal construct for inheritance, the OpenAPI emitter represents this form of composition with an allOf
in the schema of the child model that references the schema for the parent model.
Extends with Discriminator
The OpenAPI emitter supports the @discriminator(propertyName)
decorator on a model
. This will produce a discriminator
object with the named property in the schema for this model.
Models that extend this model must define this property with a literal string value, and these values must be distinct across all the models that extend this model. These values are used to construct a mapping
for the discriminator.
The @discriminator
decorator can be used to create multi-level discriminated inheritance but must use a different discriminated property at each level.
Is
The is
keyword provides a form of composition similar to the spread operator, where no semantic relationship is conveyed between the source and target models. The OpenAPI emitter represents this form of composition with an independent schema that contains all the same properties as the model named by the is
keyword, plus any properties defined directly on the model.
Union
Unions are another form of model composition.
Unions can be defined in two different ways in TypeSpec. One way is with the union type operator, |
:
The second way is with the union
statement which not only declares the variant models but also assigns a name for each.
The OpenAPI emitter represents either form of union with an anyOf
with an element for each option of the union. The OpenAPI emitter ignores the ānamesā for variants in named unions.
The OpenAPI emitter also defines the@oneOf
decorator which can be specified on a union
statement to indicate that a union should be emitted as a oneOf
rather than anyOf
.
Encoding and Formats
When working with the @encode
decorator, the rule is as follows. Given the 3 values encoding
, encodeAs
, and realType
where @encode(encoding, encodeAs) _: realType
:
- If
realType
isutcDateTime
oroffsetDateTime
:encoding
ofrfc3339
will producetype: string, format: date-time
encoding
ofrfc7231
will producetype: string, format: http-date
- If
realType
isutcDateTime
andencoding
isunixTimestamp
:encodeAs
of any integer type will producetype: integer, format: unixtime
- If the schema of
encodeAs
produces aformat
, use it (e.g., encoding asint32
will producetype: integer, format: integer
) - Otherwise, use the
encoding
as the format
Summary Table
encoding | OpenAPI 3 | Swagger 2.0 (autorest) |
---|---|---|
@encode("seconds", int32) _: duration | type: integer, format: int32 | type: integer, format: int32 |
@encode("seconds", float32) _: duration | type: number, format: float32 | type: number, format: float32 |
@encode("ISO8601") _: duration | type: number, format: duration | type: number, format: duration |
@encode("unixTimestamp", int32) _: utcDateTime | type: integer, format: unixtime | type: integer, format: unixtime |
@encode("unixTimestamp", int64) _: utcDateTime | type: integer, format: unixtime | type: integer, format: unixtime |
@encode("rfc3339") _: utcDateTime | type: string, format: date-time | type: string, format: date-time |
@encode("rfc7231") _: utcDateTime | type: string, format: http-date | type: string, format: http-date |
@encode("http-date") _: utcDateTime | type: string, format: http-date | type: string, format: http-date |
Security Definitions
The OpenAPI emitter uses the (http) @useAuth
decorator to handle security definitions.
Examples
The following example shows how to define a security scheme for Azure Active Directory authentication: