Codegen REST API types and requests for Angular
Automatic code generation from OpenAPI 3 for Angular
- Authors
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.


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.