Codegen REST API types and requests for Angular

Automatic code generation from OpenAPI 3 for Angular

Authors
Marc Stammerjohann Marc Stammerjohann
Published at

Are you using a REST API in your Angular app to fetch data from a server? Are you manually adding model types, specifying each REST call with HttpClient? Stop right there!

Use ng-openapi-gen for a hassle free and automatic generation of models and services based on your OpenAPI 3 specification.

Nx monorepo

Setup a monorepo using nx with Angular and NestJS.

npx create-nx-workspace --preset angular-nest

Open package.json and replace the start script with:

"start": "nx run-many --target=serve",

This will start both your Angular and NestJS app in serve mode.

npm run start

Angular will be exposed on localhost:4200 and Nest on localhost:3333.

Setup Swagger

Setup Swagger in NestJS for type-safe REST endpoints.

First, install the Nest swagger library.

npm install --save @nestjs/swagger

Configure Swagger in your main.ts file:

/**
 * This is not a production server yet!
 * This is only a minimal backend to get started.
 */

import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

import { AppModule } from './app/app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const globalPrefix = 'api';
  app.setGlobalPrefix(globalPrefix);

  // setup swagger
  const config = new DocumentBuilder()
    .setTitle('Angular NestJS Codegen')
    .setDescription('Base for codegen for Angular app')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);

  // enable cors for Angular
  app.enableCors();

  const port = process.env.PORT || 3333;
  await app.listen(port);
  Logger.log(
    `🚀 Application is running on: http://localhost:${port}/${globalPrefix}`
  );
}

bootstrap();

Visit localhost:3333/api to see the Swagger UI.

While you are add it. Create a message.entity.ts class and annotate the attribute with @ApiProperty().

// entities/message.entity.ts
import { ApiProperty } from '@nestjs/swagger';

export class Message {
  @ApiProperty()
  message: string;
}

Use @ApiResponse({ type: Message }) to inform Swagger about the response type.

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ApiResponse } from '@nestjs/swagger';

import { AppService } from './app.service';
import { Message } from './entities/message.entity';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('hello')
  @ApiResponse({ type: Message })
  getData(): Message {
    return this.appService.getData();
  }
}

Configure Codegen

Next, you will configure ng-openapi-gen as the OpenAPI 3 code generator for Angular.

npm i -D ng-openapi-gen

Add a config file with the name ng-openapi-gen.json to the root folder. ng-openapi-gen loads the config file with this name automatically. Pass ng-openapi-gen --config your-config.json for an alternative config file name.

Copy the following config content into the file, will explain the configuration options next.

{
  "$schema": "node_modules/ng-openapi-gen/ng-openapi-gen-schema.json",
  "input": "http://localhost:3333/api-json",
  "output": "apps/app/src/api"
}

With $schema you get autocomplete in JSON for all possible configuration options of ng-openapi-gen.

The input requires a file or URL of a OpenAPI 3 specification. In your case the Swagger JSON is available at localhost:3333/api-json. You should see openapi as first value with version 3.0.0.

output is the directory for the generated files. The files are generated inside your Angular app. Change the directory if you choose a different app name (apps/your-name/src/api) or perhaps you want to generate into a shared library (libs/api/src/lib).

Last step, add a new script to your package.json let's call it "codegen": "ng-openapi-gen". Run the new script, also make sure the Nest app is serving.

npm run codegen

Your output directory (apps/your-name/src/api) now contains a couple of new files. Next, you will start with the configuration of the REST API endpoint.

Codegen CLI Output

Codegen file structure

Specify API url with ApiModule

Add ApiModule, import from apps/your-name/src/api/api.module.ts, to your Angular AppModule imports. Use forRoot(...) to specify the rootUrl pointing to localhost:3333 in development.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
import { HttpClientModule } from '@angular/common/http';

import { ApiModule } from '../api/api.module';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [AppComponent, NxWelcomeComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    ApiModule.forRoot({ rootUrl: environment.apiUrl }),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Because your API endpoint will be different in production you need to add the apiUrl to the environment(.prod).ts files.

// environments/environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3333',
};

// environments/environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.awesome-app', // update in production
};

First generated REST request

Lastly, you'll be making a REST request with the generated API. Look into the api/services directory. A service will be generated for each tag (e.g. @ApiTags('users')) in your Swagger API.

Use ApiService in AppComponent to replace the direct HttpClient call. Under the hood ApiService uses HttpClient.

import { Component } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { Message } from '@angular-nest-codegen/api-interfaces';
+import { ApiService } from '../api/services';

@Component({
  selector: 'angular-nest-codegen-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
+ hello$ = this.apiService.appControllerGetData();
- hello$ = this.http.get<Message>('/api/hello');
+ constructor(private apiService: ApiService) {}
- constructor(private http: HttpClient) {}
}

Perfect, you made it till the end. Keep in mind that the codegen is only as good as your Swagger documentation. If you are missing type information for the request or response, you're also missing out in codegen.

Checkout the following two posts as inspiration about type-safe endpoints with Nest.

Sponsor us

Did you find this post useful? We at notiz.dev write about our experiences developing Apps, Websites and APIs and develop Open Source tools. Your support would mean a lot to us 🙏. Receive a reward by sponsoring us on Patreon or start with a one-time donation on GitHub Sponsors.

Table of Contents

Top of Page Comments Related Articles

Related Posts

Find more posts like this one.

Authors
Marc Stammerjohann
July 27, 2022

Downloading files with NestJS

Setup type-safe endpoints for downloading files in your NestJS application.
NestJS Read More
Authors
Marc Stammerjohann
July 08, 2022

Maizzle: Craft beautiful HTML emails with Tailwind CSS

Send beautiful HTML emails via NestJS crafted with Maizzle and Tailwind CSS
Maizzle Tailwind CSS NestJS Read More
Authors
Gary Großgarten
September 23, 2021

Media Queries with RxJS

Media Queries | Practical examples with RxJS
RxJS Angular Read More
Authors
Marc Stammerjohann
August 26, 2021

NestJS: Type-safe File Uploads

Learn how to apply Swagger decorators for type-safe file upload endpoints.
NestJS Read More
Authors
Marc Stammerjohann
July 27, 2022

OpenAPI for your REST APIs in NestJS

Setup Swagger to generate an OpenAPI documentation for your REST endpoints.
NestJS Read More
Authors
Marc Stammerjohann
July 08, 2022

Send Emails with NestJS

Create Email Templates and send them with nodemailer from your Nest application
NestJS Read More
Authors
Marc Stammerjohann
December 15, 2020

Tailwind CSS Purge: Optimize Angular for Production

Remove unused Tailwind CSS utilities from your Angular production build for best performance
Tailwind CSS Angular Scully Read More
Authors
Marc Stammerjohann
November 09, 2020

Firebase Hosting: Preview and Deploy via GitHub Actions

Preview and Deploy your Angular or Scully app on Firebase Hosting automated via GitHub Actions
Firebase Angular GitHub Read More

Sign up for our newsletter

Sign up for our newsletter to stay up to date. Sent every other week.

We care about the protection of your data. Read our Privacy Policy.