boeschenstein / angular9-dotnetcore-openapi-swagger

Add Swager/OpenApi to your ASP.NET Core 3.1 WebApi. Generate Proxy classes for Angular 9.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Auto-Generate Angular 9 services (Proxy classes) for accessing .NET Core 3.1 Backend

Goal

We want to generate TypeScript service classes for Angular 9 frontend to simplify backend access (aka Proxy classes). To achieve this, we have to add OpenApi (Swagger/Swashbuckle) to your .NET Core backend.

Install Swagger/OpenApi in new WebAPI Project

Create new .NET WebAPI project

Use your own .NET Core 3.1 WebApi backend.

Alternatively you can clone my sample from here: https://github.com/boeschenstein/angular9-dotnetcore3

If you are new to web development: download the code, open cmd in the folder \frontend and enter "npm i" to install the node modules.

Add Swashbuckle to your .NET Core backend

Open project in Visual Studio. Open Package Manager Console (Tools -> Nuget Package Manager -> Package Manager Console).

Install Swashbuckle:

Install-Package Swashbuckle.AspNetCore

Configure Swagger/OpenApi

Configure Swagger in Startup.cs

using Microsoft.OpenApi.Models;

Register swagger generator (simple):

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddControllers(); // already there

    // Register the Swagger generator, defining 1 or more Swagger documents
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    });
}
Optional: extended version with more details
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "A simple example ASP.NET Core Web API",
        TermsOfService = new Uri("https://boeschenstein.net/terms"),
        Contact = new OpenApiContact
        {
            Name = "Patrik Böschenstein",
            Email = string.Empty,
            Url = new Uri("https://twitter.com/patrikbo"),
        },
        License = new OpenApiLicense
        {
            Name = "Use under LICX",
            Url = new Uri("https://boeschenstein.net/license"),
        }
    });
});

Activate swagger

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
Complete code of Configure(). I suggest use Swagger in development mode only
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();

        // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
        // specifying the Swagger JSON endpoint.
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
    }

    app.UseHttpsRedirection();

    app.UseRouting();
    // activate cors here: app.UseCors(...): see https://github.com/boeschenstein/angular9-dotnetcore3#fix-cors-error

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Start the backend application Open swagger endpoint of your backend (you may have a different port)

https://localhost:5001/swagger

Check the swagger document and API

Your swagger endpoint should look like this. Please note that your WebApi endpoints have been discovered and presented in the GUI:

swagger endpoint

Execute your endpoints in Swagger: In my case, try WeatherForecast api: "Get", "Try it out", "Execute": You should see the data from the API.

Improve documentation (xml comments)

https://www.dotnetnakama.com/blog/enriched-web-api-documentation-using-swagger-openapi-in-asp-dotnet-core/

Add OpenApi to Angular 9

Install OpenApi Generator

Add the OpenApi generator to your project:

npm install @openapitools/openapi-generator-cli --save-dev

If you don't have it yet, install Java for openapi-generator: https://java.com/download/

OpenApi Generator

Some information before we generate the code

  • According my \backend\Properties\launchSettings.json, the endpoint is available by https and http. To avoid issues with https, I decide to use http for generating the ts files
...
"MyBackend": {
    "commandName": "Project",
    "launchBrowser": true,
    "launchUrl": "weatherforecast",
    "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
    },
    "applicationUrl": "https://localhost:5001;http://localhost:5000"
}
...
  • I decided to create the source code here in this frontend folder: frontend\src\app\core\backend\
  • npx is a tool to start applications from \nodes_module folder. It is needed, because the generator is installed locally. This is preferred almost for all tools. In this way, you can have different versions of the tools in different applications.
rem Start the backend to read all information out of it. Then start the OpenApi generator:

npx openapi-generator generate -g typescript-angular -i http://localhost:5000/swagger/v1/swagger.json -o src\app\core\backend

Tweak the generator config

The generator is generating the source code and also the configuration to create a node module (this is another approach: see links). To avoid this additional files, edit this file: frontend\src\app\core\backend\api\.openapi-generator-ignore

Any npm related files are Unix file types (LF line feeds instead of Windows CRLF). You have to use notepad++ or VS Code to edit it (older notepad versions might make such files unusable)

Tweak the file by adding the following at the lower end of the file: (.openapi-generator cannot be suppressed here)

*.sh
*.md
.gitignore

Now delete all other files (beside frontend\src\app\core\backend\api\.openapi-generator-ignore) and run the generator again.

If you are using my project template, you'll get the following folder structure in \frontend\src\app\core\backend\:

|-- .openapi-generator
    |-- VERSION
|-- api
    |-- api.ts
    |-- weatherForecast.service.ts
|-- model
    |-- models.ts
    |-- weatherForecast.ts
|-- .openapi-generator-ignore
|-- api.module.ts
|-- configuration.ts
|-- index.ts
|-- encoder.ts
|-- README.md
|-- variables.ts

Create new npm command

Edit frontend\package.json in VS Code. Add the following line to the "scripts" section (use unix style folder separator / or duplicate \ to escape it in json):

"gen-api": "npx openapi-generator generate -g typescript-angular -i http://localhost:5000/swagger/v1/swagger.json -o src/app/core/backend"

From now on, you can easily regenerate your code in cmd, whenever your WebApi (backend) did change:

REM open cmd or VS Code Terminal in `\frontend` and start this:

npm run gen-api

That's pretty neat I think.

VS Code

On this picture you see

  • How the new Script line looks like
  • I'm using the terminal within VS Code (press Shift Control ¨ to open it)

Use the new Services

If you are using my template, you change the existing call of the backend (WebApi):

// old version
constructor(http: HttpClient) {
  http.get<any[]>('https://localhost:5001/weatherforecast').subscribe(result => {
    console.warn("weatherforecast", result);
  }, error => console.error(error));
}

To make use of the new/generated service:

// new version
import { WeatherForecastService } from './core/backend';
...
constructor(service: WeatherForecastService) {
  service.weatherForecastGet().subscribe(result => {
    console.warn('weatherforecast', result);
  }, error => console.error(error));
}
See the complete code of AppComponent (app.component.ts) here
import { Component } from '@angular/core';
import { WeatherForecastService } from './core/backend';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'MyFrontend';
  constructor(service: WeatherForecastService) {
    service.weatherForecastGet().subscribe(result => {
      console.warn('weatherforecast', result);
    }, error => console.error(error));
  }
}

If you hover over the result variable, you'll realize that this is actually strictly typed "WeatherForecast[]"!

Before we can actually test the new service, we have to configure the URL.

Add API_BASE_PATH to your your src/environments/*.ts:

export const environment = {
  production: false,
  API_BASE_PATH: 'https://localhost:5001'
};

In the src/app/app.module.ts, add the following imports and providers:

import { BASE_PATH } from '';
import { environment } from '../environments/environment';

providers: [{ provide: BASE_PATH, useValue: environment.API_BASE_PATH }],
See the complete code of AppModule (app.module.ts) here
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { BASE_PATH } from './core/backend';
import { environment } from 'src/environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [{ provide: BASE_PATH, useValue: environment.API_BASE_PATH }],
  bootstrap: [AppComponent]
})
export class AppModule { }

Check the application

  1. Start your new Backend
  2. Start your new Frontend (ng serve -o int the folder \frontend)
  3. Check Console Output: you should see an array of data:

Success :)

If you can see the array, you just created your first business application in Angular 9 and .NET core 3.1 and access backend WebApi using Swagger Generator. Congratulations! Please let me know on twitter @patrikbo @patrikbo. Thank you!

Enums

Send Enums as strings (not id's) to the client (ASP.NET Core 7, "ng-openapi-gen": "^0.24.0")

ng-openapi-gen now supports x-enumNames: Details: cyclosproject/ng-openapi-gen#40

builder.Services
    .AddControllers()
    .AddJsonOptions(options =>
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); // convert enums to strings for openapi generator

What's next

  • Logging in .NET Core 3.1:
  • EF Core (todo)
  • Identity (todo)
  • Authorization (todo)
  • Authentication (todo)
  • Frontend Tooling (todo)
  • Backend Tooling (todo)

Additional Information

Links

OpenAPI flavors

There are 2 version of OpenApi/Swagger generators available.

Fork explained

OpenApi by Community

In this blog, I'm using this community driven solution.

SmartBear Swagger

Alternative approaches

Current Versions

  • Visual Studio 2019 16.5.3
  • .NET core 3.1
  • npm 6.14.4
  • node 12.16.1
  • Angular CLI 9.1
  • SwashBuckle 5.3.1

About

Add Swager/OpenApi to your ASP.NET Core 3.1 WebApi. Generate Proxy classes for Angular 9.


Languages

Language:HTML 48.2%Language:TypeScript 36.4%Language:C# 11.9%Language:JavaScript 3.4%Language:SCSS 0.1%