Skip to content

Commit b996605

Browse files
committed
server codegen documentation
1 parent 0d37580 commit b996605

File tree

1 file changed

+375
-0
lines changed

1 file changed

+375
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
# Generating server stubs with TypeSpec: a user guide
2+
3+
This guide will walk you through the process of generating server stubs from your TypeSpec API specifications, enabling you to quickly scaffold and develop your backend services.
4+
5+
Think of it like building a house. You could ask a builder to build a house for you without any specific instructions, but the result might not be what you had in mind. However, if you provide the builder with a detailed blueprint, they can create a house that matches your vision. **In this analogy, TypeSpec is the blueprint for your API, and the server stub code is the foundation. With this blueprint and foundation in place, you can more efficiently build the rest of your service.**
6+
7+
TypeSpec plays a vital role in your project. By providing a well-defined blueprint and a solid foundation for your API design, TypeSpec helps make the development process more efficient, consistent, and structured.
8+
9+
**Key benefits:**
10+
11+
* **Accelerated development:** Jumpstart your server implementation with automatically generated models and controllers.
12+
* **API consistency:** Ensure your server implementation adheres precisely to your API specification.
13+
* **Reduced manual effort:** Eliminate repetitive coding tasks, freeing you to focus on business logic.
14+
* **Improved maintainability:** Easily update your server as your API evolves by regenerating the stubs from the updated TypeSpec definition.
15+
16+
## Prerequisites
17+
18+
Before you begin, make sure you have the following installed:
19+
20+
* **Node.js:** (version 20.x or later). Download from [https://nodejs.org/](https://nodejs.org/)
21+
* **npm:** (version 6.x or later). Typically included with Node.js.
22+
* **TypeSpec compiler:** Install the latest `@next` version globally using:
23+
24+
```bash
25+
npm install -g @typespec/compiler@next
26+
```
27+
* **Language-specific SDKs (optional):** Depending on the target language of your server, you may need the appropriate SDK. For example, to emit .NET SDKs, install the [.NET SDK](https://dotnet.microsoft.com/download). For Java, install the [JDK](https://www.oracle.com/java/technologies/downloads/).
28+
29+
## Workflow options
30+
31+
You can use the Server Stub Generation feature from TypeSpec in two ways:
32+
33+
1. **Command-line interface (CLI):** Ideal for automated builds and developers comfortable with the command line.
34+
2. **Visual studio code (VSCode) IDE with the TypeSpec extension:** Provides a seamless, integrated development experience within VSCode.
35+
36+
## Configuring `tspconfig.yaml` for server stub generation
37+
38+
The `tspconfig.yaml` file is the heart of your TypeSpec project. It defines how your TypeSpec code is compiled and what outputs are generated. To enable server stub generation, you need to configure the `emit` and `options` sections of this file.
39+
40+
Here's an example `tspconfig.yaml` file that enables server stub generation for both C# (ASP.NET Core) and JavaScript (Node.js/Express):
41+
42+
```yaml
43+
emit:
44+
- "@typespec/openapi3"
45+
- "@typespec/http-client-csharp"
46+
- "@typespec/http-client-js"
47+
- "@typespec/http-server-js"
48+
- "@typespec/http-server-csharp"
49+
options:
50+
"@typespec/openapi3":
51+
emitter-output-dir: "{project-root}/openapi/"
52+
"@typespec/http-client-csharp":
53+
emitter-output-dir: "{project-root}/clients/csharp"
54+
"@typespec/http-client-js":
55+
emitter-output-dir: "{project-root}/clients/javascript"
56+
"@typespec/http-server-csharp":
57+
emitter-output-dir: "{project-root}/servers/aspnet/generated"
58+
"@typespec/http-server-js":
59+
emitter-output-dir: "{project-root}/servers/javascript"
60+
```
61+
62+
**Explanation:**
63+
64+
* **`emit` section:** This section lists the *emitters* that you want to use. An emitter is a plugin that takes your TypeSpec code and generates output in a specific format (e.g., OpenAPI, C# client, JavaScript server).
65+
* `"@typespec/openapi3"`: Generates an OpenAPI 3.0 specification.
66+
* `"@typespec/http-client-csharp"`: Generates a C# client SDK.
67+
* `"@typespec/http-client-js"`: Generates a JavaScript client SDK.
68+
* `"@typespec/http-server-csharp"`: Generates a C# (ASP.NET Core) server stub.
69+
* `"@typespec/http-server-js"`: Generates a JavaScript (Node.js/Express) server stub.
70+
* **`options` section:** This section configures the emitters. For each emitter, you can specify options like the output directory.
71+
* `emitter-output-dir`: This option specifies where the generated code should be placed. The `{project-root}` variable refers to the root directory of your TypeSpec project.
72+
73+
**Important:** Make sure you have installed all the necessary emitters:
74+
```bash
75+
npm install -D @typespec/openapi3 @typespec/http-client-csharp @typespec/http-client-js @typespec/http-server-csharp @typespec/http-server-js
76+
```
77+
78+
## Using the cli to generate server stubs
79+
80+
1. **Create a TypeSpec project:** If you don't already have one, create a new TypeSpec project using `tsp init`.
81+
82+
```bash
83+
mkdir my-api
84+
cd my-api
85+
tsp init
86+
```
87+
88+
During `tsp init`, you will be prompted to select different emitters, including server and client. If you have the necessary dependencies installed, TypeSpec can automatically populate your `tspconfig.yaml` file.
89+
90+
2. **Define your api:** Write your API specification in a `.tsp` file (e.g., `main.tsp`). This is where you define your models, operations, and routes.
91+
92+
3. **Compile your TypeSpec:** Use the `tsp compile` command to generate server stubs and other artifacts based on your specification.
93+
94+
```bash
95+
tsp compile .
96+
```
97+
98+
The compiler will output the generated server stubs to the directories specified in your `tspconfig.yaml` file (e.g., `servers/aspnet/generated` for C#).
99+
100+
4. **Project structure:** After compiling, you will typically see the following structure:
101+
102+
```text
103+
\my-api
104+
\tsp-output
105+
\schema # Generated OpenAPI 3.0 spec
106+
openapi.yaml
107+
\clients # Generated Client SDK for selected language(s)
108+
\dotnet
109+
\node
110+
...
111+
\servers # Generated Server Code
112+
\aspnet
113+
\generated # Generated code for ASP.NET
114+
\node
115+
\generated # Generated code for Node.js
116+
main.tsp
117+
tspconfig.yaml
118+
package.json
119+
```
120+
121+
## Understanding the generated code structure
122+
123+
The server stub generation process creates a basic code structure for your server application. The specific files and folders generated depend on the target language and the complexity of your API.
124+
125+
**C# (ASP.NET core) example:**
126+
127+
Based on a generic 'todo' style app, the generated code structure for C# will typically include:
128+
129+
```text
130+
servers/
131+
┣ aspnet/
132+
┃ ┗ generated/
133+
┃ ┣ controllers/ # Contains the base controller classes
134+
┃ ┃ ┃ ┣ CommentOpsOperationsControllerBase.cs # Base class for comment-related API operations
135+
┃ ┃ ┃ ┣ CommentsOperationsControllerBase.cs # Base class for general comment operations
136+
┃ ┃ ┃ ┣ ... (other controller base classes)
137+
┃ ┣ lib/ # Utility functions
138+
┃ ┃ ┃ ┣ ArrayConstraintAttribute.cs # Custom attributes for enforcing array constraints
139+
┃ ┃ ┃ ┣ Base64UrlConverter.cs # Utility for Base64 URL encoding
140+
┃ ┃ ┃ ┣ ... (other utility files)
141+
┃ ┣ models/ # Defines the data models (DTOs) used by the API
142+
┃ ┃ ┃ ┣ Attachment.cs # Data model representing an attachment
143+
┃ ┃ ┃ ┣ Collaborator.cs # Data model representing a collaborator
144+
┃ ┃ ┃ ┣ ... (other model files)
145+
┃ ┗ operations/ # Defines service interface
146+
┃ ┃ ┃ ┣ ICommentOpsOperations.cs # Service interface for comment-related operations
147+
┃ ┃ ┃ ┣ ICommentsOperations.cs # Service interface for general comment operations
148+
┃ ┃ ┃ ┣ ... (other operation interface files)
149+
```
150+
151+
* **`Controllers`**: These folders contain *base classes* for your API controllers (e.g., `CommentOpsOperationsControllerBase.cs`, `TodoItemsOperationsControllerBase.cs`). These base classes define the API endpoints and handle basic request processing. **You will need to create concrete controller classes that inherit from these base classes and implement your business logic.**
152+
153+
* **`lib`**: This directory contains utility classes such as custom attributes used for server side validation to ensure input data adhere to the spec.
154+
155+
* **`Models`**: These files define the data models (also known as Data Transfer Objects or DTOs) used in your API (e.g., `TodoItem.cs`, `Project.cs`). These classes represent the structure of the data being exchanged between the client and the server.
156+
157+
* **`Operations`**: These files defines the service interface used for API operations.
158+
159+
**Node.js/express example:**
160+
161+
```
162+
node/
163+
┗ tsp-output/
164+
┗ @typespec/
165+
┃ ┗ http-server-javascript/
166+
┃ ┃ ┣ helpers/ # Contains helper functions
167+
┃ ┃ ┃ ┃ ┣ header.ts # Helper for header operations
168+
┃ ┃ ┃ ┃ ┣ multipart.ts # Helper for multipart form data
169+
┃ ┃ ┃ ┃ ┗ router.ts # Helper for routing
170+
┃ ┃ ┣ http/ # Contains http request related code
171+
┃ ┃ ┃ ┃ ┗ router.ts # Helper for setting up http router
172+
┃ ┃ ┗ models/ # Contains generated data models
173+
┃ ┃ ┃ ┣ all/ # Contains helper import all the data models
174+
┃ ┃ ┃ ┃ ┃ ┗ getitdone/ # Folder containing data models generated from getitdone namespace
175+
┃ ┃ ┃ ┃ ┃ ┗ index.ts # Helper to export the data models
176+
┃ ┃ ┃ ┗ synthetic.ts # Type spec synthetic code
177+
```
178+
179+
* **`Helpers`**: This folder contains helper functions to perform common operations such as setting header, and multipart operations.
180+
181+
* **`Http`**: This folder contains code for setting up the http requests.
182+
183+
* **`Models`**: This folder contains code and helper functions for all data models.
184+
185+
## Cli: setting up the project and adding necessary code:
186+
187+
Now that you have the base controller, models and service interface generated, the next step is to implement the code with a service scaffolding and business logic for a runnable server. Please follow the instruction below:
188+
189+
* **ASP.NET webapi example (C#):**
190+
191+
1. Create a new ASP.NET Core Web API project:
192+
193+
```bash
194+
cd servers/aspnet
195+
dotnet new webapi
196+
dotnet add package Swashbuckle.AspNetCore
197+
```
198+
199+
2. Replace content of `Program.cs` with code below:
200+
201+
```csharp
202+
var builder = WebApplication.CreateBuilder(args);
203+
204+
builder.Services.AddControllers();
205+
builder.Services.AddEndpointsApiExplorer();
206+
builder.Services.AddSwaggerGen();
207+
208+
var app = builder.Build();
209+
210+
// Configure the HTTP request pipeline.
211+
if (app.Environment.IsDevelopment())
212+
{
213+
app.UseSwagger();
214+
app.UseSwaggerUI();
215+
}
216+
217+
app.UseAuthorization();
218+
app.MapControllers();
219+
220+
app.Run();
221+
```
222+
223+
3. **Additional scaffolding command (ASP.NET only)**. Note that you'll have to go up one level to execute the scaffolding command.
224+
225+
```bash
226+
cd ..
227+
npx hscs scaffold ./generated/ . --use-swaggerui
228+
```
229+
230+
The scaffold command will set up dependency injection for the controllers and interfaces, and also generates a swagger ui for the project.
231+
232+
4. The controllers and the models that were created are just service interfaces, so you'll need to add your business logic code here. Follow the examples below:
233+
234+
```csharp
235+
using Microsoft.AspNetCore.Mvc;
236+
using server.Models;
237+
using server.Operations;
238+
using System.ComponentModel.DataAnnotations;
239+
240+
namespace server.Controllers
241+
{
242+
[ApiController]
243+
public class CommentOpsOperationsController : CommentOpsOperationsControllerBase
244+
{
245+
private static List<Comment> _comments = new List<Comment>();
246+
247+
/// <inheritdoc />
248+
public override Task<IActionResult> CreateComment([Required] string project, [Required] string todoItem, [Required] CreateCommentRequest body)
249+
{
250+
var newComment = new Comment()
251+
{
252+
Id = Guid.NewGuid().ToString(),
253+
ProjectId = project,
254+
TodoItemId = todoItem,
255+
Body = body.Body,
256+
Created = DateTime.Now
257+
};
258+
_comments.Add(newComment);
259+
return Task.FromResult<IActionResult>(CreatedAtAction(nameof(GetComment), new { id = newComment.Id }, newComment));
260+
}
261+
262+
/// <inheritdoc />
263+
public override Task<IActionResult> GetComment(string id)
264+
{
265+
var comment = _comments.FirstOrDefault(c => c.Id == id);
266+
if (comment == null)
267+
{
268+
return Task.FromResult<IActionResult>(NotFound());
269+
}
270+
271+
return Task.FromResult<IActionResult>(Ok(comment));
272+
}
273+
}
274+
}
275+
```
276+
277+
**Important**: if your controller file is not automatically generated as `CommentOpsOperationsController.cs`, you will have to manually add in `[ApiController]` and inherit the base class `CommentOpsOperationsControllerBase`.
278+
279+
* **Node.js/express example:**
280+
281+
[Placeholder: Detailed instructions on setting up a Node.js/Express project, integrating the generated code, and running the server will be added here.]
282+
283+
1. **Create a basic express app:** Use the Express generator to create a new project:
284+
285+
```bash
286+
npm install -g express-generator
287+
express my-express-app
288+
cd my-express-app
289+
npm install
290+
```
291+
292+
2. **Install additional dependencies:** You may need additional dependencies depending on your API requirements (e.g., `body-parser` for parsing request bodies).
293+
294+
```bash
295+
npm install body-parser --save
296+
```
297+
298+
3. **Integrate generated code:** Copy the contents of the `servers/node/tsp-output/@typespec/http-server-javascript` directory into your Express project. You will likely need to adapt the generated code to fit the Express routing and middleware structure.
299+
300+
4. **Configure routes:** Define your API routes in your Express app, mapping them to the generated controller functions.
301+
302+
5. **Run the server:** Start the Express server:
303+
304+
```bash
305+
npm start
306+
```
307+
308+
## Cli: running the project and adding necessary code:
309+
310+
Now that you have the base controller, models and service interface generated, the next step is to implement the code with a service scaffolding and business logic for a runnable server. Please follow the instruction below:
311+
312+
1. **ASP.NET webapi server (C#):**
313+
314+
1. Navigate to the server directory:
315+
316+
```bash
317+
cd servers/aspnet
318+
```
319+
320+
2. Run the server:
321+
322+
```bash
323+
dotnet run
324+
```
325+
326+
3. Open your browser and navigate to `http://localhost:[PORT#]/swagger/index.html` (replace `[PORT#]` with the actual port number shown in the console output). You should see the Swagger UI, allowing you to test your API endpoints.
327+
328+
## Using the vscode extension
329+
330+
The TypeSpec Extension for VSCode offers a convenient way to generate server stubs directly from your IDE.
331+
332+
1. **Install the extension:** Search for "TypeSpec" in the VSCode Extensions Marketplace and install the official TypeSpec extension.
333+
334+
2. **Create a TypeSpec project:**
335+
* Click “Create TypeSpec Project” in the EXPLORE sidebar.
336+
* `[Placeholder: Screenshot showing "Create TypeSpec Project" in the VSCode Explorer sidebar]`
337+
* Select a project root folder.
338+
* Provide the required inputs via Quick Picks, similar to using `tsp init` on the command line.
339+
340+
3. **Define your api:** Write your API specification in a `.tsp` file.
341+
342+
4. **Generate the server stub:**
343+
* Right-click on a `.tsp` file to open the context menu.
344+
* Select “Generate from TypeSpec”.
345+
* `[Placeholder: Screenshot showing the "Generate from TypeSpec" option in the context menu]`
346+
* Select "Server Stub" from the Emitter Types.
347+
* `[Placeholder: Screenshot showing the "Emitter Types" Quick Pick with "Server Stub" selected]`
348+
* Choose the desired target language (e.g., ".NET – Generate .Net server stub by @typespec/http-server-csharp").
349+
* `[Placeholder: Screenshot showing the language selection Quick Pick]`
350+
* TypeSpec compiler will run in the background, generating a new directory under "servers\<language>".
351+
352+
* `[Placeholder: Screenshot showing the generated server directory structure in VSCode]`
353+
354+
## Next steps
355+
356+
* **Add business logic:** Implement the core logic for your API endpoints within the generated server stub. **Remember that the generated controllers are base classes; you will need to create concrete classes that inherit from them and implement your business logic.**
357+
* **Configure routes:** Verify and configure the routes defined in your server project. You may need to adjust the routing configuration to match your TypeSpec definitions.
358+
* **Add data persistence:** Integrate your server with a database or other data storage solution.
359+
* **Implement authentication and authorization:** Secure your API by adding appropriate authentication and authorization mechanisms.
360+
361+
## Getting help
362+
363+
If you encounter any issues or have questions about TypeSpec and server stub generation, please consult the following resources:
364+
365+
**TypeSpec documentation:**
366+
367+
[Official TypeSpec documentation](https://typespec.io/docs/)
368+
369+
**TypeSpec community:**
370+
371+
[Join our Discord discussion](https://aka.ms/typespec/discord/)
372+
373+
**GitHub issues:**
374+
375+
[Report bugs and suggest features on the TypeSpec GitHub repository](https://github.com/microsoft/typespec/issues)

0 commit comments

Comments
 (0)