Beliebte Suchanfragen
//

Charge your APIs Volume 10: Crafting API Definitions with TypeSpec

12.7.2023 | 4 minutes of reading time

As we approach the summer holiday, I thought of wrapping up the series o with a deep dive into the crafting of API definitions with a example for retail domains. We'll explore the powerful capabilities of Microsoft TypeSpec and its transformation to OpenAPI. Let's go!

Understanding TypeSpec

Microsoft's TypeSpec is a robust language-agnostic tool that allows us to define data models and types. It helps to enforce type-safe design, minimise potential errors, and simplify API maintenance. Its main purpose is to provide a way of defining types and data structures that can be understood and shared across different programming languages.

The crux of TypeSpec is to allow developers to define their data models in one place, keeping them synchronised, less prone to errors, and easy to maintain. TypeSpec creates a "source of truth" for your data models and types.

But be careful, TypeSpec is still under development. The version of the TypeSpec compiler used in this introduction is 0.45.2.

Crafting Retail Models with TypeSpec

In the context of a retail API, these models may represent customers, products, orders, and more. Defining these models accurately is crucial for efficient API functioning.

For instance, the TypeSpec model for a customer could look like this:

1model Customer {
2    id: string;
3    firstName: string;
4    lastName: string;
5    email: string;
6    phone: string;
7}

We can also have a representation of Problem+JSON standardisation of error representation in an API description.

1@error
2model ProblemDetails {
3    type: string;
4    title: string;
5    status: integer;
6    detail: string;
7}

In case of reusability these two models are separated in different tsp files in a models folder. This gives us the possibilities to import the models into the TypeSpec definition.

But, to start with this definition, we need to prepare our workplace a little.

First of all, we need the TypeSpec compiler.

1npm install -g @typespec/compiler

We also need to install the VSCode extensions.

1tsp code install

We then create a folder called customer_http. In this folder we initialise TypeSpec.

1tsp init

To do this, we use the Generic Rest API template. We select @typespec/openapi3 as the library. Then we need to install the dependencies. This gives us the following structure.

1package.json
2tspconfig.yaml
3main.tsp

We describe the definition in main.tsp and also include the models in this file. As we can see in the example.

1import "@typespec/rest";
2import "@typespec/openapi3";
3
4import "../models/customer.tsp";
5import "../models/problemdetails.tsp";
6
7using TypeSpec.Http;
8
9@doc("A service for managing customers")
10@service({
11    title: "Customer Service",
12    version: "1.0.0",
13})
14namespace CustomerService;
15
16@route("/customers")
17@tag("customers")
18@summary("A collection of customers")
19interface Customers {
20    @get list(): Customer[] | ProblemDetails;
21    @get read(@path id: string): Customer | ProblemDetails;
22    @post create(): {@statusCode _: 201 | 404, ...Customer} | ProblemDetails;
23    @patch update(...Customer): Customer | ProblemDetails;
24    @delete delete(@path id: string): Customer | ProblemDetails;
25}

From TypeSpec to OpenAPI

Once we've crafted our TypeSpec models, we can transform them into other formats. One of the most popular choices for API specifications is OpenAPI.

We translate the TypeSpec definition into OpenAPI one by using tsp compile .. This creates a openapi.yaml file in a tsp-output folder. Following we can have a look at the transformed OpenAPI definition.

1openapi: 3.0.0
2info:
3  title: Customer Service
4  version: 1.0.0
5  description: A service for managing customers
6tags:
7  - name: customers
8paths:
9  /customers:
10    get:
11      tags:
12        - customers
13      operationId: Customers_list
14      parameters: []
15      responses:
16        '200':
17          description: The request has succeeded.
18          content:
19            application/json:
20              schema:
21                type: array
22                items:
23                  $ref: '#/components/schemas/Customer'
24                x-typespec-name: Customer[]
25        default:
26          description: An unexpected error response.
27          content:
28            application/json:
29              schema:
30                $ref: '#/components/schemas/ProblemDetails'
31    post:
32      tags:
33        - customers
34      operationId: Customers_create
35      parameters: []
36      responses:
37        '201':
38          description: >-
39            The request has succeeded and a new resource has been created as a
40            result.
41          content:
42            application/json:
43              schema:
44                $ref: '#/components/schemas/Customer'
45        '404':
46          description: The server cannot find the requested resource.
47          content:
48            application/json:
49              schema:
50                $ref: '#/components/schemas/Customer'
51        default:
52          description: An unexpected error response.
53          content:
54            application/json:
55              schema:
56                $ref: '#/components/schemas/ProblemDetails'
57    patch:
58      tags:
59        - customers
60      operationId: Customers_update
61      parameters: []
62      responses:
63        '200':
64          description: The request has succeeded.
65          content:
66            application/json:
67              schema:
68                $ref: '#/components/schemas/Customer'
69        default:
70          description: An unexpected error response.
71          content:
72            application/json:
73              schema:
74                $ref: '#/components/schemas/ProblemDetails'
75      requestBody:
76        required: true
77        content:
78          application/json:
79            schema:
80              $ref: '#/components/schemas/CustomerUpdate'
81  /customers/{id}:
82    get:
83      tags:
84        - customers
85      operationId: Customers_read
86      parameters:
87        - name: id
88          in: path
89          required: true
90          schema:
91            type: string
92      responses:
93        '200':
94          description: The request has succeeded.
95          content:
96            application/json:
97              schema:
98                $ref: '#/components/schemas/Customer'
99        default:
100          description: An unexpected error response.
101          content:
102            application/json:
103              schema:
104                $ref: '#/components/schemas/ProblemDetails'
105    delete:
106      tags:
107        - customers
108      operationId: Customers_delete
109      parameters:
110        - name: id
111          in: path
112          required: true
113          schema:
114            type: string
115      responses:
116        '200':
117          description: The request has succeeded.
118          content:
119            application/json:
120              schema:
121                $ref: '#/components/schemas/Customer'
122        default:
123          description: An unexpected error response.
124          content:
125            application/json:
126              schema:
127                $ref: '#/components/schemas/ProblemDetails'
128components:
129  schemas:
130    Customer:
131      type: object
132      properties:
133        id:
134          type: string
135        firstName:
136          type: string
137        lastName:
138          type: string
139        email:
140          type: string
141        phone:
142          type: string
143      required:
144        - id
145        - firstName
146        - lastName
147        - email
148        - phone
149    CustomerUpdate:
150      type: object
151      properties:
152        id:
153          type: string
154        firstName:
155          type: string
156        lastName:
157          type: string
158        email:
159          type: string
160        phone:
161          type: string
162    ProblemDetails:
163      type: object
164      properties:
165        type:
166          type: string
167        title:
168          type: string
169        status:
170          type: integer
171        detail:
172          type: string
173      required:
174        - type
175        - title
176        - status
177        - detail

Wrapping Up

In essence, Microsoft TypeSpec provides a language-agnostic method to define models, which you can then translate into other API specifications like OpenAPI. This creates a comprehensive and flexible approach to API development, fitting various use cases and technology stacks.

As I bid adieu for the summer, I leave you with the excitement of exploring TypeSpec and its incredible capabilities. Here's to a summer of innovation and relaxation! Stay tuned, and we'll see you after the break with more engaging topics from the world of APIs!

References

GitHub - danielkocot/typespec-playground-retail: A playground for TypeSpec

Introduction | TypeSpec

RFC 7807: Problem Details for HTTP APIs

share post

//

More articles in this subject area

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.