@devlearning/swagger-generator v1.0.12
Swagger Generator for Angular & Next.js
This tool automates the generation of API clients for Angular and Next.js using a Swagger (OpenAPI) specification. It creates TypeScript models and service classes, making API integration seamless and type-safe.
Features
- 🚀 Automatic Model Generation – Converts Swagger schemas into TypeScript interfaces or classes.
- 🔥 API Client Generation – Creates service methods for making API calls with authentication, headers, and request parameters.
- 🎯 Framework-Specific Output:
- Angular – Generates injectable services using
HttpClient. - Next.js – Provides fetch-based or Axios-based API functions, optimized for both server-side and client-side usage.
- Angular – Generates injectable services using
- ✅ Strong Typing – Ensures type safety for API requests and responses.
- ⚡ Customization – Configurable options for method naming, error handling, and request structure.
- 🔄 Auto-Sync with Backend – Keeps API clients up-to-date with backend changes.
Installation
npm i @devlearning/swagger-generator --save-devadd npm script:
"swgen": "swgen http://localhost:7550/swagger/ApiGateway/swagger.json src/app/core/autogenerated angular moment"
params:
- url of swagger.json: not https
- output path for autogenerated files: src/app/core/autogenerated
- target framework/library: angular/next
- type of date management:
- angular only support momentjs, sorry :(
- nextjs only support date-fns
create output path like this: src/app/core/autogenerated
Angular configuration
create ApiService like this
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ApiAutogeneratedService } from '../autogenerated/api.autogenerated';
import { environment } from 'src/environments/environment';
import { ResponseError } from '../models/response-error';
import { throwError } from 'rxjs';
import * as moment from 'moment-timezone';
@Injectable({
providedIn: 'root',
})
export class ApiService extends ApiAutogeneratedService {
private _dateTimeFormat = /^((19|20)[0-9][0-9])[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])[T]([01]?[0-9]|[2][0-3])[:]([0-5][0-9])[:]([0-5][0-9])[.]([0-9][0-9][0-9])([+|-]([01][0-9]|[2][0-3])[:]([0-5][0-9])){0,1}$/;
private _timeFormat = /^([01]?[0-9]|[2][0-3])[:]([0-5][0-9])[:]([0-5][0-9])[.]([0-9][0-9][0-9])$/;
private _ianaName: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
private _dateTimeFormatString = "YYYY-MM-DDTHH:mm:ss.SSSZ";
private _timeFormatString = "HH:mm:ss.SSS";
public get ianaName() { return this._ianaName; }
constructor(
public override _http: HttpClient,
) {
super(_http, environment.BASE_URL);
}
protected override _momentToString(moment: moment.Moment) {
return (<moment.Moment>moment).format(this._dateTimeFormatString);
}
protected override _handleRequest<T>(request: T) {
if (request === null || request === undefined) {
return request;
}
if (typeof request !== 'object') {
return request;
}
var clonedRequest = { ...request };
for (const key of Object.keys(clonedRequest)) {
const value = (<any>clonedRequest)[key];
if (moment.isMoment(value)) {
(<any>clonedRequest)[key] = this._momentToString(value);
} else if (typeof value === 'object') {
this._handleRequest(value);
}
}
return clonedRequest;
}
protected override _handleMultipart<T>(request: T): FormData {
const formData = new FormData();
if (request === null || request === undefined) {
return formData;
}
for (const key of Object.keys(request)) {
const value = (<any>request)[key];
if (value instanceof File) {
formData.append(key, value, value.name);
} else {
formData.append(key, value.toString());
}
}
return formData;
}
public override _handleResponse<T>(response: T) {
if (response === null || response === undefined) {
return response;
}
if (typeof response !== 'object') {
return response;
}
for (const key of Object.keys(response)) {
const value = (<any>response)[key];
if (this._isDateString(value)) {
(<any>response)[key] = moment.tz(value, this._dateTimeFormatString, this._ianaName);
} else if (this._isTimeString(value)) {
(<any>response)[key] = moment.tz(value, this._timeFormatString, this._ianaName);
} else if (typeof value === 'object') {
this._handleResponse(value);
}
}
return response;
}
protected override _handleError(error: any, obs: any) {
let responseError = new ResponseError();
if (error.error instanceof Error) {
console.error('Api - an error occurred:', error.error.message);
responseError.message = error.error.message;
} else if (error instanceof HttpErrorResponse) {
responseError = ResponseError.CreateFromHttpErrorResponse(error);
}
console.error(`Api - error code ${error.status} message ${responseError.message} ${responseError.stacktrace}`);
return throwError(() => responseError);
}
private _isDateString(value: string) {
if (value === null || value === undefined) {
return false;
}
if (typeof value === 'string') {
return this._dateTimeFormat.test(value);
}
return false;
}
private _isTimeString(value: string) {
if (value === null || value === undefined) {
return false;
}
if (typeof value === 'string') {
return this._timeFormat.test(value);
}
return false;
}
}import { HttpErrorResponse } from '@angular/common/http';
export class ResponseError {
public url: string | null;
public status: number | null;
public message: string | null;
public stacktrace: string | null;
constructor() {
this.url = null;
this.status = null;
this.message = null;
this.stacktrace = null;
}
static CreateFromHttpErrorResponse(httpErrorResponse: HttpErrorResponse) {
let responseError = new ResponseError();
if (httpErrorResponse.error != null && !(httpErrorResponse.error instanceof ProgressEvent)) {
if (httpErrorResponse.error.hasOwnProperty('message')) {
responseError.message = httpErrorResponse.error.message;
}
if (httpErrorResponse.error.hasOwnProperty('stacktrace')) {
responseError.stacktrace = httpErrorResponse.error.stacktrace;
}
} else {
responseError.message = httpErrorResponse.message;
}
responseError.status = httpErrorResponse.status;
responseError.url = httpErrorResponse.url;
return responseError;
}
}9 months ago
9 months ago
9 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
8 months ago
8 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago