@devlearning/swagger-generator 1.1.8 โ 1.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-OLD.md +210 -0
- package/README.md +198 -185
- package/dist/generator.js +12 -28
- package/dist/generators-writers/angular/api-angular-writer.js +10 -1
- package/dist/generators-writers/dart/api-dart-writer.js +2 -5
- package/dist/generators-writers/dart/templates/api.mustache +35 -6
- package/dist/swagger-downloader.js +30 -3
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.js +63 -0
- package/dist/utils/swagger-validator.d.ts +19 -0
- package/dist/utils/swagger-validator.js +76 -0
- package/package.json +6 -4
- package/src/generator.ts +13 -32
- package/src/generators-writers/angular/api-angular-writer.ts +10 -1
- package/src/generators-writers/dart/api-dart-writer.ts +2 -6
- package/src/generators-writers/dart/templates/api.mustache +35 -6
- package/src/swagger-downloader.ts +38 -4
- package/src/utils/logger.ts +73 -0
- package/src/utils/swagger-validator.ts +89 -0
package/README-OLD.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Swagger Generator for Angular, Next.js and Flutter
|
|
2
|
+
|
|
3
|
+
This tool automates the generation of API clients for Angular, Next.js and Flutter using a Swagger (OpenAPI) specification. It creates TypeScript models and service classes, making API integration seamless and type-safe.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ๐ **Automatic Model Generation** โ Converts Swagger schemas into TypeScript interfaces or classes.
|
|
8
|
+
- ๐ฅ **API Client Generation** โ Creates service methods for making API calls with authentication, headers, and request parameters.
|
|
9
|
+
- ๐ฏ **Framework-Specific Output**:
|
|
10
|
+
- **Angular** โ Generates injectable services using `HttpClient`.
|
|
11
|
+
- **Next.js** โ Provides fetch-based or Axios-based API functions, optimized for both server-side and client-side usage.
|
|
12
|
+
- **Flutter** โ Provides Flutter with Dio API functions, optimized for both server-side and client-side usage.
|
|
13
|
+
- โ
**Strong Typing** โ Ensures type safety for API requests and responses.
|
|
14
|
+
- โก **Customization** โ Configurable options for method naming, error handling, and request structure.
|
|
15
|
+
- ๐ **Auto-Sync with Backend** โ Keeps API clients up-to-date with backend changes.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm i @devlearning/swagger-generator --save-dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
add npm script:
|
|
25
|
+
|
|
26
|
+
"swgen": "swgen http://localhost:7550/swagger/ApiGateway/swagger.json src/app/core/autogenerated angular moment"
|
|
27
|
+
|
|
28
|
+
params:
|
|
29
|
+
- url of swagger.json: not https
|
|
30
|
+
- output path for autogenerated files: src/app/core/autogenerated
|
|
31
|
+
- target framework/library: angular/next
|
|
32
|
+
- type of date management:
|
|
33
|
+
- angular only support momentjs, sorry :(
|
|
34
|
+
- nextjs only support date-fns
|
|
35
|
+
- dart native date management
|
|
36
|
+
|
|
37
|
+
create output path like this: src/app/core/autogenerated
|
|
38
|
+
|
|
39
|
+
## Angular configuration
|
|
40
|
+
|
|
41
|
+
create ApiService like this
|
|
42
|
+
```ts
|
|
43
|
+
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
44
|
+
import { Injectable } from '@angular/core';
|
|
45
|
+
import { ApiAutogeneratedService } from '../autogenerated/api.autogenerated';
|
|
46
|
+
import { environment } from 'src/environments/environment';
|
|
47
|
+
import { ResponseError } from '../models/response-error';
|
|
48
|
+
import { throwError } from 'rxjs';
|
|
49
|
+
import * as moment from 'moment-timezone';
|
|
50
|
+
|
|
51
|
+
@Injectable({
|
|
52
|
+
providedIn: 'root',
|
|
53
|
+
})
|
|
54
|
+
export class ApiService extends ApiAutogeneratedService {
|
|
55
|
+
|
|
56
|
+
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}$/;
|
|
57
|
+
private _timeFormat = /^([01]?[0-9]|[2][0-3])[:]([0-5][0-9])[:]([0-5][0-9])[.]([0-9][0-9][0-9])$/;
|
|
58
|
+
private _ianaName: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
59
|
+
private _dateTimeFormatString = "YYYY-MM-DDTHH:mm:ss.SSSZ";
|
|
60
|
+
private _timeFormatString = "HH:mm:ss.SSS";
|
|
61
|
+
|
|
62
|
+
public get ianaName() { return this._ianaName; }
|
|
63
|
+
|
|
64
|
+
constructor(
|
|
65
|
+
public override _http: HttpClient,
|
|
66
|
+
) {
|
|
67
|
+
super(_http, environment.BASE_URL);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected override _momentToString(moment: moment.Moment) {
|
|
71
|
+
return (<moment.Moment>moment).format(this._dateTimeFormatString);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected override _handleRequest<T>(request: T) {
|
|
75
|
+
if (request === null || request === undefined) {
|
|
76
|
+
return request;
|
|
77
|
+
}
|
|
78
|
+
if (typeof request !== 'object') {
|
|
79
|
+
return request;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var clonedRequest = { ...request };
|
|
83
|
+
|
|
84
|
+
for (const key of Object.keys(clonedRequest)) {
|
|
85
|
+
const value = (<any>clonedRequest)[key];
|
|
86
|
+
if (moment.isMoment(value)) {
|
|
87
|
+
(<any>clonedRequest)[key] = this._momentToString(value);
|
|
88
|
+
} else if (typeof value === 'object') {
|
|
89
|
+
this._handleRequest(value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return clonedRequest;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected override _handleMultipart<T>(request: T): FormData {
|
|
97
|
+
const formData = new FormData();
|
|
98
|
+
if (request === null || request === undefined) {
|
|
99
|
+
return formData;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const key of Object.keys(request)) {
|
|
103
|
+
const value = (<any>request)[key];
|
|
104
|
+
if (value instanceof File) {
|
|
105
|
+
formData.append(key, value, value.name);
|
|
106
|
+
} else {
|
|
107
|
+
formData.append(key, value.toString());
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return formData;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public override _handleResponse<T>(response: T) {
|
|
115
|
+
if (response === null || response === undefined) {
|
|
116
|
+
return response;
|
|
117
|
+
}
|
|
118
|
+
if (typeof response !== 'object') {
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const key of Object.keys(response)) {
|
|
123
|
+
const value = (<any>response)[key];
|
|
124
|
+
if (this._isDateString(value)) {
|
|
125
|
+
(<any>response)[key] = moment.tz(value, this._dateTimeFormatString, this._ianaName);
|
|
126
|
+
} else if (this._isTimeString(value)) {
|
|
127
|
+
(<any>response)[key] = moment.tz(value, this._timeFormatString, this._ianaName);
|
|
128
|
+
} else if (typeof value === 'object') {
|
|
129
|
+
this._handleResponse(value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return response;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
protected override _handleError(error: any, obs: any) {
|
|
137
|
+
let responseError = new ResponseError();
|
|
138
|
+
if (error.error instanceof Error) {
|
|
139
|
+
console.error('Api - an error occurred:', error.error.message);
|
|
140
|
+
responseError.message = error.error.message;
|
|
141
|
+
} else if (error instanceof HttpErrorResponse) {
|
|
142
|
+
responseError = ResponseError.CreateFromHttpErrorResponse(error);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.error(`Api - error code ${error.status} message ${responseError.message} ${responseError.stacktrace}`);
|
|
146
|
+
|
|
147
|
+
return throwError(() => responseError);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private _isDateString(value: string) {
|
|
151
|
+
if (value === null || value === undefined) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === 'string') {
|
|
155
|
+
return this._dateTimeFormat.test(value);
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private _isTimeString(value: string) {
|
|
161
|
+
if (value === null || value === undefined) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (typeof value === 'string') {
|
|
165
|
+
return this._timeFormat.test(value);
|
|
166
|
+
}
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
175
|
+
|
|
176
|
+
export class ResponseError {
|
|
177
|
+
public url: string | null;
|
|
178
|
+
public status: number | null;
|
|
179
|
+
public message: string | null;
|
|
180
|
+
public stacktrace: string | null;
|
|
181
|
+
|
|
182
|
+
constructor() {
|
|
183
|
+
this.url = null;
|
|
184
|
+
this.status = null;
|
|
185
|
+
this.message = null;
|
|
186
|
+
this.stacktrace = null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static CreateFromHttpErrorResponse(httpErrorResponse: HttpErrorResponse) {
|
|
190
|
+
let responseError = new ResponseError();
|
|
191
|
+
|
|
192
|
+
if (httpErrorResponse.error != null && !(httpErrorResponse.error instanceof ProgressEvent)) {
|
|
193
|
+
if (httpErrorResponse.error.hasOwnProperty('message')) {
|
|
194
|
+
responseError.message = httpErrorResponse.error.message;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (httpErrorResponse.error.hasOwnProperty('stacktrace')) {
|
|
198
|
+
responseError.stacktrace = httpErrorResponse.error.stacktrace;
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
responseError.message = httpErrorResponse.message;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
responseError.status = httpErrorResponse.status;
|
|
205
|
+
responseError.url = httpErrorResponse.url;
|
|
206
|
+
|
|
207
|
+
return responseError;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
package/README.md
CHANGED
|
@@ -1,210 +1,223 @@
|
|
|
1
|
-
# Swagger Generator
|
|
1
|
+
# Swagger API Generator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generatore automatico di client API e modelli per **Angular**, **Next.js** e **Flutter/Dart** da specifiche Swagger/OpenAPI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@devlearning/swagger-generator)
|
|
6
|
+
[](https://opensource.org/licenses/ISC)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- ๐ฅ **API Client Generation** โ Creates service methods for making API calls with authentication, headers, and request parameters.
|
|
9
|
-
- ๐ฏ **Framework-Specific Output**:
|
|
10
|
-
- **Angular** โ Generates injectable services using `HttpClient`.
|
|
11
|
-
- **Next.js** โ Provides fetch-based or Axios-based API functions, optimized for both server-side and client-side usage.
|
|
12
|
-
- **Flutter** โ Provides Flutter with Dio API functions, optimized for both server-side and client-side usage.
|
|
13
|
-
- โ
**Strong Typing** โ Ensures type safety for API requests and responses.
|
|
14
|
-
- โก **Customization** โ Configurable options for method naming, error handling, and request structure.
|
|
15
|
-
- ๐ **Auto-Sync with Backend** โ Keeps API clients up-to-date with backend changes.
|
|
8
|
+
## ๐ฏ Caratteristiche
|
|
16
9
|
|
|
17
|
-
|
|
10
|
+
- โ
**Generazione automatica** di modelli e API da Swagger JSON
|
|
11
|
+
- ๐จ **Multi-framework**: Angular, Next.js, Flutter/Dart
|
|
12
|
+
- ๐ **Type-safe**: Tipizzazione forte per TypeScript e Dart
|
|
13
|
+
- ๐ฆ **Zero dipendenze** nei file generati (configurabile)
|
|
14
|
+
- ๐ **CLI semplice** da usare
|
|
15
|
+
- ๐ **Validazione** del documento Swagger prima della generazione
|
|
16
|
+
- ๐ **Logging strutturato** per debugging
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
## ๐ฆ Installazione
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @devlearning/swagger-generator --save-dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## ๐ Utilizzo
|
|
25
|
+
|
|
26
|
+
### Da linea di comando
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx swgen --url <swagger-url> --output <output-dir> --target <angular|next|flutter> [opzioni]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Esempi
|
|
33
|
+
|
|
34
|
+
#### Angular
|
|
35
|
+
```bash
|
|
36
|
+
npx swgen \
|
|
37
|
+
--url http://localhost:5000/swagger/v1/swagger.json \
|
|
38
|
+
--output src/app/core/autogen \
|
|
39
|
+
--target angular \
|
|
40
|
+
--dateTimeLibrary moment
|
|
21
41
|
```
|
|
22
42
|
|
|
43
|
+
#### Next.js
|
|
44
|
+
```bash
|
|
45
|
+
npx swgen \
|
|
46
|
+
--url https://api.example.com/swagger.json \
|
|
47
|
+
--output src/lib/api \
|
|
48
|
+
--target next \
|
|
49
|
+
--dateTimeLibrary date-fns
|
|
50
|
+
```
|
|
23
51
|
|
|
24
|
-
|
|
52
|
+
#### Flutter/Dart
|
|
53
|
+
```bash
|
|
54
|
+
npx swgen \
|
|
55
|
+
--url http://localhost:5000/swagger/v1/swagger.json \
|
|
56
|
+
--output lib/core/api \
|
|
57
|
+
--target flutter \
|
|
58
|
+
--package my_app_name
|
|
59
|
+
```
|
|
25
60
|
|
|
26
|
-
|
|
61
|
+
### Opzioni
|
|
27
62
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- dart native date management
|
|
63
|
+
| Opzione | Alias | Descrizione | Obbligatorio | Default |
|
|
64
|
+
|---------|-------|-------------|--------------|---------|
|
|
65
|
+
| `--url` | `-u` | URL del file swagger.json | โ
| - |
|
|
66
|
+
| `--output` | `-o` | Directory di output | โ
| - |
|
|
67
|
+
| `--target` | `-t` | Framework target (`angular`, `next`, `flutter`) | โ
| - |
|
|
68
|
+
| `--dateTimeLibrary` | `-d` | Libreria date (`moment`, `date-fns`) | โ | `date-fns` |
|
|
69
|
+
| `--package` | `-p` | Nome package (solo Dart/Flutter) | โ | - |
|
|
36
70
|
|
|
37
|
-
|
|
71
|
+
## ๐ Struttura File Generati
|
|
38
72
|
|
|
39
|
-
|
|
73
|
+
### Angular
|
|
74
|
+
```
|
|
75
|
+
output/
|
|
76
|
+
โโโ models/
|
|
77
|
+
โ โโโ user.model.ts
|
|
78
|
+
โ โโโ product.model.ts
|
|
79
|
+
โ โโโ ...
|
|
80
|
+
โโโ api/
|
|
81
|
+
โโโ user.api.ts
|
|
82
|
+
โโโ product.api.ts
|
|
83
|
+
โโโ ...
|
|
84
|
+
```
|
|
40
85
|
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
86
|
+
### Next.js
|
|
87
|
+
```
|
|
88
|
+
output/
|
|
89
|
+
โโโ models/
|
|
90
|
+
โ โโโ user.ts
|
|
91
|
+
โ โโโ product.ts
|
|
92
|
+
โ โโโ ...
|
|
93
|
+
โโโ api/
|
|
94
|
+
โโโ user-api.ts
|
|
95
|
+
โโโ product-api.ts
|
|
96
|
+
โโโ ...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Flutter/Dart
|
|
100
|
+
```
|
|
101
|
+
lib/output/
|
|
102
|
+
โโโ user/
|
|
103
|
+
โ โโโ models/
|
|
104
|
+
โ โ โโโ user.dart
|
|
105
|
+
โ โโโ api/
|
|
106
|
+
โ โโโ user_api.dart
|
|
107
|
+
โโโ product/
|
|
108
|
+
โโโ models/
|
|
109
|
+
โ โโโ product.dart
|
|
110
|
+
โโโ api/
|
|
111
|
+
โโโ product_api.dart
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## ๐ง Integrazione nel Progetto
|
|
115
|
+
|
|
116
|
+
### Angular
|
|
117
|
+
|
|
118
|
+
1. Crea un service wrapper:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
44
121
|
import { Injectable } from '@angular/core';
|
|
45
|
-
import {
|
|
46
|
-
import { environment } from '
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
54
|
-
export class ApiService extends ApiAutogeneratedService {
|
|
55
|
-
|
|
56
|
-
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}$/;
|
|
57
|
-
private _timeFormat = /^([01]?[0-9]|[2][0-3])[:]([0-5][0-9])[:]([0-5][0-9])[.]([0-9][0-9][0-9])$/;
|
|
58
|
-
private _ianaName: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
59
|
-
private _dateTimeFormatString = "YYYY-MM-DDTHH:mm:ss.SSSZ";
|
|
60
|
-
private _timeFormatString = "HH:mm:ss.SSS";
|
|
61
|
-
|
|
62
|
-
public get ianaName() { return this._ianaName; }
|
|
63
|
-
|
|
64
|
-
constructor(
|
|
65
|
-
public override _http: HttpClient,
|
|
66
|
-
) {
|
|
67
|
-
super(_http, environment.BASE_URL);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
protected override _momentToString(moment: moment.Moment) {
|
|
71
|
-
return (<moment.Moment>moment).format(this._dateTimeFormatString);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
protected override _handleRequest<T>(request: T) {
|
|
75
|
-
if (request === null || request === undefined) {
|
|
76
|
-
return request;
|
|
77
|
-
}
|
|
78
|
-
if (typeof request !== 'object') {
|
|
79
|
-
return request;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
var clonedRequest = { ...request };
|
|
83
|
-
|
|
84
|
-
for (const key of Object.keys(clonedRequest)) {
|
|
85
|
-
const value = (<any>clonedRequest)[key];
|
|
86
|
-
if (moment.isMoment(value)) {
|
|
87
|
-
(<any>clonedRequest)[key] = this._momentToString(value);
|
|
88
|
-
} else if (typeof value === 'object') {
|
|
89
|
-
this._handleRequest(value);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return clonedRequest;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
protected override _handleMultipart<T>(request: T): FormData {
|
|
97
|
-
const formData = new FormData();
|
|
98
|
-
if (request === null || request === undefined) {
|
|
99
|
-
return formData;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (const key of Object.keys(request)) {
|
|
103
|
-
const value = (<any>request)[key];
|
|
104
|
-
if (value instanceof File) {
|
|
105
|
-
formData.append(key, value, value.name);
|
|
106
|
-
} else {
|
|
107
|
-
formData.append(key, value.toString());
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return formData;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
public override _handleResponse<T>(response: T) {
|
|
115
|
-
if (response === null || response === undefined) {
|
|
116
|
-
return response;
|
|
117
|
-
}
|
|
118
|
-
if (typeof response !== 'object') {
|
|
119
|
-
return response;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
for (const key of Object.keys(response)) {
|
|
123
|
-
const value = (<any>response)[key];
|
|
124
|
-
if (this._isDateString(value)) {
|
|
125
|
-
(<any>response)[key] = moment.tz(value, this._dateTimeFormatString, this._ianaName);
|
|
126
|
-
} else if (this._isTimeString(value)) {
|
|
127
|
-
(<any>response)[key] = moment.tz(value, this._timeFormatString, this._ianaName);
|
|
128
|
-
} else if (typeof value === 'object') {
|
|
129
|
-
this._handleResponse(value);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return response;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
protected override _handleError(error: any, obs: any) {
|
|
137
|
-
let responseError = new ResponseError();
|
|
138
|
-
if (error.error instanceof Error) {
|
|
139
|
-
console.error('Api - an error occurred:', error.error.message);
|
|
140
|
-
responseError.message = error.error.message;
|
|
141
|
-
} else if (error instanceof HttpErrorResponse) {
|
|
142
|
-
responseError = ResponseError.CreateFromHttpErrorResponse(error);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
console.error(`Api - error code ${error.status} message ${responseError.message} ${responseError.stacktrace}`);
|
|
146
|
-
|
|
147
|
-
return throwError(() => responseError);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private _isDateString(value: string) {
|
|
151
|
-
if (value === null || value === undefined) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
if (typeof value === 'string') {
|
|
155
|
-
return this._dateTimeFormat.test(value);
|
|
156
|
-
}
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private _isTimeString(value: string) {
|
|
161
|
-
if (value === null || value === undefined) {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
if (typeof value === 'string') {
|
|
165
|
-
return this._timeFormat.test(value);
|
|
166
|
-
}
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
122
|
+
import { HttpClient } from '@angular/common/http';
|
|
123
|
+
import { environment } from '@env/environment';
|
|
124
|
+
|
|
125
|
+
@Injectable({ providedIn: 'root' })
|
|
126
|
+
export class ApiService {
|
|
127
|
+
constructor(private http: HttpClient) {}
|
|
128
|
+
|
|
129
|
+
// I tuoi metodi personalizzati qui
|
|
169
130
|
}
|
|
170
131
|
```
|
|
171
132
|
|
|
133
|
+
2. Usa i modelli generati:
|
|
172
134
|
|
|
173
|
-
```
|
|
174
|
-
import {
|
|
135
|
+
```typescript
|
|
136
|
+
import { User } from './autogen/models/user.model';
|
|
137
|
+
import { UserApi } from './autogen/api/user.api';
|
|
138
|
+
```
|
|
175
139
|
|
|
176
|
-
|
|
177
|
-
public url: string | null;
|
|
178
|
-
public status: number | null;
|
|
179
|
-
public message: string | null;
|
|
180
|
-
public stacktrace: string | null;
|
|
140
|
+
### Next.js
|
|
181
141
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
this.message = null;
|
|
186
|
-
this.stacktrace = null;
|
|
187
|
-
}
|
|
142
|
+
```typescript
|
|
143
|
+
import { getUsers } from '@/lib/api/user-api';
|
|
144
|
+
import { User } from '@/lib/api/models/user';
|
|
188
145
|
|
|
189
|
-
|
|
190
|
-
|
|
146
|
+
export async function UsersPage() {
|
|
147
|
+
const users = await getUsers();
|
|
148
|
+
// ...
|
|
149
|
+
}
|
|
150
|
+
```
|
|
191
151
|
|
|
192
|
-
|
|
193
|
-
if (httpErrorResponse.error.hasOwnProperty('message')) {
|
|
194
|
-
responseError.message = httpErrorResponse.error.message;
|
|
195
|
-
}
|
|
152
|
+
### Flutter/Dart
|
|
196
153
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
} else {
|
|
201
|
-
responseError.message = httpErrorResponse.message;
|
|
202
|
-
}
|
|
154
|
+
```dart
|
|
155
|
+
import 'package:my_app/core/api/user/api/user_api.dart';
|
|
156
|
+
import 'package:my_app/core/api/user/models/user.dart';
|
|
203
157
|
|
|
204
|
-
|
|
205
|
-
|
|
158
|
+
final userApi = UserApi();
|
|
159
|
+
final users = await userApi.getUsers();
|
|
160
|
+
```
|
|
206
161
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
162
|
+
## ๐ Risoluzione Problemi
|
|
163
|
+
|
|
164
|
+
### Errore: "Swagger validation failed"
|
|
165
|
+
Il documento Swagger non รจ valido. Verifica:
|
|
166
|
+
- Presenza di `openApi` version
|
|
167
|
+
- Presenza di `paths` object
|
|
168
|
+
- Struttura corretta delle definizioni
|
|
169
|
+
|
|
170
|
+
### Errore: "Cannot parse null data"
|
|
171
|
+
L'API restituisce null per un tipo primitivo. Verifica che il backend ritorni sempre un valore valido.
|
|
172
|
+
|
|
173
|
+
### Tipi primitivi non funzionano (Dart)
|
|
174
|
+
โ
**RISOLTO** - Ora il generatore gestisce correttamente String, int, bool, double con conversioni automatiche.
|
|
175
|
+
|
|
176
|
+
## ๐ ๏ธ Sviluppo
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Clone repository
|
|
180
|
+
git clone <repo-url>
|
|
181
|
+
|
|
182
|
+
# Install dependencies
|
|
183
|
+
npm install
|
|
184
|
+
|
|
185
|
+
# Build
|
|
186
|
+
npm run build
|
|
187
|
+
|
|
188
|
+
# Test local
|
|
189
|
+
npm run debug-angular
|
|
190
|
+
npm run debug-nextjs
|
|
191
|
+
npm run debug-flutter
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## ๐ Script NPM
|
|
195
|
+
|
|
196
|
+
| Script | Descrizione |
|
|
197
|
+
|--------|-------------|
|
|
198
|
+
| `npm run build` | Compila TypeScript e copia templates |
|
|
199
|
+
| `npm run debug-angular` | Test con target Angular |
|
|
200
|
+
| `npm run debug-nextjs` | Test con target Next.js |
|
|
201
|
+
| `npm run debug-flutter` | Test con target Flutter |
|
|
202
|
+
| `npm run deploy` | Pubblica su npm |
|
|
203
|
+
|
|
204
|
+
## ๐ค Contribuire
|
|
205
|
+
|
|
206
|
+
Contributi benvenuti! Per favore:
|
|
207
|
+
1. Fai fork del progetto
|
|
208
|
+
2. Crea un branch per la tua feature (`git checkout -b feature/amazing-feature`)
|
|
209
|
+
3. Commit dei cambiamenti (`git commit -m 'Add amazing feature'`)
|
|
210
|
+
4. Push del branch (`git push origin feature/amazing-feature`)
|
|
211
|
+
5. Apri una Pull Request
|
|
212
|
+
|
|
213
|
+
## ๐ Licenza
|
|
214
|
+
|
|
215
|
+
ISC License - vedi file LICENSE per dettagli
|
|
216
|
+
|
|
217
|
+
## ๐ Crediti
|
|
218
|
+
|
|
219
|
+
Sviluppato da DeVLearninG Team
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
**Note**: Questo tool รจ in sviluppo attivo. Per bug o feature request, apri una issue su GitHub.
|