# Generate TypeScript Client from dotnet API
https://blog.logrocket.com/generate-typescript-csharp-clients-nswag-api/
## Introdution
To generate a TypeScript client or a C# client from a dotnet API using NSwag, we will build five projects to demo.
1. The `api` project will implement an endpoint that provides a `User.get()` restful API and a `swagger` HTML page.
2. The `api_generator` project will generate the TypeScript/C# client code.
3. The `client` project will create a `Vite-React` client project which will demo `multiple fetching function`.
4. The `client-console` project will create a dotnet console app which using `C# client code` generated by `api-generator` to fetch endpoint.
the final folder structure will be like :
```
.
├── README.md
├── api
│ ├── Controllers
│ ├── Models
│ ├── Program.cs
│ ├── Properties
│ ├── WeatherForecast.cs
│ ├── api.csproj
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── bin
│ └── obj
├── api_generator
│ ├── Program.cs
│ ├── api_generator.csproj
│ ├── api_generator.sln
│ ├── bin
│ └── obj
├── client
│ ├── dist
│ ├── index.html
│ ├── node_modules
│ ├── package.json
│ ├── public
│ ├── src
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ ├── vite.config.ts
│ └── yarn.lock
├── client-console
│ ├── Program.cs
│ ├── bin
│ ├── client-console.csproj
│ ├── clients.cs
│ └── obj
├── node-ts
│ ├── node_modules
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── tsconfig.json
│ └── yarn.lock
├── package.json
└── yarn.lock
```
## Step 1 : Setup folder structure
```bash
mkdir api
mkdir api_generator
mkdir client
mkdir client-console
mkdir node-ts
```
## Step 2 : Create API end point project
```bash
cd api
dotnet new webapi -o .
dotnet remove package Swashbuckle.AspNetCore
dotnet add package NSwag.AspNetCore
dotnet add package Microsoft.AspNetCore.Cors
dotnet new gitignore
```
Then create a folder witch named `Models` and create `UserModle.cs` in this folder
```C#
namespace api.Models;
public class UserModel
{
public string Name { get; set; }
public string? Email { get; set; }
}
```
Let create `UserController` in Controllers folder
you can see the source code that has a `[HttpGet(Name = "GetUser")]` function which providing a api to get the UserModels.
```C#
using System.Net.NetworkInformation;
using System.Runtime.InteropServices.ComTypes;
using System.IO;
using api.Models;
using Microsoft.AspNetCore.Mvc;
namespace api.Controllers;
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private List<UserModel> userList = new List<UserModel>(){
new UserModel(){
Name = "Adem",
Email= "adem@pic.net"
},
new UserModel(){
Name="Ted",
Email = "ted@pic.net"
}
}
;
private readonly ILogger<UserController> _logger;
public UserController(ILogger<UserController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetUser")]
public IEnumerable<UserModel> Get()
{
return userList;
// yield return new UserModel() { Name = "Adem" };
}
}
```
and the most important things is changing some code in `Program.cs`
1. change `builder.Services.AddSwaggerGen();` to `builder.Services.AddSwaggerDocument();`
2. change ` app.UseSwagger();` and `app.UseSwaggerUi();` to `app.UseOpenApi();`,`app.UseSwaggerUi3();`
```C#
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
// app.UseSwagger();
// app.UseSwaggerUi();
app.UseDeveloperExceptionPage();
// Register the Swagger generator and the Swagger UI middlewares
app.UseOpenApi();
app.UseSwaggerUi3();
}
```
3. Add Cors
```C#
const string ALLOW_DEVELOPMENT_CORS_ORIGINS_POLICY = "AllowDevelopmentSpecificOrigins";
const string LOCAL_DEVELOPMENT_URL = "http://127.0.0.1:5173"; //your client url
builder.Services.AddCors(options =>
{
options.AddPolicy(name: ALLOW_DEVELOPMENT_CORS_ORIGINS_POLICY,
policy =>
{
policy.WithOrigins(LOCAL_DEVELOPMENT_URL)
.AllowAnyHeader()
.AllowAnyMethod()
;
});
});
//.....
app.UseCors(ALLOW_DEVELOPMENT_CORS_ORIGINS_POLICY);
```
Let's run the project
```bash
ASPNETCORE_URLS=http://*:5001 ASPNETCORE_ENVIRONMENT=Development dotnet watch --project . run --no-launch-profile
```
and you can open `http://localhost:5001/swagger/index.html` in the browser which show swagger page.
Do not stop this project, we will use that url in api-generator.
## Step 3 : Create API-GENERATOR project
move to the root folder and jump into api_generator folder
```bash
cd ..
cd api_generator
dotnet new console -o .
dotnet add package NSwag.CodeGeneration.CSharp
dotnet add package NSwag.CodeGeneration.TypeScript
dotnet add package NSwag.Core
dotnet new gitignore
```
## Step 4 : Create Client Vite-React
using Vite to create react client project
https://vitejs.dev/guide/
```
cd client
yarn create vite . --template react-ts
```
## Step 5 : Client dotnet console App
```
mkdir client-console
cd client-console
dotnet new console -o .
dotnet add package Newtonsoft.Json
dotnet new gitignore
```
## Step 6 : Add `package.json` and add some `script` in root folder
## Generator Project
```
mkdir api_generator
cd api_generator
dotnet new console -o .
dotnet add package NSwag.CodeGeneration.CSharp
dotnet add package NSwag.CodeGeneration.TypeScript
dotnet add package NSwag.Core
```
change `Program.cs`
```
// See https://aka.ms/new-console-template for more information
using System;
using System.IO;
using System.Threading.Tasks;
using NJsonSchema.CodeGeneration.TypeScript;
using NSwag;
using NSwag.CodeGeneration.CSharp;
using NSwag.CodeGeneration.TypeScript;
if (args.Length != 3) throw new ArgumentException("Expecting 4 arguments: URL, generatePath, language");
var url = args[0];
var generatePath = args[1];
var language = args[2];
if (language != "TypeScript" && language != "CSharp") throw new AbandonedMutexException("Invalid language parameter; valid values are TypeScript and CSharp");
var document = await OpenApiDocument.FromUrlAsync(url);
Console.WriteLine($"Generating {generatePath}...");
await System.IO.File.WriteAllTextAsync(generatePath, language switch
{
"TypeScript" => GenerateTypeScriptClient(document),
"CSharp" => GenerateCSharpClient(document),
_ => throw new AbandonedMutexException("Invalid language parameter; valid values are TypeScript and CSharp")
});
static string GenerateTypeScriptClient(OpenApiDocument document)
{
var settings = new TypeScriptClientGeneratorSettings
{
TypeScriptGeneratorSettings =
{
TypeStyle = TypeScriptTypeStyle.Interface,
TypeScriptVersion = 3.5M,
DateTimeType = TypeScriptDateTimeType.String
}
};
var generator = new TypeScriptClientGenerator(document, settings);
return generator.GenerateFile();
}
static string GenerateCSharpClient(OpenApiDocument document)
{
var settings = new CSharpClientGeneratorSettings { UseBaseUrl = false };
var generator = new CSharpClientGenerator(document, settings);
return generator.GenerateFile();
}
```
run console app
- Generate TypeScript:
```
dotnet run --project . http://localhost:5001/swagger/v1/swagger.json ../client/clients.ts TypeScript
```
- Generate CShrap
```
dotnet run --project . http://localhost:5001/swagger/v1/swagger.json ../client-console/clients.cs CSharp
```
* Note: if got some errors `error CS0103: The name 'TypeScriptTypeStyle' does not exist in the current context `, please make sure you are using `NJsonSchema.CodeGeneration.TypeScript` in Program.cs
### Install Global Package
```
npm install -g npm-run-all
```