TypeSpec 0.59 - September Release branch (#4386)
Co-authored-by: Christopher Radek <Christopher.Radek@microsoft.com>
This commit is contained in:
Родитель
bc68f8499a
Коммит
0be9e8f22b
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/openapi3"
|
||||
---
|
||||
|
||||
Fix Bug for OpenAPI 3 Emitter crash on `@useAuth({})`
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix Semantic walker doesn't fire exitOperation or exitModelProperty
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/openapi"
|
||||
---
|
||||
|
||||
Add api extractor setup
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/xml"
|
||||
---
|
||||
|
||||
Setup api extractor for xml library
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/playground"
|
||||
---
|
||||
|
||||
Accessibility, increase footer contrast
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/bundler"
|
||||
---
|
||||
|
||||
Allow bundling libraries that don't import their `main` file from the TypeSpec
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: feature
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Add new way to define decorator implementation with `$decorators` export.
|
||||
```ts
|
||||
export const $decorators = {
|
||||
"TypeSpec.OpenAPI": {
|
||||
useRef: $useRef,
|
||||
oneOf: $oneOf,
|
||||
},
|
||||
};
|
||||
```
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: feature
|
||||
packages:
|
||||
- "@typespec/http"
|
||||
- "@typespec/json-schema"
|
||||
- "@typespec/openapi"
|
||||
- "@typespec/openapi3"
|
||||
- "@typespec/protobuf"
|
||||
- "@typespec/rest"
|
||||
- "@typespec/versioning"
|
||||
- "@typespec/xml"
|
||||
---
|
||||
|
||||
Internals: Migrate to new api for declaring decorator implementation
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: feature
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Diagnostics logged to the terminal now have a clickable hyperlink to the diagnostic documentation url if applicable.
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix model expression defined in alias will resolve its namespace from the namespace where the alias was declared
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/html-program-viewer"
|
||||
---
|
||||
|
||||
Fix crash when using anonymous union variant
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/playground"
|
||||
---
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix examples with models using `extends`
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/json-schema"
|
||||
---
|
||||
|
||||
Stop json schema from crashing on unknown scalar and handle `unixTimestamp32`
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix: Model and union expression in template were not considered as template instances
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix numeric 0 stringify producing 0.0
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/openapi3"
|
||||
---
|
||||
|
||||
Fix OpenAPI3 union names when declared within a namespace
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/html-program-viewer"
|
||||
---
|
||||
|
||||
Fix namespace with the same name conflicting in the tree navigation
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/playground"
|
||||
---
|
||||
|
||||
Fix: Reloading the playground will not register the typespec language server
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
||||
Fix error when trying to reference types from another sub namespace of a versioned namespace
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
||||
Fix regression using dep
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/http"
|
||||
---
|
||||
|
||||
Use user provided description of model if model has a status code property(detect it as an response envelope)
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
IDE: Formatting command will use prettier config if provided over the editor's configuration.
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Fix tmlanguage for named type argument in type reference.
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
||||
Add validation to make sure operation params reference models available in the current version
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
||||
Add validation to make sure types referencing array in union types have compatible versioning.
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/versioning"
|
||||
---
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: feature
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Diagnostic code in IDE now link to the linter rule documentation url if applicable
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
API: Extract source resolution logic into its own source loader
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: internal
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Refactor checker: Split type relation logic
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/openapi3"
|
||||
---
|
||||
|
||||
Fixes issue in tsp-openapi3 that resulted in component schemas and parameters with the same name being merged into a single TypeSpec data type.
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/openapi3"
|
||||
---
|
||||
|
||||
Improves tsp-openapi3 model generation from schemas utilizing allOf. Models will now extend an allOf member if it is a schema reference and the only member with a discriminator. Other members will be spread into the model if defined as a schema reference, or have their properties treated as top-level properties if they are an inline-schema.
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
changeKind: fix
|
||||
packages:
|
||||
- "@typespec/openapi3"
|
||||
---
|
||||
|
||||
Updates tsp-openapi3 conversion of OpenAPI3 component schemas to improve handling of enums, unions, scalars, and aliases.
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
|
||||
changeKind: feature
|
||||
packages:
|
||||
- "@typespec/compiler"
|
||||
---
|
||||
|
||||
Improvements to type relation errors: Show stack when it happens in a nested property otherwise show up in the correct location.
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log - @typespec/bundler
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Allow bundling libraries that don't import their `main` file from the TypeSpec
|
||||
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/bundler",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.7",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "Package to bundle a TypeSpec library.",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,34 @@
|
|||
# Change Log - @typespec/compiler
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4381](https://github.com/microsoft/typespec/pull/4381) Fix Semantic walker doesn't fire exitOperation or exitModelProperty
|
||||
- [#4146](https://github.com/microsoft/typespec/pull/4146) Fix model expression defined in alias will resolve its namespace from the namespace where the alias was declared
|
||||
- [#4147](https://github.com/microsoft/typespec/pull/4147) Fix examples with models using `extends`
|
||||
- [#4144](https://github.com/microsoft/typespec/pull/4144) Fix: Model and union expression in template were not considered as template instances
|
||||
- [#4135](https://github.com/microsoft/typespec/pull/4135) Fix numeric 0 stringify producing 0.0
|
||||
- [#4064](https://github.com/microsoft/typespec/pull/4064) IDE: Formatting command will use prettier config if provided over the editor's configuration.
|
||||
- [#4089](https://github.com/microsoft/typespec/pull/4089) Fix tmlanguage for named type argument in type reference.
|
||||
- [#4324](https://github.com/microsoft/typespec/pull/4324) API: Extract source resolution logic into its own source loader
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Add new way to define decorator implementation with `$decorators` export.
|
||||
```ts
|
||||
export const $decorators = {
|
||||
"TypeSpec.OpenAPI": {
|
||||
useRef: $useRef,
|
||||
oneOf: $oneOf,
|
||||
},
|
||||
};
|
||||
```
|
||||
- [#4148](https://github.com/microsoft/typespec/pull/4148) Diagnostics logged to the terminal now have a clickable hyperlink to the diagnostic documentation url if applicable.
|
||||
- [#4141](https://github.com/microsoft/typespec/pull/4141) Diagnostic code in IDE now link to the linter rule documentation url if applicable
|
||||
- [#4357](https://github.com/microsoft/typespec/pull/4357) Improvements to type relation errors: Show stack when it happens in a nested property otherwise show up in the correct location.
|
||||
|
||||
|
||||
## 0.59.1
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/compiler",
|
||||
"version": "0.59.1",
|
||||
"version": "0.60.0",
|
||||
"description": "TypeSpec Compiler Preview",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
"title": "Empty project",
|
||||
"description": "Create an empty project.",
|
||||
"libraries": [],
|
||||
"compilerVersion": "0.59.1"
|
||||
"compilerVersion": "0.60.0"
|
||||
},
|
||||
"rest": {
|
||||
"title": "Generic REST API",
|
||||
"description": "Create a project representing a generic REST API",
|
||||
"compilerVersion": "0.59.1",
|
||||
"compilerVersion": "0.60.0",
|
||||
"libraries": [
|
||||
"@typespec/http",
|
||||
"@typespec/rest",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"library-ts": {
|
||||
"title": "TypeSpec Library (With TypeScript)",
|
||||
"description": "Create a new package to add decorators or linters to typespec.",
|
||||
"compilerVersion": "0.59.1",
|
||||
"compilerVersion": "0.60.0",
|
||||
"libraries": [],
|
||||
"files": [
|
||||
{
|
||||
|
@ -99,7 +99,7 @@
|
|||
"emitter-ts": {
|
||||
"title": "TypeSpec Emitter (With TypeScript)",
|
||||
"description": "Create a new package that will be emitting typespec",
|
||||
"compilerVersion": "0.59.1",
|
||||
"compilerVersion": "0.60.0",
|
||||
"libraries": [],
|
||||
"files": [
|
||||
{
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - @typespec/eslint-plugin
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/eslint-plugin",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "Eslint plugin providing set of rules to be used in the JS/TS code of TypeSpec libraries",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# Change Log - @typespec/html-program-viewer
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4353](https://github.com/microsoft/typespec/pull/4353) Fix crash when using anonymous union variant
|
||||
- [#4136](https://github.com/microsoft/typespec/pull/4136) Fix namespace with the same name conflicting in the tree navigation
|
||||
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/html-program-viewer",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library for emitting an html view of the program.",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - @typespec/http-server-csharp
|
||||
|
||||
## 0.58.0-alpha.3
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.58.0-alpha.2
|
||||
|
||||
No changes, version bump only.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/http-server-csharp",
|
||||
"version": "0.58.0-alpha.2",
|
||||
"version": "0.58.0-alpha.3",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec service code generator for c-sharp",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Changelog - @typespec/http-server-javascript
|
||||
|
||||
## 0.58.0-alpha.3
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.58.0-alpha.2
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/http-server-javascript",
|
||||
"version": "0.58.0-alpha.2",
|
||||
"version": "0.58.0-alpha.3",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec HTTP server code generator for JavaScript",
|
||||
"homepage": "https://github.com/microsoft/typespec",
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
# Change Log - @typespec/http
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4322](https://github.com/microsoft/typespec/pull/4322) Use user provided description of model if model has a status code property(detect it as an response envelope)
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.1
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/http",
|
||||
"version": "0.59.1",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec HTTP protocol binding",
|
||||
"homepage": "https://github.com/microsoft/typespec",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - @typespec/internal-build-utils
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/internal-build-utils",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "Internal library to TypeSpec providing helpers to build.",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
# Change Log - @typespec/json-schema
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4150](https://github.com/microsoft/typespec/pull/4150) Stop json schema from crashing on unknown scalar and handle `unixTimestamp32`
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/json-schema",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library for emitting TypeSpec to JSON Schema and converting JSON Schema to TypeSpec",
|
||||
"homepage": "https://github.com/microsoft/typespec",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - @typespec/library-linter
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/library-linter",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library for linting another library.",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log - @typespec/openapi
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/openapi",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library providing OpenAPI concepts",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
# Change Log - @typespec/openapi3
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4133](https://github.com/microsoft/typespec/pull/4133) Fix Bug for OpenAPI 3 Emitter crash on `@useAuth({})`
|
||||
- [#4123](https://github.com/microsoft/typespec/pull/4123) Fix OpenAPI3 union names when declared within a namespace
|
||||
- [#4216](https://github.com/microsoft/typespec/pull/4216) Fixes issue in tsp-openapi3 that resulted in component schemas and parameters with the same name being merged into a single TypeSpec data type.
|
||||
- [#4232](https://github.com/microsoft/typespec/pull/4232) Improves tsp-openapi3 model generation from schemas utilizing allOf. Models will now extend an allOf member if it is a schema reference and the only member with a discriminator. Other members will be spread into the model if defined as a schema reference, or have their properties treated as top-level properties if they are an inline-schema.
|
||||
- [#4149](https://github.com/microsoft/typespec/pull/4149) Updates tsp-openapi3 conversion of OpenAPI3 component schemas to improve handling of enums, unions, scalars, and aliases.
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.1
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/openapi3",
|
||||
"version": "0.59.1",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library for emitting OpenAPI 3.0 from the TypeSpec REST protocol binding and converting OpenAPI3 to TypeSpec",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# Change Log - @typespec/playground
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4276](https://github.com/microsoft/typespec/pull/4276) Accessibility, increase footer contrast
|
||||
- [#4081](https://github.com/microsoft/typespec/pull/4081) Fix: Reloading the playground will not register the typespec language server
|
||||
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/playground",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec playground UI components.",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - @typespec/prettier-plugin-typespec
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/prettier-plugin-typespec",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log - @typespec/protobuf
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/protobuf",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library and emitter for Protobuf (gRPC)",
|
||||
"homepage": "https://github.com/microsoft/typespec",
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log - @typespec/rest
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.1
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/rest",
|
||||
"version": "0.59.1",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec REST protocol binding",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - typespec-vs
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "typespec-vs",
|
||||
"author": "Microsoft Corporation",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"description": "TypeSpec Language Support for Visual Studio",
|
||||
"homepage": "https://typespec.io",
|
||||
"readme": "https://github.com/microsoft/typespec/blob/main/README.md",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# Change Log - typespec-vscode
|
||||
|
||||
## 0.60.0
|
||||
|
||||
No changes, version bump only.
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bump dependencies
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "typespec-vscode",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec language support for VS Code",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
# Change Log - @typespec/versioning
|
||||
|
||||
## 0.60.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [#4145](https://github.com/microsoft/typespec/pull/4145) Fix error when trying to reference types from another sub namespace of a versioned namespace
|
||||
- [#4179](https://github.com/microsoft/typespec/pull/4179) Add validation to make sure operation params reference models available in the current version
|
||||
- [#4179](https://github.com/microsoft/typespec/pull/4179) Add validation to make sure types referencing array in union types have compatible versioning.
|
||||
|
||||
### Features
|
||||
|
||||
- [#4139](https://github.com/microsoft/typespec/pull/4139) Internals: Migrate to new api for declaring decorator implementation
|
||||
|
||||
|
||||
## 0.59.0
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@typespec/versioning",
|
||||
"version": "0.59.0",
|
||||
"version": "0.60.0",
|
||||
"author": "Microsoft Corporation",
|
||||
"description": "TypeSpec library for declaring and emitting versioned APIs",
|
||||
"homepage": "https://typespec.io",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[
|
||||
"0.60.x",
|
||||
"0.59.x",
|
||||
"0.58.x",
|
||||
"0.57.x",
|
||||
|
|
|
@ -21,6 +21,16 @@ emit:
|
|||
- "@typespec/json-schema"
|
||||
```
|
||||
|
||||
The config can be extended with options as follows:
|
||||
|
||||
```yaml
|
||||
emit:
|
||||
- "@typespec/json-schema"
|
||||
options:
|
||||
"@typespec/json-schema":
|
||||
option: value
|
||||
```
|
||||
|
||||
## Emitter options
|
||||
|
||||
### `file-type`
|
||||
|
|
|
@ -21,7 +21,6 @@ title: "[P] JS API"
|
|||
- [$flags](variables/$flags.md)
|
||||
- [$lib](variables/$lib.md)
|
||||
- [EmitterOptionsSchema](variables/EmitterOptionsSchema.md)
|
||||
- [namespace](variables/namespace.md)
|
||||
|
||||
## Functions
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
jsApi: true
|
||||
title: "[V] namespace"
|
||||
|
||||
---
|
||||
```ts
|
||||
const namespace: "TypeSpec.JsonSchema" = "TypeSpec.JsonSchema";
|
||||
```
|
|
@ -21,6 +21,16 @@ emit:
|
|||
- "@typespec/openapi3"
|
||||
```
|
||||
|
||||
The config can be extended with options as follows:
|
||||
|
||||
```yaml
|
||||
emit:
|
||||
- "@typespec/openapi3"
|
||||
options:
|
||||
"@typespec/openapi3":
|
||||
option: value
|
||||
```
|
||||
|
||||
## Emitter options
|
||||
|
||||
### `file-type`
|
||||
|
|
|
@ -21,6 +21,16 @@ emit:
|
|||
- "@typespec/protobuf"
|
||||
```
|
||||
|
||||
The config can be extended with options as follows:
|
||||
|
||||
```yaml
|
||||
emit:
|
||||
- "@typespec/protobuf"
|
||||
options:
|
||||
"@typespec/protobuf":
|
||||
option: value
|
||||
```
|
||||
|
||||
## Emitter options
|
||||
|
||||
### `noEmit`
|
||||
|
|
|
@ -5,7 +5,7 @@ title: "[F] $externRef"
|
|||
---
|
||||
```ts
|
||||
function $externRef(
|
||||
ctx,
|
||||
context,
|
||||
target,
|
||||
path,
|
||||
name): void
|
||||
|
@ -15,10 +15,10 @@ function $externRef(
|
|||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `ctx` | `DecoratorContext` |
|
||||
| `context` | `DecoratorContext` |
|
||||
| `target` | `Model` |
|
||||
| `path` | `StringLiteral` |
|
||||
| `name` | `StringLiteral` |
|
||||
| `path` | `Type` |
|
||||
| `name` | `Type` |
|
||||
|
||||
## Returns
|
||||
|
||||
|
|
|
@ -71,7 +71,21 @@ const tagName: string = "widgets";
|
|||
|
||||
## JavaScript decorator implementation
|
||||
|
||||
Decorators can be implemented in JavaScript by prefixing the function name with `$`. A decorator function must have the following parameters:
|
||||
Decorators can be implemented in JavaScript in 2 ways:
|
||||
|
||||
1. Prefixing the function name with `$`. e.g `export function $doc(target, name) {...}` **Great to get started/play with decorators**
|
||||
2. Exporting all decorators for your library using `$decorators` variable. **Recommended**
|
||||
|
||||
```ts
|
||||
export const $decorators = {
|
||||
// Namespace
|
||||
"MyOrg.MyLib": {
|
||||
doc: docDecoratorFn,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
A decorator implementation takes the following parameters:
|
||||
|
||||
- `1`: `context` of type `DecoratorContext`
|
||||
- `2`: `target` The TypeSpec type target. (`Namespace`, `Interface`, etc.)
|
||||
|
|
|
@ -8,23 +8,54 @@ pagination_next: getting-started/getting-started-rest/02-operations-responses #
|
|||
|
||||
## Introduction
|
||||
|
||||
Welcome to the first part of our tutorial on using TypeSpec to define REST APIs with HTTP. In this section, we'll introduce you to TypeSpec, help you set up your environment, and cover the basic syntax and structure of TypeSpec. By the end of this section, you'll have a solid foundation to build upon in the subsequent sections.
|
||||
Welcome to our tutorial on using TypeSpec to define REST APIs with HTTP. In this section, we'll introduce you to TypeSpec, help you set up your environment, and cover the basic syntax and structure of TypeSpec. By the end of this section, you'll have a solid foundation to build upon in the subsequent sections.
|
||||
|
||||
### What is TypeSpec?
|
||||
|
||||
TypeSpec is a language and toolset developed by Microsoft for defining data models and service APIs. It provides a structured way to describe the shape and behavior of data and services, ensuring consistency and reducing errors in API development. With TypeSpec, you can generate code, documentation, and other artifacts from your API definitions, making it easier to maintain and evolve your services. Microsoft uses TypeSpec internally to define APIs for various products and services, including Azure.
|
||||
|
||||
TypeSpec is used to define the **interface** of your API, which clients will use to interact with resources provided by your service. This includes specifying the operations, request and response models, and error handling mechanisms. The actual API logic is implemented in the backend service, which processes the requests and communicates with the database.
|
||||
|
||||
Before we start writing TypeSpec code, we need to set up our development environment. For detailed instructions on setting up your environment, please refer to the [Installation Guide](../../introduction/installation.md).
|
||||
|
||||
### Summary of Setup and Installation
|
||||
|
||||
1. **Install Node.js**: Download and install Node.js from [nodejs.org](https://nodejs.org/).
|
||||
1. **Install Node.js**: Download and install Node.js from [nodejs.org](https://nodejs.org/). This will also install npm, the Node.js package manager. The minimum versions required are Node.js 20.0.0 and npm 7.0.0.
|
||||
2. **Install TypeSpec CLI**: Run `npm install -g @typespec/compiler` to install the TypeSpec CLI.
|
||||
3. **Verify Installation**: Run `tsp --version` to verify that the TypeSpec CLI is installed correctly.
|
||||
4. **Create a New Project**:
|
||||
- Run `tsp init` and select the `Generic REST API` template.
|
||||
- Run `tsp install` to install dependencies.
|
||||
- Run `tsp compile .` to compile the initial file. You can also run `tsp compile . --watch` to automatically compile changes on save.
|
||||
- Run `tsp compile .` to compile the initial file.
|
||||
- Run `tsp compile . --watch` to automatically compile changes on save.
|
||||
|
||||
### Project Structure Overview
|
||||
|
||||
Once you've completed these steps, you'll have a basic TypeSpec project set up. Here's an overview of the files and directories in your TypeSpec project:
|
||||
|
||||
```
|
||||
Project Root
|
||||
├── main.tsp
|
||||
├── tspconfig.yaml
|
||||
├── package.json
|
||||
├── node_modules/
|
||||
└── tsp-output/
|
||||
```
|
||||
|
||||
- **main.tsp**: Entry point for TypeSpec definitions.
|
||||
- **tspconfig.yaml**: TypeSpec compiler configuration.
|
||||
- **package.json**: Project metadata and dependencies.
|
||||
- **node_modules/**: Installed dependencies.
|
||||
- **tsp-output/**: Generated files.
|
||||
- **openapi.yaml**: Generated OpenAPI specification.
|
||||
|
||||
As we work through the tutorial, keep the openapi.yaml file open in Visual Studio or VS Code to watch the API specification evolve as we make changes.
|
||||
|
||||
## Basic Syntax and Structure
|
||||
|
||||
Now that we have our environment set up, let's dive into the basic syntax and structure of TypeSpec. We'll start with a simple example to illustrate the key concepts.
|
||||
Now that we have our environment set up, let's dive into the basic syntax and structure of TypeSpec. We'll create a simple REST API for a pet store by introducing concepts in a layered fashion, increasing complexity as we progress through the tutorial.
|
||||
|
||||
As the tutorial advances and the code examples grow more complex, we'll highlight changes in the code to help you easily spot where new lines have been added.
|
||||
|
||||
### Import and Using Statements
|
||||
|
||||
|
@ -32,11 +63,11 @@ Before defining models and services, we need to import the necessary TypeSpec li
|
|||
|
||||
As we progress through the tutorial, you can follow along by updating the `main.tsp` file in your project and compiling the changes to see the results reflected in the generated `openapi.yaml` specification.
|
||||
|
||||
In most cases throughout this tutorial, you can alternatively use the `Try it` feature with the code samples to view the generated OpenAPI spec in your browser via the TypeSpec Playground.
|
||||
You can also alternatively use the `Try it` feature with the code samples to quickly view the generated OpenAPI spec in your browser via the TypeSpec Playground.
|
||||
|
||||
Let's begin by adding the following import and using statements to the `main.tsp` file:
|
||||
|
||||
```typespec
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
@ -47,7 +78,69 @@ In this example:
|
|||
- `import` statement brings in the [TypeSpec HTTP library](../../libraries/http/reference/), which provides the decorators and models we'll be using to define our REST API.
|
||||
- `using` statement makes the imported library available in the current namespace, allowing us to use its features and decorators.
|
||||
|
||||
### Understanding Models
|
||||
**NOTE: Your generated project file likely already has these import/using statements, plus import/using for the `@typespec/openapi3` library. The `@typespec/openapi3` library is necessary for emitting the OpenAPI specification file but is not required for creating our Pet Store API in TypeSpec. Remove them from your `main.tsp` file so your code matches the example above.**
|
||||
|
||||
## Defining a REST Service
|
||||
|
||||
A REST service in TypeSpec is defined using the [`@service`](../../standard-library/built-in-decorators#@service) decorator. This decorator allows you to specify metadata about your service, such as its title. Additionally, you can use the [`@server`](../../libraries/http/reference/decorators#@TypeSpec.Http.server) decorator to define the server endpoint where your service will be hosted.
|
||||
|
||||
### Example: Defining a Service with a Title and Server Endpoint
|
||||
|
||||
Let's start by defining a simple REST service for a Pet Store:
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
// highlight-start
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `@service` decorator is used to define a service with the title "Pet Store".
|
||||
- The `@server` decorator specifies the server endpoint for the service, which is "https://example.com".
|
||||
|
||||
**OpenAPI Comparison**: In OpenAPI, this is similar to defining the `info` object (which includes the title) and the `servers` array (which includes the server URL).
|
||||
|
||||
**NOTE: This code will not compile as-is because we've not yet defined a `namespace` for these decorators to apply to. We'll cover that topic next.**
|
||||
|
||||
## Organizing with Namespaces
|
||||
|
||||
[Namespaces](../../language-basics/namespaces.md) in TypeSpec help you organize your models and operations logically. They act as containers for related definitions, making your API easier to manage and understand.
|
||||
|
||||
### Example: Creating a Namespace
|
||||
|
||||
Let's create a namespace for our Pet Store service:
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
|
||||
// highlight-next-line
|
||||
namespace PetStore;
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `namespace` keyword is used to define a top-level namespace named `PetStore`.
|
||||
- All models and operations related to the Pet Store service will be defined within this namespace.
|
||||
- The first use of namespace defines the top-level namespace and does not require brackets. This is because it serves as the primary container for all related definitions.
|
||||
- Any subsequent namespaces defined within this top-level namespace will require brackets {} to indicate that they are nested within the top-level namespace.
|
||||
|
||||
**OpenAPI Comparison**: In OpenAPI, namespaces are similar to using tags to group related operations and definitions.
|
||||
|
||||
## Defining Models
|
||||
|
||||
In TypeSpec, a [model](../../language-basics/models.md) is a fundamental building block used to define the structure of data. Models are used to represent entities, such as a `Pet`, with various properties that describe the entity's attributes.
|
||||
|
||||
|
@ -55,11 +148,18 @@ In TypeSpec, a [model](../../language-basics/models.md) is a fundamental buildin
|
|||
|
||||
Let's define a simple model for a `Pet`:
|
||||
|
||||
```typespec
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
// highlight-start
|
||||
model Pet {
|
||||
id: int32;
|
||||
name: string;
|
||||
|
@ -74,6 +174,7 @@ enum petType {
|
|||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -82,22 +183,33 @@ In this example:
|
|||
- The `Pet` model has four properties: `id`, `name`, `age`, and `kind`.
|
||||
- The `petType` [`enum`](../../language-basics/enums.md) defines possible values for the `kind` property.
|
||||
|
||||
**OpenAPI Comparison**: In OpenAPI, this is similar to defining a `schema` object under the `components` section, where you define the structure and properties of your data models.
|
||||
|
||||
### Example: Adding Validation Annotations
|
||||
|
||||
We can add [validation](../../language-basics/values#validation) annotations to our model properties to enforce certain constraints:
|
||||
|
||||
```typespec
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
// highlight-next-line
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
// highlight-next-line
|
||||
@minValue(0)
|
||||
// highlight-next-line
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
|
@ -118,219 +230,10 @@ In this example:
|
|||
- `@minLength(1)` ensures that the `name` property has at least one character.
|
||||
- `@minValue(0)` and `@maxValue(100)` ensure that the `age` property is between 0 and 100.
|
||||
|
||||
## Defining a REST Service
|
||||
|
||||
A REST service in TypeSpec is defined using the [`@service`](../../standard-library/built-in-decorators#@service) decorator. This decorator allows you to specify metadata about your service, such as its title. Additionally, you can use the [`@server`](../../libraries/http/reference/decorators#@TypeSpec.Http.server) decorator to define the server endpoint where your service will be hosted.
|
||||
|
||||
### Example: Defining a Service with a Title and Server Endpoint
|
||||
|
||||
Let's start by defining a simple REST service for a Pet Store:
|
||||
|
||||
```typespec
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `@service` decorator is used to define a service with the title "Pet Store".
|
||||
- The `@server` decorator specifies the server endpoint for the service, which is "https://example.com".
|
||||
|
||||
## Organizing with Namespaces
|
||||
|
||||
[Namespaces](../../language-basics/namespaces.md) in TypeSpec help you organize your models and operations logically. They act as containers for related definitions, making your API easier to manage and understand.
|
||||
|
||||
### Example: Creating a Namespace
|
||||
|
||||
Let's create a namespace for our Pet Store service:
|
||||
|
||||
```typespec
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `namespace` keyword is used to define a namespace named `PetStore`.
|
||||
- All models and operations related to the Pet Store service will be defined within this namespace.
|
||||
|
||||
## Adding Models to the Namespace
|
||||
|
||||
Next, we'll add the `Pet` model we defined earlier to our `PetStore` namespace.
|
||||
|
||||
### Example: Adding the Pet Model
|
||||
|
||||
```typespec
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `Pet` model is defined within the `PetStore` namespace.
|
||||
- The model includes validation annotations to enforce constraints on the properties.
|
||||
- The `petType` enum is also defined within the `PetStore` namespace.
|
||||
|
||||
## Defining HTTP Operations
|
||||
|
||||
Now that we have our service, namespace, and model defined, let's add some HTTP [operations](../../language-basics/operations.md) to interact with our `Pet` model. We'll start with a simple `GET` operation to list all pets.
|
||||
|
||||
### Example: Defining a GET Operation
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `@route` decorator is used to define the base path for the `Pets` namespace.
|
||||
- The `@get` decorator defines a `GET` operation named `listPets`.
|
||||
- The `listPets` operation returns a list of `Pet` objects in the response body.
|
||||
|
||||
### Example: Defining a GET Operation with Path Parameter
|
||||
|
||||
Let's add another `GET` operation to retrieve a specific pet by its `petId`.
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `getPet` operation retrieves a specific pet by its `petId` and returns it in the response body.
|
||||
- If the pet is not found, it returns a `NotFoundError`, a custom error we've defined within the PetStore namespace. We'll cover error handling in more detail in a later section.
|
||||
**OpenAPI Comparison**: In OpenAPI, this is similar to using `minLength`, `minimum`, and `maximum` constraints within the `schema` object.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we introduced you to TypeSpec, set up the development environment, and covered the basic syntax and structure of TypeSpec. We defined a simple model with validation annotations, created a REST service with a title and server endpoint, organized our API using namespaces, and added a model and HTTP operations.
|
||||
In this section, we introduced you to TypeSpec, set up the development environment, and covered basic language syntax and structure. We defined a simple REST service, organized our API using namespaces, and defined a model with validation annotations.
|
||||
|
||||
In the next section, we'll dive deeper into defining more HTTP operations and handling different types of responses.
|
||||
With this foundational knowledge, you're now ready to dive deeper into defining operations and handling different types of responses in your REST API. In the next section, we'll expand our API by adding CRUD operations.
|
||||
|
|
|
@ -7,15 +7,15 @@ title: Operations and Responses
|
|||
|
||||
## Introduction
|
||||
|
||||
In this section, we'll build upon the basics we covered in the previous section and guide you through expanding your REST API using TypeSpec. We'll define more HTTP operations and handle different types of responses.
|
||||
In this section, we'll build upon the basics we covered in the previous section. We'll define CRUD operations (Create, Read, Update, Delete) for our Pet Store API and discuss the benefits of using nested namespaces.
|
||||
|
||||
## Defining More HTTP Operations
|
||||
## Defining CRUD Operations
|
||||
|
||||
Now that we have a basic `GET` operation to list all pets, let's add more operations to our API. We'll add operations for creating, updating, and deleting pets.
|
||||
Next, we'll discuss how to define CRUD operations for our API. We'll cover operations for `Creating`, `Reading`, `Updating`, and `Deleting` pets, all within a nested namespace for better organization.
|
||||
|
||||
### Example: Defining a POST Operation
|
||||
### Example: Adding CRUD Operations
|
||||
|
||||
Let's define a `POST` operation to create a new pet:
|
||||
Let's define the CRUD operations for our `Pet` model:
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
@ -49,87 +49,19 @@ enum petType {
|
|||
reptile: "reptile",
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
op createPet(@body pet: Pet): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `createPet` operation is defined using the `@post` decorator.
|
||||
- It takes a `Pet` object in the request body and returns the created `Pet` object with a status code of 201.
|
||||
|
||||
### Example: Defining a PUT Operation
|
||||
|
||||
Let's define a `PUT` operation to update an existing pet:
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
|
@ -140,114 +72,73 @@ namespace Pets {
|
|||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet): {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `updatePet` operation is defined using the `@put` decorator.
|
||||
- It takes a `petId` as a path parameter and a `Pet` object in the request body, returning the updated `Pet` object or a `NotFoundError`.
|
||||
|
||||
### Example: Defining a DELETE Operation
|
||||
|
||||
Let's define a `DELETE` operation to delete an existing pet:
|
||||
|
||||
```typespec
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
op createPet(@body pet: Pet): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
};
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet): {
|
||||
@body updatedPet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `deletePet` operation is defined using the `@delete` decorator.
|
||||
- It takes a `petId` as a path parameter and returns a status code of 204 if the deletion is successful or a `NotFoundError` if the pet is not found.
|
||||
- The `@route` decorator defines the base path for the `Pets` namespace.
|
||||
- The `listPets` operation lists all pets.
|
||||
- The `getPet` operation retrieves a specific pet by its `petId`.
|
||||
- The `createPet` operation creates a new pet.
|
||||
- The `updatePet` operation updates an existing pet.
|
||||
- The `deletePet` operation deletes an existing pet.
|
||||
|
||||
### Benefits of Nested Namespaces
|
||||
|
||||
Using nested namespaces in TypeSpec provides several benefits:
|
||||
|
||||
1. **Organization**: Grouping related operations under a common namespace makes the API easier to manage and understand.
|
||||
2. **Operation IDs**: The TypeSpec compiler appends the namespace name to the `operationId` in the OpenAPI spec, making it clear which resource each operation is intended to operate on.
|
||||
3. **Clarity**: It helps in avoiding naming conflicts and provides a clear structure for the API.
|
||||
|
||||
#### Example: Operation ID in OpenAPI Spec
|
||||
|
||||
For the `listPets` operation defined in the `Pets` namespace, the OpenAPI spec will generate an `operationId` like `Pets_listPets`, making it clear that this operation is related to the `Pets` resource.
|
||||
|
||||
### Example: Route URLs for CRUD Operations
|
||||
|
||||
Here's what the route URLs will look like for the CRUD operations defined in the `Pets` namespace:
|
||||
|
||||
- **List Pets**: `GET https://example.com/pets`
|
||||
- Retrieves a list of all pets.
|
||||
- **Get Pet by ID**: `GET https://example.com/pets/{petId}`
|
||||
- Retrieves a specific pet by its `petId`.
|
||||
- **Create Pet**: `POST https://example.com/pets`
|
||||
- Creates a new pet.
|
||||
- **Update Pet by ID**: `PUT https://example.com/pets/{petId}`
|
||||
- Updates an existing pet by its `petId`.
|
||||
- **Delete Pet by ID**: `DELETE https://example.com/pets/{petId}`
|
||||
- Deletes an existing pet by its `petId`.
|
||||
|
||||
### Operation Flowchart
|
||||
|
||||
For clarity, here's a flowchart that depicts the flow of data and operations within the API:
|
||||
|
||||
```
|
||||
[Client] --> [API Gateway] --> [listPets Operation] --> [Database] --> [Response: List of Pets]
|
||||
[Client] --> [API Gateway] --> [getPet Operation] --> [Database] --> [Response: Pet Details]
|
||||
[Client] --> [API Gateway] --> [createPet Operation] --> [Database] --> [Response: Created Pet]
|
||||
[Client] --> [API Gateway] --> [updatePet Operation] --> [Database] --> [Response: Updated Pet]
|
||||
[Client] --> [API Gateway] --> [deletePet Operation] --> [Database] --> [Response: Deletion Confirmation]
|
||||
```
|
||||
|
||||
## Handling Different Types of Responses
|
||||
|
||||
In a real-world API, different operations might return different types of responses. Let's see how we can handle various response scenarios in TypeSpec.
|
||||
In a real-world API, different operations might return different types of successful responses. Let's see how we can handle various response scenarios in TypeSpec.
|
||||
|
||||
### Example: Handling Validation Errors
|
||||
### Example: Handling Different Status Codes
|
||||
|
||||
Let's define a `ValidationError` model and update our `createPet` operation to handle validation errors.
|
||||
Let's update our pet operations to return different status codes based on the outcome.
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
@ -285,14 +176,81 @@ enum petType {
|
|||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
// highlight-start
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
@post
|
||||
op createPet(@body pet: Pet): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
// highlight-start
|
||||
} | {
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet): {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
// highlight-start
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The pet operations are updated to handle different status codes, depending on the outcome of the operation reported by the backend service.
|
||||
|
||||
**Explanation of the `|` Operator**:
|
||||
|
||||
- The `|` operator is used to define multiple possible responses for an operation. Each response block specifies a different status code and response body.
|
||||
- In the `createPet` operation for example, the `|` operator allows the operation to return either a 201 status code with a `newPet` object or a 202 status code with an `acceptedPet` object.
|
||||
|
||||
### OpenAPI Spec Mapping
|
||||
|
||||
Here is how the TypeSpec operation definitions map to the OpenAPI specification:
|
||||
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<div style="flex: 1;">
|
||||
<h4>TypeSpec Definition:</h4>
|
||||
<pre><code>
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
<nbsp>
|
||||
|
||||
@get
|
||||
op listPets(): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
@statusCode statusCode: 404;
|
||||
};
|
||||
|
||||
@post
|
||||
|
@ -300,46 +258,133 @@ namespace Pets {
|
|||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
};
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet):{
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
@statusCode statusCode: 404;
|
||||
} | {
|
||||
@statusCode statusCode: 500;
|
||||
};
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
@body NoContentResponse;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
@statusCode statusCode: 404;
|
||||
};
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<h4>OpenAPI Spec:</h4>
|
||||
<pre><code>
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
operationId: Pets_listPets
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: The request has succeeded.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
post:
|
||||
operationId: Pets_createPet
|
||||
parameters: []
|
||||
responses:
|
||||
'201':
|
||||
description: The request has succeeded and a new resource has been created as a result.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'202':
|
||||
description: The request has been accepted for processing, but processing has not yet completed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
/pets/{petId}:
|
||||
get:
|
||||
operationId: Pets_getPet
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: The request has succeeded.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'404':
|
||||
description: The server cannot find the requested resource.
|
||||
put:
|
||||
operationId: Pets_updatePet
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: The request has succeeded.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'404':
|
||||
description: The server cannot find the requested resource.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
delete:
|
||||
operationId: Pets_deletePet
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'204':
|
||||
description: 'There is no content to send for this request, but the headers may be useful. '
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@error
|
||||
model ValidationError {
|
||||
code: "VALIDATION_ERROR";
|
||||
message: string;
|
||||
details: string[];
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `ValidationError` model is defined to represent validation errors.
|
||||
- The `createPet` operation is updated to handle validation errors by returning a status code of 400 and a `ValidationError` object.
|
||||
**Note**: As you can see, TypeSpec is much more compact and easier to read compared to the equivalent OpenAPI specification.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we expanded our REST API by defining more HTTP operations, including `POST`, `PUT`, and `DELETE` operations. We also demonstrated how to handle different types of responses, such as validation errors and not found errors.
|
||||
In this section, we demonstrated how to define CRUD operations for your REST API using TypeSpec and discussed the benefits of using nested namespaces. We also covered how to handle different types of successful responses.
|
||||
|
||||
In the next section, we'll dive deeper into handling errors in your REST API, including defining custom response models for error handling.
|
||||
|
|
|
@ -6,7 +6,17 @@ title: Handling Errors
|
|||
|
||||
## Introduction
|
||||
|
||||
In this section, we'll focus on handling errors in your REST API. We've already introduced defining error models in the previous sections, and now we'll expand on that topic. We'll define additional error models, create custom response models for error handling, and demonstrate how to use union types for different response scenarios.
|
||||
In this section, we'll focus on handling errors in your REST API. We'll define error models and demonstrate how to add them as possible responses to your CRUD operations.
|
||||
|
||||
## Why Use Error Models?
|
||||
|
||||
Using error models instead of raw status codes offers several advantages:
|
||||
|
||||
1. **Consistency**: Error models ensure that error responses are consistent across your API. This makes it easier for clients to handle errors predictably.
|
||||
2. **Clarity**: Error models provide clear, structured information about the error, including error codes, messages, and additional details. This helps developers understand what went wrong and how to fix it.
|
||||
3. **Extensibility**: Error models can be extended to include additional information, such as error details, validation issues, or links to documentation. This makes it easier to provide comprehensive error information.
|
||||
4. **Documentation**: Error models improve the generated API documentation by clearly defining the structure of error responses. This helps API consumers understand the possible error responses and how to handle them.
|
||||
5. **Type Safety**: In strongly-typed languages, using error models can provide type safety, ensuring that error responses conform to the expected structure.
|
||||
|
||||
## Defining Error Models
|
||||
|
||||
|
@ -14,7 +24,7 @@ Error models can be used to represent different types of errors that your API mi
|
|||
|
||||
### Example: Defining Common Error Models
|
||||
|
||||
We've already defined models to represent validation errors and not-found errors. We'll now add a model for internal server errors:
|
||||
We'll define models to represent validation errors, not-found errors, and internal server errors:
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
@ -52,13 +62,18 @@ enum petType {
|
|||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
|
||||
// highlight-next-line
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
|
@ -67,240 +82,43 @@ namespace Pets {
|
|||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
};
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet): {
|
||||
@body updatedPet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
|
||||
@error
|
||||
model ValidationError {
|
||||
code: "VALIDATION_ERROR";
|
||||
message: string;
|
||||
details: string[];
|
||||
}
|
||||
|
||||
@error
|
||||
model InternalServerError {
|
||||
code: "INTERNAL_SERVER_ERROR";
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `ValidationError`, `NotFoundError`, and `InternalServerError` models are defined to represent different types of errors.
|
||||
- The `@error` decorator is used to indicate that these models represent error responses.
|
||||
|
||||
## Custom Response Models for Error Handling
|
||||
|
||||
Sometimes, you may need to create custom response models to handle specific error scenarios. Let's define a custom response model for the `InternalServerError` we just created.
|
||||
|
||||
### Example: Defining a Custom Response Model
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
op createPet(@body pet: Pet): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
};
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet): {
|
||||
@body updatedPet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
} | InternalServerErrorResponse;
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
message: string;
|
||||
}
|
||||
|
||||
@error
|
||||
model ValidationError {
|
||||
code: "VALIDATION_ERROR";
|
||||
message: string;
|
||||
details: string[];
|
||||
}
|
||||
|
||||
@error
|
||||
model InternalServerError {
|
||||
code: "INTERNAL_SERVER_ERROR";
|
||||
message: string;
|
||||
}
|
||||
|
||||
model InternalServerErrorResponse {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `InternalServerErrorResponse` model is defined to represent a custom response for a 500 Internal Server Error.
|
||||
- The `updatePet` operation is updated to respond with with our custom `InternalServerErrorResponse` in case of an internal server error.
|
||||
|
||||
## Union Expressions for Different Response Scenarios
|
||||
|
||||
Union expressions are a type of [union](../../language-basics/unions.md) that allows you to define operations that can return different responses based on various scenarios.
|
||||
|
||||
We've already seen some examples of this, let's expand on how we can use union types to handle different response scenarios in our operations.
|
||||
|
||||
### Example: Using Union Expressions for Responses
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
@minLength(1)
|
||||
name: string;
|
||||
|
||||
@minValue(0)
|
||||
@maxValue(100)
|
||||
age: int32;
|
||||
|
||||
kind: petType;
|
||||
}
|
||||
|
||||
enum petType {
|
||||
dog: "dog",
|
||||
cat: "cat",
|
||||
fish: "fish",
|
||||
bird: "bird",
|
||||
reptile: "reptile",
|
||||
}
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(): {
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32): {
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
op createPet(@body pet: Pet): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
// highlight-start
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
};
|
||||
// highlight-end
|
||||
|
||||
@put
|
||||
op updatePet(@path petId: int32, @body pet: Pet):
|
||||
| {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@body error: NotFoundError;
|
||||
// highlight-start
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| InternalServerErrorResponse;
|
||||
| {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
@delete
|
||||
op deletePet(@path petId: int32): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
@error
|
||||
model NotFoundError {
|
||||
code: "NOT_FOUND";
|
||||
|
@ -319,20 +137,17 @@ model InternalServerError {
|
|||
code: "INTERNAL_SERVER_ERROR";
|
||||
message: string;
|
||||
}
|
||||
|
||||
model InternalServerErrorResponse {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `updatePet` operation is updated to handle multiple response scenarios using union expressions.
|
||||
- It can return an updated `Pet` object, a `NotFoundError`, a `ValidationError`, or an `InternalServerErrorResponse` custom response model.
|
||||
- The `NotFoundError`, `ValidationError`, and `InternalServerError` models are defined to represent different types of errors.
|
||||
- The `@error` decorator is used to indicate that these models represent error responses.
|
||||
- The Pet Store operations are updated to return the appropriate error models when the service can't perform the requested operation.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we focused on defining error handling in your REST API. We expanded on the topic of defining error models, created custom response models for error handling, and demonstrated how to use union expressions for different response scenarios.
|
||||
In this section, we focused on defining error handling in your REST API. We introduced error models and demonstrated how to represent different operation response scenarios in TypeSpec.
|
||||
|
||||
In the next section, we'll dive into reusing common parameters in your REST API.
|
||||
|
|
|
@ -10,13 +10,13 @@ In this section, we'll focus on reusing common parameters in your REST API. Comm
|
|||
|
||||
## Creating a Common Parameters Model
|
||||
|
||||
Let's start by defining a model for common parameters. This model will include parameters that will be used across all pet store operations.
|
||||
Let's start by defining a model for common parameters. This model will include parameters that will be used across all Pet Store operations.
|
||||
|
||||
### Example: Defining Common Parameters
|
||||
|
||||
For the sake of demonstration, we're going to require each API call in our pet store service to include a request ID, a locale, and a client version. Let's define a model for these common parameters, which we'll label `requestID`, `locale`, and `clientVersion`:
|
||||
For the sake of demonstration, we're going to require each API call in our Pet Store service to include a request ID, a locale, and a client version. Let's define a model for these common parameters, which we'll label `requestID`, `locale`, and `clientVersion`:
|
||||
|
||||
```typespec
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
||||
using TypeSpec.Http;
|
||||
|
@ -26,6 +26,7 @@ using TypeSpec.Http;
|
|||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
namespace PetStore;
|
||||
|
||||
model Pet {
|
||||
id: int32;
|
||||
|
||||
|
@ -47,6 +48,7 @@ enum petType {
|
|||
reptile: "reptile",
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
model CommonParameters {
|
||||
@header
|
||||
requestID: string;
|
||||
|
@ -57,6 +59,7 @@ model CommonParameters {
|
|||
@header
|
||||
clientVersion?: string;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -116,45 +119,59 @@ model CommonParameters {
|
|||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
// highlight-next-line
|
||||
op listPets(...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
// highlight-next-line
|
||||
op getPet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
// highlight-next-line
|
||||
op createPet(@body pet: Pet, ...CommonParameters): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
};
|
||||
|
||||
@put
|
||||
// highlight-next-line
|
||||
op updatePet(@path petId: int32, @body pet: Pet, ...CommonParameters):
|
||||
| {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| InternalServerErrorResponse;
|
||||
| {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
};
|
||||
|
||||
@delete
|
||||
// highlight-next-line
|
||||
op deletePet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -176,11 +193,6 @@ model InternalServerError {
|
|||
code: "INTERNAL_SERVER_ERROR";
|
||||
message: string;
|
||||
}
|
||||
|
||||
model InternalServerErrorResponse {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -188,8 +200,84 @@ In this example:
|
|||
- The `CommonParameters` model is reused across multiple operations using the [spread operator](../../language-basics/models#spread) `(...)`, which tells the TypeSpec compiler to expand the model definition inline.
|
||||
- This approach ensures that the common parameters are consistently applied to all relevant operations, making the API more maintainable and reducing redundancy.
|
||||
|
||||
### Example: OpenAPI Specification for Common Parameters
|
||||
|
||||
Let's take a closer look at how the common parameters model with the `spread` operator is represented in the generated OpenAPI specification by looking at the `deletePet` operation:
|
||||
|
||||
```yaml
|
||||
#### Generated OpenAPI Specification:
|
||||
|
||||
paths:
|
||||
/pets/{petId}:
|
||||
delete:
|
||||
operationId: Pets_deletePet
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
// highlight-start
|
||||
- $ref: "#/components/parameters/CommonParameters.requestID"
|
||||
- $ref: "#/components/parameters/CommonParameters.locale"
|
||||
- $ref: "#/components/parameters/CommonParameters.clientVersion"
|
||||
// highlight-end
|
||||
responses:
|
||||
"204":
|
||||
description: "There is no content to send for this request, but the headers may be useful."
|
||||
"404":
|
||||
description: "Not Found"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NotFoundError"
|
||||
components:
|
||||
parameters:
|
||||
// highlight-start
|
||||
CommonParameters.clientVersion:
|
||||
name: client-version
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
CommonParameters.locale:
|
||||
name: locale
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
CommonParameters.requestID:
|
||||
name: request-id
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
// highlight-end
|
||||
schemas:
|
||||
NotFoundError:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
example: "NOT_FOUND"
|
||||
message:
|
||||
type: string
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- **Parameters Section**: The `deletePet` operation includes the `petId` path parameter and the common parameters (`requestID`, `locale`, and `clientVersion`). The common parameters are referenced using `$ref` to ensure they are consistently defined and reused across multiple operations.
|
||||
- **Components Section**: The common parameters are defined under the `components` section, ensuring they are reusable and maintainable. Each parameter is specified with its name, location (`in` indicating header or query), whether it is required, and its schema.
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Consistency**: Ensures that common parameters are applied consistently across all relevant operations.
|
||||
2. **Maintainability**: Changes to common parameters need to be made only once in the `CommonParameters` model, reducing redundancy and potential errors.
|
||||
3. **Clarity**: The generated OpenAPI specification clearly shows which parameters are required for each operation, improving the documentation and usability of the API.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we focused on reusing common parameters in your REST API using TypeSpec. By defining a common parameters model and reusing it across multiple operations, we can make our API more consistent, easier to read, and easier to maintain.
|
||||
In this section, we focused on reusing common parameters in your REST API. By defining a common parameters model and reusing it across multiple operations, we can make our API more consistent, easier to read, and easier to maintain.
|
||||
|
||||
In the next section, we'll dive into adding authentication to your REST API.
|
||||
Next, we'll learn how to add authentication to our REST API.
|
||||
|
|
|
@ -6,15 +6,17 @@ title: Authentication
|
|||
|
||||
## Introduction
|
||||
|
||||
In this section, we'll focus on adding authentication to your REST API. We'll introduce the `@useAuth` decorator, show how to enforce [authentication](../../libraries/http/authentication) on specific operations, and provide an example using Bearer authentication.
|
||||
In this section, we'll focus on adding [authentication](../../libraries/http/authentication) to your REST API. We'll introduce the `@useAuth` decorator, show how to enforce authentication on specific operations, and provide an example using Bearer authentication.
|
||||
|
||||
## Introduction to the `@useAuth` Decorator
|
||||
|
||||
The [@useAuth](../../libraries/http/reference/decorators#@TypeSpec.Http.useAuth) decorator is used to enforce authentication on specific operations in your REST API. This decorator allows you to specify the authentication mechanism that should be used for the operation. The TypeSpec HTTP library provides support for several authentication models, including `BearerAuth` for Bearer authentication.
|
||||
|
||||
Bearer authentication uses tokens for access control. The server generates a token upon login, and the client includes it in the Authorization header for protected resource requests. The server validates the token to grant access to the resource.
|
||||
|
||||
### Example: Enforcing Authentication on Specific Operations
|
||||
|
||||
Let's update our existing operations to enforce authentication using the `@useAuth` decorator. We'll add authentication to the operations that modify pet data, such as creating, updating, and deleting pets.
|
||||
Let's update our existing operations to enforce authentication using the `@useAuth` decorator. We'll add authentication to the operations that modify pet data: creating, updating, and deleting pets. We'll also add a new error model for unauthorized access.
|
||||
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
|
@ -63,47 +65,80 @@ model CommonParameters {
|
|||
namespace Pets {
|
||||
@get
|
||||
op listPets(...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
// highlight-next-line
|
||||
@useAuth(BearerAuth)
|
||||
op createPet(@body pet: Pet, ...CommonParameters): {
|
||||
op createPet(@body pet: Pet, ...CommonParameters):
|
||||
| {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
// highlight-start
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
@put
|
||||
// highlight-next-line
|
||||
@useAuth(BearerAuth)
|
||||
op updatePet(@path petId: int32, @body pet: Pet, ...CommonParameters):
|
||||
| {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| InternalServerErrorResponse;
|
||||
| {
|
||||
// highlight-start
|
||||
@statusCode statusCode: 401;
|
||||
|
||||
@body error: UnauthorizedError;
|
||||
// highlight-end
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
};
|
||||
|
||||
@delete
|
||||
// highlight-next-line
|
||||
@useAuth(BearerAuth)
|
||||
op deletePet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 204;
|
||||
// highlight-start
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
// highlight-end
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -120,6 +155,14 @@ model ValidationError {
|
|||
details: string[];
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
@error
|
||||
model UnauthorizedError {
|
||||
code: "UNAUTHORIZED";
|
||||
message: string;
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
@error
|
||||
model InternalServerError {
|
||||
code: "INTERNAL_SERVER_ERROR";
|
||||
|
@ -135,8 +178,91 @@ model InternalServerErrorResponse {
|
|||
In this example:
|
||||
|
||||
- The `@useAuth(BearerAuth)` decorator is applied to the `createPet`, `updatePet`, and `deletePet` operations to enforce authentication using the Bearer authentication mechanism.
|
||||
- Bearer authentication uses tokens for access control. The server generates a token upon login, and the client includes it in the Authorization header for protected resource requests.
|
||||
- A new error model, `UnauthorizedError`, is defined to handle unauthorized access errors.
|
||||
- The `UnauthorizedError` model is used in the `createPet`, `updatePet`, and `deletePet` operations to indicate unauthorized access.
|
||||
|
||||
### Example: OpenAPI Specification with Authentication
|
||||
|
||||
Let's take a closer look at how the `@useAuth` decorator affects the generated OpenAPI specification for the `deletePet` operation.
|
||||
|
||||
```yaml
|
||||
paths:
|
||||
/pets/{petId}:
|
||||
delete:
|
||||
operationId: Pets_deletePet
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
- $ref: "#/components/parameters/CommonParameters.requestID"
|
||||
- $ref: "#/components/parameters/CommonParameters.locale"
|
||||
- $ref: "#/components/parameters/CommonParameters.clientVersion"
|
||||
// highlight-start
|
||||
security:
|
||||
- BearerAuth: []
|
||||
// highlight-end
|
||||
responses:
|
||||
"204":
|
||||
description: "There is no content to send for this request, but the headers may be useful."
|
||||
"404":
|
||||
description: "Not Found"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NotFoundError"
|
||||
components:
|
||||
parameters:
|
||||
CommonParameters.clientVersion:
|
||||
name: client-version
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
CommonParameters.locale:
|
||||
name: locale
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
CommonParameters.requestID:
|
||||
name: request-id
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
// highlight-start
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
// highlight-end
|
||||
schemas:
|
||||
NotFoundError:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
example: "NOT_FOUND"
|
||||
message:
|
||||
type: string
|
||||
```
|
||||
|
||||
### Explanation
|
||||
|
||||
- **Security Section**: The `security` section in the `deletePet` operation specifies that Bearer authentication is required. This is indicated by the `BearerAuth` security scheme.
|
||||
- **Security Schemes**: The `components` section includes a `securitySchemes` definition for `BearerAuth`, specifying that it uses the HTTP bearer authentication scheme.
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Security**: Ensures that only authorized clients can perform certain actions by enforcing authentication on specific operations.
|
||||
2. **Consistency**: The use of common parameters and authentication mechanisms is consistently applied across relevant operations.
|
||||
3. **Clarity**: The generated OpenAPI specification clearly shows which operations require authentication and which parameters are needed, improving the documentation and usability of the API.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we focused on adding authentication to your REST API using TypeSpec. By using the `@useAuth` decorator, we can enforce authentication on specific operations, ensuring that only authorized clients can perform certain actions.
|
||||
|
||||
In the next section, we'll dive into versioning your REST API. Versioning allows you to introduce new features and improvements while maintaining backward compatibility for existing clients.
|
||||
|
|
|
@ -14,17 +14,25 @@ Before we can use the versioning decorators, we need to add the `@typespec/versi
|
|||
|
||||
### Step 1: Update `package.json`
|
||||
|
||||
Add the `@typespec/versioning` library to your `package.json` file:
|
||||
Add the `@typespec/versioning` library to your `package.json` file, in both the `peerDependencies` and `devDependencies` sections. Your updated `package.json` should look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "tsp_pet_store",
|
||||
"name": "typespec-petstore",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"peerDependencies": {
|
||||
"@typespec/compiler": "latest",
|
||||
"@typespec/http": "latest",
|
||||
"@typespec/openapi3": "latest",
|
||||
// highlight-next-line
|
||||
"@typespec/versioning": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typespec/compiler": "latest",
|
||||
"@typespec/http": "latest",
|
||||
"@typespec/openapi3": "latest",
|
||||
// highlight-next-line
|
||||
"@typespec/versioning": "latest"
|
||||
},
|
||||
"private": true
|
||||
|
@ -47,24 +55,29 @@ The [`@versioned`](../../libraries/versioning/reference/decorators#@TypeSpec.Ver
|
|||
|
||||
Let's define two versions of our API, `v1` and `v2`:
|
||||
|
||||
```typespec
|
||||
```tsp tryit="{"emit": ["@typespec/openapi3"]}"
|
||||
import "@typespec/http";
|
||||
// highlight-next-line
|
||||
import "@typespec/versioning";
|
||||
|
||||
using TypeSpec.Http;
|
||||
// highlight-next-line
|
||||
using TypeSpec.Versioning;
|
||||
|
||||
@service({
|
||||
title: "Pet Store",
|
||||
})
|
||||
@server("https://example.com", "Single server endpoint")
|
||||
// highlight-next-line
|
||||
@versioned(Versions)
|
||||
namespace PetStore;
|
||||
|
||||
// highlight-start
|
||||
enum Versions {
|
||||
v1: "1.0",
|
||||
v2: "2.0",
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -73,6 +86,28 @@ In this example:
|
|||
- The `@versioned` decorator is used to define the versions supported by the API, defined in the `Versions` enum.
|
||||
- The `Versions` enum specifies two versions: `v1` (1.0) and `v2` (2.0).
|
||||
|
||||
### Generating OpenAPI Specifications for Different Versions
|
||||
|
||||
Once we start adding versions, the TypeSpec compiler will generate individual OpenAPI specifications for each version. In our case, it will generate two OpenAPI specs, one for each version of our Pet Store service API. Our file structure will now look like this:
|
||||
|
||||
```tsp
|
||||
main.tsp
|
||||
tspconfig.yaml
|
||||
package.json
|
||||
node_modules/
|
||||
tsp-output/
|
||||
┗ @typespec/
|
||||
┗ openapi3/
|
||||
// highlight-start
|
||||
┣ openapi.1.0.yaml
|
||||
┗ openapi.2.0.yaml
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
Generating separate specs for each version ensures backward compatibility, provides clear documentation for developers to understand differences between versions, and simplifies maintenance by allowing independent updates to each version's specifications.
|
||||
|
||||
By encapsulating different versions of the API within the context of the same TypeSpec project, we can manage all versions in a unified manner. This approach makes it easier to maintain consistency, apply updates, and ensure that all versions are properly documented and aligned with the overall API strategy.
|
||||
|
||||
## Using the `@added` Decorator
|
||||
|
||||
The [`@added`](../../libraries/versioning/reference/decorators#@TypeSpec.Versioning.added) decorator is used to indicate that a model or operation was added in a specific version of the API. This allows you to manage changes and additions to your API over time.
|
||||
|
@ -121,11 +156,13 @@ enum petType {
|
|||
reptile: "reptile",
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
@added(Versions.v2)
|
||||
model Toy {
|
||||
id: int32;
|
||||
name: string;
|
||||
}
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -199,55 +236,83 @@ model CommonParameters {
|
|||
namespace Pets {
|
||||
@get
|
||||
op listPets(...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pets: Pet[];
|
||||
};
|
||||
|
||||
@get
|
||||
op getPet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body pet: Pet;
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@post
|
||||
@useAuth(BearerAuth)
|
||||
op createPet(@body pet: Pet, ...CommonParameters): {
|
||||
op createPet(@body pet: Pet, ...CommonParameters):
|
||||
| {
|
||||
@statusCode statusCode: 201;
|
||||
@body newPet: Pet;
|
||||
} | {
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 202;
|
||||
@body acceptedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
};
|
||||
|
||||
@put
|
||||
@useAuth(BearerAuth)
|
||||
op updatePet(@path petId: int32, @body pet: Pet, ...CommonParameters):
|
||||
| {
|
||||
@statusCode statusCode: 200;
|
||||
@body updatedPet: Pet;
|
||||
}
|
||||
| {
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| InternalServerErrorResponse;
|
||||
| {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 500;
|
||||
@body error: InternalServerError;
|
||||
};
|
||||
|
||||
@delete
|
||||
@useAuth(BearerAuth)
|
||||
op deletePet(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@body error: NotFoundError;
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
};
|
||||
|
||||
// highlight-start
|
||||
@route("{petId}/toys")
|
||||
namespace Toys {
|
||||
@added(Versions.v2)
|
||||
@get
|
||||
op listToys(@path petId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 200;
|
||||
@body toys: Toy[];
|
||||
} | {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@added(Versions.v2)
|
||||
|
@ -256,13 +321,32 @@ namespace Pets {
|
|||
op createToy(@path petId: int32, @body toy: Toy, ...CommonParameters): {
|
||||
@statusCode statusCode: 201;
|
||||
@body newToy: Toy;
|
||||
} | {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
} | {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
};
|
||||
|
||||
@added(Versions.v2)
|
||||
@put
|
||||
@useAuth(BearerAuth)
|
||||
op updateToy(@path petId: int32, @path toyId: int32, @body toy: Toy, ...CommonParameters): {
|
||||
op updateToy(@path petId: int32, @path toyId: int32, @body toy: Toy, ...CommonParameters):
|
||||
| {
|
||||
@body updatedToy: Toy;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 400;
|
||||
@body error: ValidationError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
}
|
||||
| {
|
||||
@statusCode statusCode: 404;
|
||||
@body error: NotFoundError;
|
||||
};
|
||||
|
||||
@added(Versions.v2)
|
||||
|
@ -270,8 +354,12 @@ namespace Pets {
|
|||
@useAuth(BearerAuth)
|
||||
op deleteToy(@path petId: int32, @path toyId: int32, ...CommonParameters): {
|
||||
@statusCode statusCode: 204;
|
||||
} | {
|
||||
@statusCode statusCode: 401;
|
||||
@body error: UnauthorizedError;
|
||||
};
|
||||
}
|
||||
// highlight-end
|
||||
}
|
||||
|
||||
@error
|
||||
|
@ -287,6 +375,12 @@ model ValidationError {
|
|||
details: string[];
|
||||
}
|
||||
|
||||
@error
|
||||
model UnauthorizedError {
|
||||
code: "UNAUTHORIZED";
|
||||
message: string;
|
||||
}
|
||||
|
||||
@error
|
||||
model InternalServerError {
|
||||
code: "INTERNAL_SERVER_ERROR";
|
||||
|
@ -305,26 +399,6 @@ In this example:
|
|||
- The `@added(Versions.v2)` decorator is applied to the operations within the `Toys` namespace to indicate that they were added in version 2 of the API.
|
||||
- The `Toys` namespace includes operations to list, create, update, and delete toys for a specific pet. These operations are only available in version 2 of the API.
|
||||
|
||||
### Generating OpenAPI Specifications for Different Versions
|
||||
|
||||
Once we start adding versions, the TypeSpec compiler will generate individual OpenAPI specifications for each version. In our case, it will generate two OpenAPI specs, one for each version of our pet store service API. Our file structure will now look like this:
|
||||
|
||||
```
|
||||
main.tsp
|
||||
tspconfig.yaml
|
||||
package.json
|
||||
node_modules/
|
||||
tsp-output/
|
||||
┗ @typespec/
|
||||
┗ openapi3/
|
||||
┃ ┣ openapi.1.0.yaml
|
||||
┃ ┗ openapi.2.0.yaml
|
||||
```
|
||||
|
||||
The 2.0 version of the OpenAPI spec will include the Toy model and any other additions specified for version 2 of our service, while the 1.0 version will not include these additions.
|
||||
|
||||
Generating separate specs for each version ensures backward compatibility, provides clear documentation for developers to understand differences between versions, and simplifies maintenance by allowing independent updates to each version's specifications.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we focused on implementing versioning in your REST API. By using the `@versioned` and `@added` decorators, we can manage changes to our API over time without breaking existing clients.
|
||||
In the next section, we'll dive into creating custom response models for your REST API.
|
||||
|
|
|
@ -6,31 +6,39 @@ title: Custom Response Models
|
|||
|
||||
## Introduction
|
||||
|
||||
In this section, we'll focus on creating custom response models. We'll define custom response models, extend base response models, and demonstrate how to use them in your API operations. We'll also incorporate existing response models from the TypeSpec HTTP library.
|
||||
In this section, we'll focus on creating custom response models and demonstrate how to use them in your API operations. We'll also incorporate predefined response models from the TypeSpec HTTP library.
|
||||
|
||||
## Introduction to Custom Response Models
|
||||
|
||||
Custom response models allow you to define structured responses for your API operations. They help ensure consistency and clarity in your API responses. TypeSpec defines response models for common HTTP responses in the [HTTP library](https://typespec.io/docs/libraries/http/reference), which we can incorporate into our custom response models.
|
||||
|
||||
### Common HTTP Status Codes and TypeSpec Response Models
|
||||
|
||||
Here are some common HTTP status codes and their equivalent TypeSpec response models from the TypeSpec HTTP library:
|
||||
|
||||
| **HTTP Status Code** | **Meaning** | **TypeSpec Response Model** |
|
||||
| -------------------- | --------------------------------------------------------------------------- | --------------------------- |
|
||||
| 200 OK | The request was successful, and the server returned the requested resource. | `OkResponse` |
|
||||
| 201 Created | The request was successful, and a new resource was created. | `CreatedResponse` |
|
||||
| 204 No Content | The request was successful, but there is no content to return. | `NoContentResponse` |
|
||||
| 400 Bad Request | The server could not understand the request due to invalid syntax. | `BadRequestResponse` |
|
||||
| 401 Unauthorized | The client must authenticate itself to get the requested response. | `UnauthorizedResponse` |
|
||||
| 403 Forbidden | The client does not have access rights to the content. | `ForbiddenResponse` |
|
||||
| 404 Not Found | The server cannot find the requested resource. | `NotFoundResponse` |
|
||||
|
||||
### Benefits of Using Custom Response Models
|
||||
|
||||
- **Reducing Duplication**: By defining common response structures once, you can reuse them across multiple operations.
|
||||
- **Improving Readability**: Custom response models make your API definitions clearer and easier to understand.
|
||||
- **Minimizing Errors**: Consistent response models help reduce the likelihood of errors in your API responses.
|
||||
|
||||
## Defining Custom Response Models
|
||||
## Creating Custom Response Models
|
||||
|
||||
Let's start by defining some basic custom response models. We'll incorporate existing response models from the TypeSpec HTTP library.
|
||||
Let's start by defining and extending some custom response models. These models will incorporate existing response models from the TypeSpec HTTP library to ensure consistency.
|
||||
|
||||
### Example: Defining Basic Custom Response Models
|
||||
|
||||
```typespec
|
||||
import "@typespec/http";
|
||||
import "@typespec/versioning";
|
||||
|
||||
using TypeSpec.Http;
|
||||
using TypeSpec.Versioning;
|
||||
### Example: Defining and Extending Custom Response Models
|
||||
|
||||
```tsp
|
||||
model PetListResponse {
|
||||
...OkResponse;
|
||||
...Body<Pet[]>;
|
||||
|
@ -50,6 +58,25 @@ model PetErrorResponse {
|
|||
...BadRequestResponse;
|
||||
...Body<ValidationError>;
|
||||
}
|
||||
|
||||
model PetNotFoundResponse {
|
||||
...NotFoundResponse;
|
||||
...Body<NotFoundError>;
|
||||
}
|
||||
|
||||
model PetUnauthorizedResponse {
|
||||
...UnauthorizedResponse;
|
||||
...Body<UnauthorizedError>;
|
||||
}
|
||||
|
||||
model PetSuccessResponse {
|
||||
...OkResponse;
|
||||
...Body<string>;
|
||||
}
|
||||
|
||||
model PetNoContentResponse {
|
||||
...NoContentResponse;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
@ -58,35 +85,12 @@ In this example:
|
|||
- `PetResponse` extends `OkResponse` and includes a body with a single `Pet` object.
|
||||
- `PetCreatedResponse` extends `CreatedResponse` and includes a body with a newly created `Pet` object.
|
||||
- `PetErrorResponse` extends `BadRequestResponse` and includes a body with a `ValidationError` object.
|
||||
|
||||
## Extending Base Response Models
|
||||
|
||||
We can extend base response models to create more specific responses for different scenarios.
|
||||
|
||||
### Example: Extending Base Response Models
|
||||
|
||||
```typespec
|
||||
model PetNotFoundResponse {
|
||||
...NotFoundResponse;
|
||||
...Body<NotFoundError>;
|
||||
}
|
||||
|
||||
model PetUnauthorizedResponse {
|
||||
...UnauthorizedResponse;
|
||||
...Body<APIError>;
|
||||
}
|
||||
|
||||
model PetSuccessResponse {
|
||||
...OkResponse;
|
||||
...Body<string>;
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- `PetNotFoundResponse` extends `NotFoundResponse` and includes a body with a `NotFoundError` object.
|
||||
- `PetUnauthorizedResponse` extends `UnauthorizedResponse` and includes a body with an `APIError` object.
|
||||
- `PetUnauthorizedResponse` extends `UnauthorizedResponse` and includes a body with an `UnauthorizedError` object.
|
||||
- `PetSuccessResponse` extends `OkResponse` and includes a body with a success message.
|
||||
- `PetNoContentResponse` extends `NoContentResponse` for situations where the request succeeded but there is no content to return.
|
||||
|
||||
**Note**: Base response models like `OkResponse`, `CreatedResponse`, `BadRequestResponse`, `NotFoundResponse`, and `UnauthorizedResponse` are imported from the TypeSpec [HTTP data types library](../../libraries/http/reference/data-types), which we're importing in our project as `@typespec/http`.
|
||||
|
||||
## Using Custom Response Models in Operations
|
||||
|
||||
|
@ -151,6 +155,7 @@ model CommonParameters {
|
|||
clientVersion?: string;
|
||||
}
|
||||
|
||||
// highlight-start
|
||||
model PetListResponse {
|
||||
...OkResponse;
|
||||
...Body<Pet[]>;
|
||||
|
@ -166,6 +171,11 @@ model PetCreatedResponse {
|
|||
...Body<Pet>;
|
||||
}
|
||||
|
||||
model PetAcceptedResponse {
|
||||
...AcceptedResponse;
|
||||
...Body<Pet>;
|
||||
}
|
||||
|
||||
model PetErrorResponse {
|
||||
...BadRequestResponse;
|
||||
...Body<ValidationError>;
|
||||
|
@ -178,7 +188,7 @@ model PetNotFoundResponse {
|
|||
|
||||
model PetUnauthorizedResponse {
|
||||
...UnauthorizedResponse;
|
||||
...Body<ValidationError>;
|
||||
...Body<UnauthorizedError>;
|
||||
}
|
||||
|
||||
model PetSuccessResponse {
|
||||
|
@ -186,34 +196,47 @@ model PetSuccessResponse {
|
|||
...Body<string>;
|
||||
}
|
||||
|
||||
model PetNoContentResponse {
|
||||
...NoContentResponse;
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
@route("/pets")
|
||||
namespace Pets {
|
||||
@get
|
||||
op listPets(...CommonParameters): PetListResponse | BadRequestResponse;
|
||||
// highlight-next-line
|
||||
op listPets(...CommonParameters): PetListResponse;
|
||||
|
||||
@get
|
||||
op getPet(
|
||||
@path petId: int32,
|
||||
@header ifMatch?: string,
|
||||
): PetResponse | PetNotFoundResponse | BadRequestResponse;
|
||||
|
||||
// highlight-start
|
||||
op getPet(@path petId: int32, @header ifMatch?: string): PetResponse | PetNotFoundResponse;
|
||||
// highlight-end
|
||||
@useAuth(BearerAuth)
|
||||
@post
|
||||
op createPet(@body pet: Pet): PetCreatedResponse | PetErrorResponse;
|
||||
// highlight-start
|
||||
op createPet(@body pet: Pet):
|
||||
| PetCreatedResponse
|
||||
| PetAcceptedResponse
|
||||
| PetErrorResponse
|
||||
| PetUnauthorizedResponse;
|
||||
// highlight-end
|
||||
|
||||
@useAuth(BearerAuth)
|
||||
@put
|
||||
// highlight-start
|
||||
op updatePet(@path petId: int32, @body pet: Pet):
|
||||
| PetResponse
|
||||
| PetNotFoundResponse
|
||||
| PetErrorResponse
|
||||
| PetUnauthorizedResponse
|
||||
| PetNotFoundResponse
|
||||
| InternalServerErrorResponse;
|
||||
// highlight-end
|
||||
|
||||
@useAuth(BearerAuth)
|
||||
@delete
|
||||
op deletePet(
|
||||
@path petId: int32,
|
||||
): PetNotFoundResponse | PetSuccessResponse | PetUnauthorizedResponse;
|
||||
// highlight-start
|
||||
op deletePet(@path petId: int32): PetNoContentResponse | PetUnauthorizedResponse;
|
||||
// highlight-end
|
||||
|
||||
@route("{petId}/toys")
|
||||
namespace Toys {
|
||||
|
@ -260,6 +283,12 @@ model ValidationError {
|
|||
details: string[];
|
||||
}
|
||||
|
||||
@error
|
||||
model UnauthorizedError {
|
||||
code: "UNAUTHORIZED";
|
||||
message: string;
|
||||
}
|
||||
|
||||
@error
|
||||
model InternalServerError {
|
||||
code: "INTERNAL_SERVER_ERROR";
|
||||
|
@ -275,13 +304,13 @@ model InternalServerErrorResponse {
|
|||
In this example:
|
||||
|
||||
- The `listPets` operation uses the `PetListResponse` custom response model.
|
||||
- The `getPet` operation uses the `PetResponse`, `PetNotFoundResponse`, and `BadRequestResponse` custom response models.
|
||||
- The `createPet` operation uses the `PetCreatedResponse` and `PetErrorResponse` custom response models.
|
||||
- The `updatePet` operation uses the `PetResponse`, `PetNotFoundResponse`, `PetUnauthorizedResponse`, and `InternalServerErrorResponse` custom response models.
|
||||
- The `deletePet` operation uses the `PetNotFoundResponse`, `PetSuccessResponse`, and `PetUnauthorizedResponse` custom response models.
|
||||
- The `getPet` operation uses the `PetResponse` and `PetNotFoundResponse` custom response models.
|
||||
- The `createPet` operation uses the `PetCreatedResponse`, `PetAcceptedResponse`, `PetErrorResponse`, and `PetUnauthorizedResponse` custom response models.
|
||||
- The `updatePet` operation uses the `PetResponse`, `PetErrorResponse`, `PetUnauthorizedResponse`, `PetNotFoundResponse`, and `InternalServerErrorResponse` custom response models.
|
||||
- The `deletePet` operation uses the `PetNoContentResponse` and `PetUnauthorizedResponse` custom response models.
|
||||
|
||||
Note that we could also define custom response models for the `Toys` operations, similar to the `Pets` operations. But for brevity, we're omitting them in this example.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this section, we focused on creating custom response models in your REST API. By defining and using custom response models, we can reduce duplication, improve readability, and minimize errors in our API responses. We also incorporated existing response models from the TypeSpec HTTP library to ensure consistency and clarity.
|
||||
In this section, we focused on creating custom response models in your REST API. By defining and extending custom response models, we can reduce duplication, improve readability, and minimize errors in our API responses. We also incorporated existing response models from the TypeSpec HTTP library to ensure consistency and clarity.
|
||||
|
|
|
@ -12,7 +12,7 @@ Throughout this tutorial, we've covered a wide range of topics to help you build
|
|||
- **Defining Models and Services**: We learned how to define models and services using TypeSpec.
|
||||
- **Creating and Organizing Namespaces**: We organized our API using namespaces to group related models and operations.
|
||||
- **Defining HTTP Operations**: We defined various HTTP operations, including GET, POST, PUT, and DELETE.
|
||||
- **Handling Errors**: We created error models and custom response models to handle different types of errors.
|
||||
- **Handling Errors**: We created error models to handle different types of errors.
|
||||
- **Reusing Common Parameters**: We defined common parameters and reused them across multiple operations.
|
||||
- **Adding Authentication**: We enforced authentication on specific operations using the `@useAuth` decorator.
|
||||
- **Implementing Versioning**: We implemented versioning in our API using the `@versioned` and `@added` decorators.
|
||||
|
@ -28,6 +28,6 @@ To continue learning and exploring TypeSpec, here are some additional resources:
|
|||
|
||||
## Feedback and Community Engagement
|
||||
|
||||
We value your feedback and would love to hear about your experiences with this tutorial. Please feel free to share your thoughts and suggestions.
|
||||
We value your feedback and would love to hear about your experiences with this tutorial. Please feel free to share your thoughts and suggestions in our [GitHub discussions channel](https://github.com/microsoft/typespec/discussions).
|
||||
|
||||
Join the TypeSpec community on Discord to engage with other developers, ask questions, and contribute to discussions. Your participation helps us improve and grow the TypeSpec ecosystem.
|
||||
Join the TypeSpec community on [Discord](https://aka.ms/typespec/discord) to engage with other developers, ask questions, and contribute to discussions. Your participation helps us improve and grow the TypeSpec ecosystem.
|
||||
|
|
|
@ -31,6 +31,39 @@ When you use the extensions for VS Code or Visual Studio, the tsp formatter beco
|
|||
|
||||
If you're working within a TypeSpec file, you can format the document using the default keyboard shortcut for formatting, `alt+shift+F`.
|
||||
|
||||
### Configuration - Prettier
|
||||
|
||||
If a prettier config (`.prettierrc.yaml`, `.prettierrc.json`, etc.) is present in the project, the formatter will use the configuration from there.
|
||||
By default this will then use the typespec style guide without any explicit option.
|
||||
|
||||
:::note
|
||||
This only affect the formatting, when using `tab` key to indent it will still use the editor's configuration, so recommend setting one of the configuration below.
|
||||
:::
|
||||
|
||||
### Configuration - VSCode
|
||||
|
||||
For VSCode to respect the TypeSpec standard style set the following options style
|
||||
|
||||
```json
|
||||
{
|
||||
["typespec"]: {
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration - EditorConfig
|
||||
|
||||
If using `.editorconfig` with the editor config extension
|
||||
|
||||
```editorconfig
|
||||
[*.tsp]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
```
|
||||
|
||||
## Via prettier
|
||||
|
||||
The tsp formatter is essentially a `prettier` plugin. If you already have a `prettier` configuration set up for other languages, it can be quite handy to simply integrate TypeSpec into this existing pipeline.
|
||||
|
|
|
@ -39,7 +39,7 @@ Run the following command in a clean directory to create a new TypeSpec project.
|
|||
tsp init
|
||||
```
|
||||
|
||||
This will prompt you with a few questions. Pick the `Generic REST API` template, your project name, and select the `@typespec/openapi3` library.
|
||||
This will prompt you with a few questions. Pick the `Generic REST API` template, your project name, and make sure the `@typespec\http` and `@typespec/openapi3` libraries are selected.
|
||||
|
||||
Next, you can install the dependencies.
|
||||
|
||||
|
@ -47,6 +47,12 @@ Next, you can install the dependencies.
|
|||
tsp install
|
||||
```
|
||||
|
||||
Run a build to generate the OpenAPI specification output file.
|
||||
|
||||
```bash
|
||||
tsp compile .
|
||||
```
|
||||
|
||||
You should now have a basic TypeSpec project setup with a structure looking like this:
|
||||
|
||||
```bash
|
||||
|
@ -67,10 +73,4 @@ tsp-output/
|
|||
- **tsp-output/**: Directory where the TypeSpec compiler outputs generated files.
|
||||
- **openapi.yaml**: The generated OpenAPI specification file for your API, detailing the API's endpoints, models, and operations. The output can vary based on the target format specified in the `tspconfig.yaml` file.
|
||||
|
||||
## Compile project
|
||||
|
||||
```bash
|
||||
tsp compile .
|
||||
```
|
||||
|
||||
You can also run `tsp compile . --watch` to automatically compile changes on save.
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
jsApi: true
|
||||
title: "[F] $onValidate"
|
||||
|
||||
---
|
||||
```ts
|
||||
function $onValidate(program): void
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `program` | `Program` |
|
||||
|
||||
## Returns
|
||||
|
||||
`void`
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
jsApi: true
|
||||
title: "[F] addQueryParamsToUriTemplate"
|
||||
|
||||
---
|
||||
```ts
|
||||
function addQueryParamsToUriTemplate(uriTemplate, params): string
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `uriTemplate` | `string` |
|
||||
| `params` | [`HttpOperationParameter`](../type-aliases/HttpOperationParameter.md)[] |
|
||||
|
||||
## Returns
|
||||
|
||||
`string`
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
jsApi: true
|
||||
title: "[F] getUriTemplatePathParam"
|
||||
|
||||
---
|
||||
```ts
|
||||
function getUriTemplatePathParam(param): string
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `param` | [`HttpOperationPathParameter`](../type-aliases/HttpOperationPathParameter.md) |
|
||||
|
||||
## Returns
|
||||
|
||||
`string`
|
|
@ -94,7 +94,6 @@ title: "[P] JS API"
|
|||
- [$header](functions/$header.md)
|
||||
- [$includeInapplicableMetadataInPayload](functions/$includeInapplicableMetadataInPayload.md)
|
||||
- [$multipartBody](functions/$multipartBody.md)
|
||||
- [$onValidate](functions/$onValidate.md)
|
||||
- [$patch](functions/$patch.md)
|
||||
- [$path](functions/$path.md)
|
||||
- [$post](functions/$post.md)
|
||||
|
@ -106,6 +105,7 @@ title: "[P] JS API"
|
|||
- [$statusCode](functions/$statusCode.md)
|
||||
- [$useAuth](functions/$useAuth.md)
|
||||
- [DefaultRouteProducer](functions/DefaultRouteProducer.md)
|
||||
- [addQueryParamsToUriTemplate](functions/addQueryParamsToUriTemplate.md)
|
||||
- [createMetadataInfo](functions/createMetadataInfo.md)
|
||||
- [getAllHttpServices](functions/getAllHttpServices.md)
|
||||
- [getAllRoutes](functions/getAllRoutes.md)
|
||||
|
@ -133,6 +133,7 @@ title: "[P] JS API"
|
|||
- [getStatusCodeDescription](functions/getStatusCodeDescription.md)
|
||||
- [getStatusCodes](functions/getStatusCodes.md)
|
||||
- [getStatusCodesWithDiagnostics](functions/getStatusCodesWithDiagnostics.md)
|
||||
- [getUriTemplatePathParam](functions/getUriTemplatePathParam.md)
|
||||
- [getVisibilitySuffix](functions/getVisibilitySuffix.md)
|
||||
- [includeInapplicableMetadataInPayload](functions/includeInapplicableMetadataInPayload.md)
|
||||
- [includeInterfaceRoutesInNamespace](functions/includeInterfaceRoutesInNamespace.md)
|
||||
|
|
|
@ -11,14 +11,16 @@ function checkDuplicateTypeName(
|
|||
existing): void
|
||||
```
|
||||
|
||||
Check the given name is not already specific in the existing map. Report a diagnostic if it is.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `program` | `Program` |
|
||||
| `type` | `Type` |
|
||||
| `name` | `string` |
|
||||
| `existing` | `undefined` \| `Record`<`string`, `unknown`\> |
|
||||
| Parameter | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| `program` | `Program` | Program |
|
||||
| `type` | `Type` | Type with the name to check |
|
||||
| `name` | `string` | Name to check |
|
||||
| `existing` | `undefined` \| `Record`<`string`, `unknown`\> | Existing map of name |
|
||||
|
||||
## Returns
|
||||
|
||||
|
|
|
@ -7,12 +7,14 @@ title: "[F] getExtensions"
|
|||
function getExtensions(program, entity): ReadonlyMap<ExtensionKey, any>
|
||||
```
|
||||
|
||||
Get extensions set for the given type.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `program` | `Program` |
|
||||
| `entity` | `Type` |
|
||||
| Parameter | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| `program` | `Program` | Program |
|
||||
| `entity` | `Type` | Type |
|
||||
|
||||
## Returns
|
||||
|
||||
|
|
|
@ -7,12 +7,14 @@ title: "[F] getExternalDocs"
|
|||
function getExternalDocs(program, entity): ExternalDocs | undefined
|
||||
```
|
||||
|
||||
Return external doc info set via the `@externalDocs` decorator.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type |
|
||||
| ------ | ------ |
|
||||
| `program` | `Program` |
|
||||
| `entity` | `Type` |
|
||||
| Parameter | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| `program` | `Program` | Program |
|
||||
| `entity` | `Type` | Type |
|
||||
|
||||
## Returns
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче