TypeSpec 0.59 - September Release branch (#4386)

Co-authored-by: Christopher Radek <Christopher.Radek@microsoft.com>
This commit is contained in:
Christopher Radek 2024-09-10 15:45:59 -07:00 коммит произвёл GitHub
Родитель bc68f8499a
Коммит 0be9e8f22b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
138 изменённых файлов: 1751 добавлений и 1243 удалений

Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше