Skip to content

Commit d7ae27d

Browse files
committed
typespec: feedback from typespec team
1 parent 285c2a1 commit d7ae27d

File tree

2 files changed

+58
-34
lines changed

2 files changed

+58
-34
lines changed

openapi/frameworks/typespec.mdx

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ model Address {
2929
@route("/stores")
3030
interface Stores {
3131
list(@query filter: string): Store[];
32-
read(@path id: Store): Store;
32+
read(@path id: string): Store;
3333
}
3434
```
3535

@@ -130,7 +130,7 @@ Just like in TypeScript, code can be organized into files, folders, and modules,
130130

131131
Here's an example of how to import files, folders, and modules in TypeSpec:
132132

133-
```typescript filename="main.tsp"
133+
```typespec filename="main.tsp"
134134
import "./books.tsp"; // Import a file
135135
import "./books"; // Import main.tsp in a folder
136136
import "/books"; // Import a TypeSpec module's main.tsp file
@@ -142,7 +142,7 @@ Modules can be installed using npm, and the `import` statement imports them into
142142

143143
Namespaces are defined using the `namespace` keyword, followed by the namespace name and a block of type definitions. Here's an example:
144144

145-
```typescript
145+
```typespec
146146
namespace MyNamespace {
147147
model User {
148148
id: string;
@@ -153,7 +153,7 @@ namespace MyNamespace {
153153

154154
They may also be defined at the file level, using the `namespace` keyword followed by the namespace name and a block of type definitions. Here's an example:
155155

156-
```typescript
156+
```typespec
157157
namespace MyNamespace;
158158
159159
model User {
@@ -172,7 +172,7 @@ model Post {
172172

173173
[Models](https://typespec.io/docs/language-basics/models) in TypeSpec are similar to OpenAPI's `schema` objects. They define the structure of the data that will be sent and received by an API. Models are defined using the `model` keyword, followed by the model name and a block of properties. Here's an example:
174174

175-
```typescript filename="main.tsp"
175+
```typespec filename="main.tsp"
176176
model User {
177177
id: string;
178178
name: string;
@@ -182,7 +182,7 @@ model User {
182182

183183
Models are composable and extensible. Models can reference other models within a definition, extend a model with additional properties, and compose multiple models into a single model. Here's an example of model composition:
184184

185-
```typescript filename="main.tsp"
185+
```typespec filename="main.tsp"
186186
namespace WithComposition {
187187
model User {
188188
id: string;
@@ -245,22 +245,22 @@ components:
245245

246246
[Operations](https://typespec.io/docs/language-basics/operations) in TypeSpec are similar to OpenAPI operations. They describe the methods that users can call in an API. Operations are defined using the `op` keyword, followed by the operation name. Here's an example:
247247

248-
```typescript filename="main.tsp"
249-
op listUsers(): User[]; // Defaults to GET
250-
op getUser(id: string): User; // Defaults to GET
251-
op createUser(@body user: User): User; // Defaults to POST with a body parameter
248+
```typespec filename="main.tsp"
249+
op list(): User[]; // Defaults to GET
250+
op read(id: string): User; // Defaults to GET
251+
op create(@body user: User): User; // Defaults to POST with a body parameter
252252
```
253253

254254
### Interfaces in TypeSpec
255255

256256
[Interfaces](https://typespec.io/docs/language-basics/interfaces) in TypeSpec group related operations together, similar to OpenAPI's `paths` object. Interfaces are defined using the `interface` keyword, followed by the interface name and a block of operations. Here's an example:
257257

258-
```typescript filename="main.tsp"
258+
```typespec filename="main.tsp"
259259
@route("/users")
260260
interface Users {
261-
op listUsers(): User[]; // Defaults to GET /users
262-
op getUser(id: string): User; // Defaults to GET /users/{id}
263-
op createUser(@body user: User): User; // Defaults to POST /users
261+
op list(): User[]; // Defaults to GET /users
262+
op read(id: string): User; // Defaults to GET /users/{id}
263+
op create(@body user: User): User; // Defaults to POST /users
264264
}
265265
```
266266

@@ -317,7 +317,7 @@ paths:
317317

318318
[Decorators](https://typespec.io/docs/language-basics/decorators) in TypeSpec add metadata to models, operations, and interfaces. They start with the `@` symbol followed by the decorator name. Here's an example of the `@doc` decorator:
319319

320-
```typescript filename="main.tsp" mark=1,3,6,9
320+
```typespec filename="main.tsp" mark=1,3,6,9
321321
@doc("A user in the system")
322322
model User {
323323
@doc("The unique identifier of the user")
@@ -395,7 +395,7 @@ Open the `main.tsp` file in a text editor and write the TypeSpec specification.
395395
396396
Here's an example of a complete TypeSpec file for a Train Travel API:
397397
398-
```typescript
398+
```typespec
399399
import "@typespec/http";
400400
import "@typespec/openapi";
401401
import "@typespec/openapi3";
@@ -646,7 +646,7 @@ Let's break down some of the key features of this TypeSpec file:
646646

647647
The file starts by importing necessary TypeSpec modules:
648648

649-
```typescript
649+
```typespec
650650
import "@typespec/http";
651651
import "@typespec/openapi";
652652
import "@typespec/openapi3";
@@ -661,7 +661,7 @@ These modules extend TypeSpec's capabilities for HTTP APIs and OpenAPI generatio
661661

662662
The `TrainTravelAPI` namespace is decorated with several metadata decorators:
663663

664-
```typescript
664+
```typespec
665665
@service(#{ title: "Train Travel API" })
666666
@info(#{
667667
version: "1.2.1",
@@ -687,7 +687,7 @@ namespace TrainTravelAPI;
687687

688688
TypeSpec supports various validation decorators for model properties:
689689

690-
```typescript
690+
```typespec
691691
/** A train station. */
692692
model Station {
693693
/** Unique identifier for the station. */
@@ -714,7 +714,7 @@ The `@format` decorator adds format annotations (which some OpenAPI tools may ch
714714

715715
Operations can return different response types using union types:
716716

717-
```typescript
717+
```typespec
718718
op `get-stations`(...params):
719719
| {
720720
@body body: {
@@ -757,7 +757,7 @@ Using multiple examples like this requires OpenAPI v3.1 or later.
757757
758758
The `Parameters` namespace defines reusable parameter models:
759759

760-
```typescript
760+
```typespec
761761
namespace Parameters {
762762
model page {
763763
/** The page number to return */
@@ -781,7 +781,7 @@ TypeSpec supports polymorphism through unions with the `@oneOf` decorator, which
781781

782782
Here's an example from the Train Travel API showing how to model payment sources that can be either a card or a bank account:
783783

784-
```typescript
784+
```typespec
785785
/** Card payment source details. */
786786
model CardPaymentSource {
787787
object?: "card";
@@ -936,10 +936,11 @@ options:
936936
"@typespec/openapi3":
937937
emitter-output-dir: "{output-dir}/schema"
938938
openapi-versions:
939+
- 3.1.0
939940
- 3.2.0
940941
```
941942

942-
This will configure TypeSpec to emit OpenAPI 3.2 specifically, which is a newer version of OpenAPI supported by both TypeSpec and Speakeasy. For an older version, change the `openapi-versions` value to `3.1.0`.
943+
This will configure TypeSpec to output both the more compatible OpenAPI v3.1, as well as the latest and greatest OpenAPI v3.2. This newer version is supported by TypeSpec and Speakeasy, and if you have older tools that need the more compatible version why not use both.
943944

944945
Now run the TypeSpec compiler in the project root to generate the OpenAPI document:
945946

@@ -1138,7 +1139,7 @@ TypeSpec allows adding OpenAPI extensions using the `@extension` decorator. This
11381139

11391140
To add retry logic to operations, add the Speakeasy `x-speakeasy-retries` extension to the TypeSpec specification:
11401141

1141-
```typescript
1142+
```typespec
11421143
@tag("Stations")
11431144
@route("/stations")
11441145
@get
@@ -1182,6 +1183,23 @@ paths:
11821183
retryConnectionErrors: true
11831184
```
11841185
1186+
Or, the extension can be added at the namespace level:
1187+
1188+
```typespec name="main.tsp"
1189+
@extension("x-speakeasy-retries", #{
1190+
strategy: "backoff",
1191+
backoff: #{
1192+
initialInterval: 500,
1193+
maxInterval: 60000,
1194+
maxElapsedTime: 3600000,
1195+
exponent: 1.5,
1196+
},
1197+
statusCodes: ["5XX"],
1198+
retryConnectionErrors: true
1199+
})
1200+
namespace TrainTravelAPI;
1201+
```
1202+
11851203
Similar extensions can be added for other Speakeasy features like [pagination](/docs/customize-sdks/pagination), [error handling](/docs/customize-sdks/error-handling), and more.
11861204

11871205
### Step 8: Generate an SDK from the OpenAPI Document
@@ -1220,17 +1238,10 @@ The `speakeasy run` command uses the existing Speakeasy configuration to regener
12201238

12211239
## Limitations of TypeSpec
12221240

1223-
While TypeSpec is a powerful tool for generating OpenAPI documents, there are some limitations to be aware of when using it with Speakeasy.
1224-
1225-
### 1. No Extensions at the Namespace Level
1226-
1227-
The `x-speakeasy-retries` extension cannot be added at the namespace level in the TypeSpec specification, even though Speakeasy supports this extension at the operation level.
1228-
1229-
The TypeSpec documentation on the [@extension](https://typespec.io/docs/libraries/openapi/reference/decorators#@TypeSpec.OpenAPI.extension) decorator does not mention any restrictions on where extensions can be applied, so this may be a bug or an undocumented limitation.
1241+
An earlier version of this guide had a handful of concerns, but TypeSpec has progressed a long way in a short time, and now there is just the one problem we currently have.
12301242

1231-
To work around this limitation, the `x-speakeasy-retries` extension can be added directly to the OpenAPI document using an overlay, as shown in the previous example, or by adding it to each operation individually in the TypeSpec specification**.**
12321243

1233-
### 2. No Support for Webhooks or Callbacks
1244+
### No Support for Webhooks or Callbacks
12341245

12351246
TypeSpec [does not yet support webhooks or callbacks](https://github.com/microsoft/typespec/issues/4736), which are common in modern APIs. This means webhook operations or callback URLs cannot be defined in a TypeSpec specification and OpenAPI documents cannot be generated for them.
12361247

public/assets/openapi/typespec/main.tsp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ using TypeSpec.Versioning;
2525
@versioned(Versions)
2626
@server("http://127.0.0.1:4010", "Book Store API v1")
2727
@doc("API for managing a book store inventory and orders")
28+
29+
@extension("x-speakeasy-retries", #{
30+
strategy: "backoff",
31+
backoff: #{
32+
initialInterval: 500,
33+
maxInterval: 60000,
34+
maxElapsedTime: 3600000,
35+
exponent: 1.5,
36+
},
37+
statusCodes: ["5XX"],
38+
retryConnectionErrors: true
39+
})
40+
2841
namespace BookStore;
2942

3043
enum Versions {
@@ -224,4 +237,4 @@ model Error {
224237

225238
@doc("Error message")
226239
message: string;
227-
}
240+
}

0 commit comments

Comments
 (0)