@team-supercharge/oasg 15.0.0-feature-nestjs-auth-guard-508b1366.0 → 15.0.0
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.md +149 -14
- package/bin/dump-json.js +9 -0
- package/bin/oasg +14 -0
- package/bin/postman-target.js +65 -0
- package/config.schema.yml +10 -0
- package/package.json +5 -4
- package/targets/angular/generate.sh +4 -0
- package/targets/nestjs/generator-config.json +6 -3
- package/targets/nestjs/templates/api.service.mustache +2 -2
- package/targets/nestjs/templates/{auth.guard.ts → auth.guard.mustache} +14 -4
- package/targets/nestjs/templates/configuration.mustache +5 -0
- package/targets/nestjs/templates/index.mustache +1 -0
- package/targets/nestjs/templates/modelGeneric.mustache +42 -6
- package/targets/nestjs/templates/package.mustache +1 -1
package/README.md
CHANGED
@@ -8,6 +8,7 @@ Design APIs in OpenAPI 3.0 format, lint them, and generate client/server package
|
|
8
8
|
* [Create `.config.json`](#create-config.json)
|
9
9
|
* [Configure Linter](#configure-linter)
|
10
10
|
* [Use with Docker](#use-with-docker)
|
11
|
+
* [Version Overview](#version-overview)
|
11
12
|
* [Usage](#usage)
|
12
13
|
* [Linter Rules](#linter-rules)
|
13
14
|
* [Custom Rules](#custom-rules)
|
@@ -102,6 +103,47 @@ swaggerlint:
|
|
102
103
|
|
103
104
|
---
|
104
105
|
|
106
|
+
# Version Overview
|
107
|
+
|
108
|
+
The table below gives an overview of the changes (breaking, non-breaking, bug fixes) introduced in various major versions. For the resolution of breaking changes please consult the [Migration Guide](#migration-guide).
|
109
|
+
|
110
|
+
| Component | | | | | | | | | | | | | | | |
|
111
|
+
|------------------------------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|
112
|
+
| **Internal** | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
113
|
+
| _Core_ |🐛 |💥 |✨ |🐛 |✨ |➖ |✨ |🐛 |🐛 |➖ |💥 |💥 |✨ |💥 |🆕 |
|
114
|
+
| _Linter_ |➖ |➖ |➖ |➖ |💥 |➖ |➖ |➖ |➖ |🐛 |➖ |✨ |💥 |🆕 |
|
115
|
+
| **Client Targets** | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
116
|
+
| `android` |➖ |🐛 |💥 |➖ |➖ |💥 |➖ |➖ |➖ |➖ |➖ |➖ |➖ |🆕 |
|
117
|
+
| `angular` |➖ |🐛 |💥 |➖ |➖ |➖ |🐛 |➖ |➖ |➖ |💥 |➖ |➖ |➖ |🆕 |
|
118
|
+
| `dotnet` |➖ |🆕 |
|
119
|
+
| `feign` |➖ |➖ |➖ |➖ |➖ |✨ |💥 |💥 |➖ |➖ |🐛 |🐛 |🆕 |
|
120
|
+
| `feign-kotlin` |➖ |➖ |➖ |➖ |➖ |🆕 |
|
121
|
+
| `flutter` |➖ |➖ |🆕 |
|
122
|
+
| `ios` |➖ |➖ |💥 |🐛 |➖ |➖ |➖ |✨ |➖ |💥 |➖ |➖ |✨ |🆕 |
|
123
|
+
| `kmp` |➖ |🆕 |
|
124
|
+
| `python` |➖ |🐛 |💥 |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |🆕 |
|
125
|
+
| `react` |➖ |➖ |💥 |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |🆕 |
|
126
|
+
| **Server Targets** | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
127
|
+
| `nestjs` |💥 |➖ |💥 |✨ |➖ |➖ |🐛 |➖ |➖ |✨ |🆕 |
|
128
|
+
| `python-fastapi` |➖ |🆕 |
|
129
|
+
| `python-fastapi-raw-request` |➖ |🆕 |
|
130
|
+
| `spring` |➖ |➖ |➖ |➖ |➖ |✨ |💥 |💥 |➖ |➖ |➖ |✨ |➖ |🆕 |
|
131
|
+
| `spring-kotlin` |➖ |➖ |➖ |➖ |➖ |✨ |💥 |💥 |➖ |➖ |🐛 |✨ |➖ |🆕 |
|
132
|
+
| **Misc Targets** | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
133
|
+
| `contract-testing` |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |🆕 |
|
134
|
+
| `openapi` |➖ |➖ |➖ |💥 |➖ |➖ |✨ |➖ |🆕 |
|
135
|
+
| `stubby` |➖ |➖ |➖ |➖ |➖ |➖ |➖ |➖ |💥 |➖ |➖ |➖ |➖ |🆕 |
|
136
|
+
| `postman` |🆕 |
|
137
|
+
|
138
|
+
**Legend:**
|
139
|
+
|
140
|
+
* 🆕 feature/target introduced
|
141
|
+
* 💥 breaking changes
|
142
|
+
* ✨ new features added
|
143
|
+
* 🐛 bug fixes only
|
144
|
+
|
145
|
+
---
|
146
|
+
|
105
147
|
# Usage
|
106
148
|
|
107
149
|
## `lint`
|
@@ -216,11 +258,11 @@ rules:
|
|
216
258
|
|
217
259
|
The following rules are defined in the custom _OASg Ruleset_.
|
218
260
|
|
219
|
-
> ⚠️ From the rules in the same group only one can be enabled at a time as they are colliding with
|
261
|
+
> ⚠️ From the rules in the same group only one can be enabled at a time as they are colliding with each other. Please turn off the default one and enable the other if you intend to change the default behaviour.
|
220
262
|
|
221
263
|
| Group | Rule | Default | Description |
|
222
264
|
|-|-|-|-|
|
223
|
-
| | `oasg-object-names-pascal-case` | Y | Every object defined in the spec (schemas, requests, responses)
|
265
|
+
| | `oasg-object-names-pascal-case` | Y | Every object defined in the spec (schemas, requests, responses) should be `PascalCased`, as they are most likely to be converted into classes / enums / objects during code generation |
|
224
266
|
| | `oasg-object-names-api-model-suffix` | | makes sure every schema, request, response has the `ApiModel` suffix (used to avoid naming collision) |
|
225
267
|
| | `oasg-operation-ids-camel-case` | Y | The `operationId` properties for paths should be `camelCased`, as they are converted to class methods during code generation |
|
226
268
|
| path casing | `oasg-path-casing-kebab` | Y | enforces `kebab-casing` for path segments |
|
@@ -242,7 +284,7 @@ The function enables to verify a value against a set of enumeration values defin
|
|
242
284
|
|
243
285
|
Function parameters:
|
244
286
|
* `schema` - Name of the schema to be validated against, must contain `enum` definition
|
245
|
-
* `file` - (optional) YAML file with `components.schemas` defined, otherwise the currently linted
|
287
|
+
* `file` - (optional) YAML file with `components.schemas` defined, otherwise the currently linted document is used
|
246
288
|
|
247
289
|
Example usage in a custom project ruleset:
|
248
290
|
|
@@ -278,7 +320,7 @@ export default {
|
|
278
320
|
|
279
321
|
# Template Customization
|
280
322
|
|
281
|
-
Using the
|
323
|
+
Using the coming `templateDir` config parameter there is a possibility to customize the templates used during generation.
|
282
324
|
|
283
325
|
OASg offers two levels of customization:
|
284
326
|
|
@@ -290,7 +332,7 @@ The **"project level"** customization can be configured using the `templateDir`
|
|
290
332
|
* if you specify a directory there, the contents of it will be __copied over__ the templates from the previous level
|
291
333
|
|
292
334
|
> ⚠️ At any level if you want to introduce a customized template, always make sure you start from the **right version**:
|
293
|
-
> 1. for **OASG level** customizations always
|
335
|
+
> 1. for **OASG level** customizations always check the version field in `DEFAULT_GENERATOR_MAPPING` for your selected [Target](#target) and copy the [original template](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources) from the right tag!
|
294
336
|
> 2. for **project level** customizations check first if the selected template is already customized on **OASG level**, in that case copy the template from the OASg source code
|
295
337
|
|
296
338
|
---
|
@@ -315,7 +357,7 @@ Common source parameters
|
|
315
357
|
|
316
358
|
The source specification is by default bundled into a single file (resolving external dependencies) using the [@redocly/cli package's](https://www.npmjs.com/package/@redocly/cli) `bundle` command.
|
317
359
|
|
318
|
-
> ⚠️ It is
|
360
|
+
> ⚠️ It is highly recommended to keep `bundle` on if you plan to use the `openapi` target type, as external refs won't be part of the target artifact.
|
319
361
|
|
320
362
|
Decorator files must export a `decorate(document)` function which transforms the parsed OpenAPI document and returns it at the end of the function.
|
321
363
|
|
@@ -454,6 +496,20 @@ Common target parameters
|
|
454
496
|
| packageName | Name of the generated NPM package | Y | - |
|
455
497
|
| repository | URL of the NPM package registry | Y | - |
|
456
498
|
|
499
|
+
##### Known issue: breaking dependencies
|
500
|
+
|
501
|
+
The Angular target has a known issue related to dependency versioning. The generated Angular project's `package.json` currently defines multiple dependencies with flexible versions (e.g., using `^` or `~` in version constraints). This flexibility allows newer versions of dependencies (not to mention the transitive dependencies), to be pulled in, which can occasionally lead to breaking changes.
|
502
|
+
|
503
|
+
A notable instance of this issue occurred with **Angular version 12**, which introduced changes that broke the build of generated projects. To address this specific case, we implemented a **temporary fix** in the `targets/angular/generate.sh` script. This script now manually installs problematic dependencies with fixed, validated versions.
|
504
|
+
|
505
|
+
###### Long-Term Solution
|
506
|
+
|
507
|
+
We are actively discussing a long-term solution to this issue. Potential approaches include implementing dependency version locking mechanisms (`package-lock.json`) per Angular versions.
|
508
|
+
|
509
|
+
The temporary fix may not cover all future breaking changes from other dependencies. Projects using different versions of Angular may encounter issues if the fix does not align with their specific requirements.
|
510
|
+
|
511
|
+
We welcome feedback and contributions to help address this issue.
|
512
|
+
|
457
513
|
#### `react`
|
458
514
|
|
459
515
|
```json
|
@@ -681,7 +737,7 @@ TBD
|
|
681
737
|
| packageName | Package nem for the project (convention: snake_case) | Y | - |
|
682
738
|
| repositoryUrl | URL of the PyPI repository | Y | - |
|
683
739
|
|
684
|
-
Publishing the PyPI packages is done with Twine. For authentication
|
740
|
+
Publishing the PyPI packages is done with Twine. For authentication against the PiPI repository you need to set the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables.
|
685
741
|
|
686
742
|
|
687
743
|
#### `python-fastapi`
|
@@ -702,7 +758,7 @@ Publishing the PyPI packages is done with Twine. For authentication againts the
|
|
702
758
|
| repositoryUrl | URL of the PyPI repository | Y | - |
|
703
759
|
|
704
760
|
Building the distribution package requires Flit.
|
705
|
-
Publishing the PyPI packages is done with Twine. For authentication
|
761
|
+
Publishing the PyPI packages is done with Twine. For authentication against the PiPI repository you need to set the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables.
|
706
762
|
|
707
763
|
#### `python-fastapi-raw-request`
|
708
764
|
|
@@ -722,7 +778,7 @@ Publishing the PyPI packages is done with Twine. For authentication againts the
|
|
722
778
|
| repositoryUrl | URL of the PyPI repository | Y | - |
|
723
779
|
|
724
780
|
Building the distribution package requires Flit.
|
725
|
-
Publishing the PyPI packages is done with Twine. For authentication
|
781
|
+
Publishing the PyPI packages is done with Twine. For authentication against the PiPI repository you need to set the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables.
|
726
782
|
|
727
783
|
#### `contract-testing`
|
728
784
|
|
@@ -821,15 +877,74 @@ describe('Auth', function () {
|
|
821
877
|
| packageName | Name of the generated NPM package | Y | - |
|
822
878
|
| repository | URL of the NPM package registry | Y | - |
|
823
879
|
|
824
|
-
|
880
|
+
**Authorisation**<br>
|
825
881
|
The package generates an AuthGuard and applies to endpoints, where a security scheme is defined.
|
826
|
-
// TODO - rest of the description and how to use it
|
827
882
|
|
883
|
+
AuthGuard usage:
|
884
|
+
Implement the `AuthServiceInterface`, which will receive a validation request for each security scheme added to the checked endpoint and define the validation per scheme.
|
885
|
+
Finally provide the service in the context of the module the controller is defined in with the `AUTH_SERVICE_TOKEN` token.
|
886
|
+
|
887
|
+
If there is already an authorisation service setup for the controllers, the below dummy implementation could be used as a step over until full implementation.
|
888
|
+
|
889
|
+
```ts
|
890
|
+
@Module(
|
891
|
+
providers:[
|
892
|
+
{
|
893
|
+
provide: AUTH_SERVICE_TOKEN,
|
894
|
+
useValue: { validate: () => true },
|
895
|
+
},
|
896
|
+
]
|
897
|
+
)
|
898
|
+
export class RootModule {}
|
899
|
+
```
|
900
|
+
Future improvements:
|
901
|
+
- with analyzing the request in the guard, only call the validation service with the relevant scheme (i.e: both ApiKey and Bearer Auth defined, but only API_KEY is present in the header, call only with ApiKey scheme )
|
828
902
|
|
829
903
|
**Known limitations:**
|
830
904
|
- array of enums in query/header/path/form parameters are not validated (stay as string)
|
831
905
|
- no multidimensional array validation in DTOs
|
832
906
|
|
907
|
+
**Validation availability:**
|
908
|
+
<br> _List is not comprehensive, missing items are definitely not currently supported_
|
909
|
+
|
910
|
+
Validations in General:
|
911
|
+
| Validation | DTO | Query | Header | Path |
|
912
|
+
| ---------------------- | :-: | :---: | :----: | :--: |
|
913
|
+
| multidimensional array | ❌ | ❌ | ❌ | ❌ |
|
914
|
+
| enum arrays | ✅ | ❌ | ❌ | ❌ |
|
915
|
+
|
916
|
+
Validations from OpenAPI spec:
|
917
|
+
| OpenApi Validation | Corresponding `class-validator` | DTO | Query | Header | Path | Workaround suggestion |
|
918
|
+
| ------------------ | ------------------------------- | :-: | :---: | :----: | :--: | ----------------------- |
|
919
|
+
| **Common** | | | | | | |
|
920
|
+
| required | IsDefined | ✅ | ✅ | ✅ | ✅ | |
|
921
|
+
| !required | IsOptional | ✅ | ✅ | ✅ | ✅ | |
|
922
|
+
| **Types** | | | | | | |
|
923
|
+
| isBoolean | IsBoolean | ✅ | ✅ | ✅ | ✅ | |
|
924
|
+
| isString | IsString | ✅ | ✅ | ✅ | ✅ | |
|
925
|
+
| isNumber | IsNumber | ✅ | ✅ | ✅ | ✅ | |
|
926
|
+
| isFloat | IsNumber | ✅ | ✅ | ✅ | ✅ | |
|
927
|
+
| isDouble | IsNumber | ✅ | ✅ | ✅ | ✅ | |
|
928
|
+
| isEnum | IsEnum | ✅ | ✅ | ✅ | ✅ | |
|
929
|
+
| isArray | IsArray | ✅ | ✅ | ✅ | ✅ | |
|
930
|
+
| isDate | | ❌ | ❌ | ❌ | ❌ | `pattern`, `isDateTime` |
|
931
|
+
| isDateTime | IsISO8601 | ✅ | ✅ | ✅ | ✅ | |
|
932
|
+
| **String** | | | | | | |
|
933
|
+
| pattern | Matches | ✅ | ✅ | ✅ | ✅ | |
|
934
|
+
| minLength | | ❌ | ❌ | ❌ | ❌ | `pattern` |
|
935
|
+
| maxLength | | ❌ | ❌ | ❌ | ❌ | `pattern` |
|
936
|
+
| isUuid | IsUUID | ✅ | ✅ | ✅ | ✅ | |
|
937
|
+
| isUri | | ❌ | ❌ | ❌ | ❌ | `pattern` |
|
938
|
+
| isEmail | IsEmail | ✅ | ✅ | ✅ | ✅ | |
|
939
|
+
| **Number** | | | | | | |
|
940
|
+
| isInt | IsInt | ✅ | ✅ | ✅ | ✅ | |
|
941
|
+
| isLong | IsInt | ✅ | ✅ | ✅ | ✅ | |
|
942
|
+
| isShort | IsInt | ✅ | ✅ | ✅ | ✅ | |
|
943
|
+
| isUnboundedInteger | | ❌ | ❌ | ❌ | ❌ | `isInt` |
|
944
|
+
| minimum | Min | ✅ | ✅ | ✅ | ✅ | |
|
945
|
+
| maximum | Max | ✅ | ✅ | ✅ | ✅ | |
|
946
|
+
|
947
|
+
|
833
948
|
#### `openapi`
|
834
949
|
|
835
950
|
```json
|
@@ -861,16 +976,36 @@ The package generates an AuthGuard and applies to endpoints, where a security sc
|
|
861
976
|
|Parameter| Description| Required | Default |
|
862
977
|
|-|-|-|-|
|
863
978
|
| sourceUrl | Url to where the package will be published | Y | - |
|
864
|
-
| apiKey |
|
979
|
+
| apiKey | Api key of nuget source | Y | - |
|
865
980
|
| packageName | Name of the generated package | Y | - |
|
866
981
|
| generatorCustomArgs | Custom arguments of the generator (--global-property, --additional-properties) | N | - |
|
867
982
|
|
983
|
+
#### `postman`
|
984
|
+
|
985
|
+
```json
|
986
|
+
{
|
987
|
+
"id": "postman-collection",
|
988
|
+
"type": "postman",
|
989
|
+
"source": "source-simple",
|
990
|
+
}
|
991
|
+
```
|
992
|
+
|
993
|
+
|Parameter| Description| Required | Default |
|
994
|
+
|-|-|-|-|
|
995
|
+
| fileName | Name of the generated file | N | `collection.json` |
|
996
|
+
|
868
997
|
---
|
869
998
|
|
870
999
|
# Migration Guide
|
871
1000
|
|
872
1001
|
This section covers the breaking changes and their migrations across major version upgrades.
|
873
1002
|
|
1003
|
+
## From `14.x.x` to `15.0.0`
|
1004
|
+
|
1005
|
+
In this version the `nestjs` generator has been upgraded to support verifying different security schemes from generated code. This means that a new [Guard](https://docs.nestjs.com/guards) has been introduced on the API oprerations which need to be implemented and checks for valid authentication credentials.
|
1006
|
+
|
1007
|
+
If you wish to change your authentication handling at a later date, use the [dummy implementation](#nestjs) mentioned above in the documentation.
|
1008
|
+
|
874
1009
|
## From `13.x.x` to `14.0.0`
|
875
1010
|
|
876
1011
|
Several dependencies have been upgraded, and OASg now uses `node` version 20.15.0 and `npm` version 10 by default. If your project still uses `node@18`, you should upgrade first.
|
@@ -977,7 +1112,7 @@ Take the following schema:
|
|
977
1112
|
properties: # users have a company, and firstName and lastName
|
978
1113
|
company:
|
979
1114
|
type: object
|
980
|
-
properties: #
|
1115
|
+
properties: # companies have id and name
|
981
1116
|
id:
|
982
1117
|
type: string
|
983
1118
|
name:
|
@@ -1089,7 +1224,7 @@ For older Angular versions it was necessary to install the `typescript@3.9.5` pa
|
|
1089
1224
|
|
1090
1225
|
## From `3.x.x` to `4.0.0`
|
1091
1226
|
|
1092
|
-
Starting from version `4.0.0` OASg became open-source. Thus future packages are (only) available from the official npmjs.org registry without any
|
1227
|
+
Starting from version `4.0.0` OASg became open-source. Thus future packages are (only) available from the official npmjs.org registry without any authentication.
|
1093
1228
|
|
1094
1229
|
Please take the following steps:
|
1095
1230
|
|
package/bin/dump-json.js
ADDED
package/bin/oasg
CHANGED
@@ -19,6 +19,7 @@ const { bash } = require(`${__dirname}/exec.js`);
|
|
19
19
|
const { merge } = require(`${__dirname}/merger.js`);
|
20
20
|
const { applyOverrides } = require(`${__dirname}/overrider.js`);
|
21
21
|
const { openApiTarget } = require(`${__dirname}/openapi-target.js`);
|
22
|
+
const { postmanTarget } = require(`${__dirname}/postman-target.js`);
|
22
23
|
const { processSource } = require(`${__dirname}/process-source.js`);
|
23
24
|
const { globSync } = require('glob');
|
24
25
|
|
@@ -54,6 +55,7 @@ const DEFAULT_GENERATOR_MAPPING = {
|
|
54
55
|
"contract-testing": { version: '4.3.1', generator: 'typescript-node' },
|
55
56
|
"openapi": { version: undefined, generator: undefined },
|
56
57
|
"stubby": { version: '4.3.1', generator: 'stubby' },
|
58
|
+
"postman": { version: undefined, generator: undefined },
|
57
59
|
};
|
58
60
|
const DEFAULT_KTLINT_VERSION = '1.0.0';
|
59
61
|
const BIN_FOLDER = 'out/.bin';
|
@@ -483,6 +485,12 @@ async function generate(argv) {
|
|
483
485
|
return;
|
484
486
|
}
|
485
487
|
|
488
|
+
// handle postman target
|
489
|
+
if (target.type === 'postman') {
|
490
|
+
postmanTarget(target, sources[target.source]);
|
491
|
+
return;
|
492
|
+
}
|
493
|
+
|
486
494
|
const binary = fetchBinary(target);
|
487
495
|
let formatter;
|
488
496
|
|
@@ -516,6 +524,12 @@ async function publish(argv) {
|
|
516
524
|
return;
|
517
525
|
}
|
518
526
|
|
527
|
+
// handle postman target
|
528
|
+
if (target.type === 'postman') {
|
529
|
+
console.log('publishing need to be implemented manuallly for `postman` targets');
|
530
|
+
return;
|
531
|
+
}
|
532
|
+
|
519
533
|
const binary = fetchBinary(target);
|
520
534
|
let formatter;
|
521
535
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
const fs = require('fs');
|
2
|
+
const PostmanParser = require('openapi-to-postmanv2');
|
3
|
+
const yaml = require('js-yaml');
|
4
|
+
|
5
|
+
const { dumpJSON } = require(`${__dirname}/dump-json.js`);
|
6
|
+
|
7
|
+
const defaultFileName = 'collection.json';
|
8
|
+
|
9
|
+
async function postmanTarget(target, source) {
|
10
|
+
const outDir = `out/${target.id}`;
|
11
|
+
let outFile = target.fileName || defaultFileName;
|
12
|
+
outFile = `${outDir}/${outFile}`;
|
13
|
+
|
14
|
+
if (fs.existsSync(outDir)) {
|
15
|
+
fs.rmSync(outDir, { recursive: true })
|
16
|
+
}
|
17
|
+
fs.mkdirSync(outDir, { recursive: true });
|
18
|
+
|
19
|
+
// Conversion options
|
20
|
+
const defaultOptions = {
|
21
|
+
requestNameSource: 'fallback',
|
22
|
+
requestParametersResolution: 'schema',
|
23
|
+
exampleParametersResolution: 'schema',
|
24
|
+
parametersResolution: 'schema',
|
25
|
+
collapseFolders: false,
|
26
|
+
folderStrategy: 'tags',
|
27
|
+
schemaFaker: false,
|
28
|
+
optimizeConversion: false,
|
29
|
+
includeAuthInfoInExample: false,
|
30
|
+
};
|
31
|
+
|
32
|
+
// Parse YAML to JavaScript object
|
33
|
+
const spec = yaml.load(fs.readFileSync(source, 'utf8'));
|
34
|
+
|
35
|
+
// Add version number in collection title
|
36
|
+
spec.info.title = `${spec.info.title} (${spec.info.version})`;
|
37
|
+
|
38
|
+
// Remove responses to avoid Example generation
|
39
|
+
for (const pathKey in spec.paths) {
|
40
|
+
const path = spec.paths[pathKey];
|
41
|
+
for (const methodKey in path) {
|
42
|
+
const operation = path[methodKey];
|
43
|
+
|
44
|
+
operation.responses = [];
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
// target-specific functions, e.g. write as JSON
|
49
|
+
PostmanParser.convert({ type: 'string', data: spec },
|
50
|
+
defaultOptions, (err, conversionResult) => {
|
51
|
+
if (err) {
|
52
|
+
console.error('Conversion error', err);
|
53
|
+
}
|
54
|
+
else if (!conversionResult.result) {
|
55
|
+
console.log('Could not convert', conversionResult.reason);
|
56
|
+
}
|
57
|
+
else {
|
58
|
+
// write file
|
59
|
+
dumpJSON(conversionResult.output[0].data, outFile);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
exports.postmanTarget = postmanTarget;
|
package/config.schema.yml
CHANGED
@@ -28,6 +28,7 @@ properties:
|
|
28
28
|
- $ref: '#/targets/Flutter'
|
29
29
|
- $ref: '#/targets/Kmp'
|
30
30
|
- $ref: '#/targets/Dotnet'
|
31
|
+
- $ref: '#/targets/Postman'
|
31
32
|
required:
|
32
33
|
- targets
|
33
34
|
additionalProperties: false
|
@@ -420,6 +421,15 @@ targets:
|
|
420
421
|
- artifactId
|
421
422
|
- repository
|
422
423
|
|
424
|
+
Postman:
|
425
|
+
allOf:
|
426
|
+
- $ref: '#/targets/Base'
|
427
|
+
- properties:
|
428
|
+
type:
|
429
|
+
pattern: "^postman$"
|
430
|
+
fileName:
|
431
|
+
type: string
|
432
|
+
|
423
433
|
definitions:
|
424
434
|
# default
|
425
435
|
SourceOverrides:
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@team-supercharge/oasg",
|
3
|
-
"version": "15.0.0
|
3
|
+
"version": "15.0.0",
|
4
4
|
"description": "Node-based tool to lint OpenAPI documents and generate clients, servers and documentation from them",
|
5
5
|
"author": "Supercharge",
|
6
6
|
"license": "MIT",
|
@@ -28,9 +28,9 @@
|
|
28
28
|
"dependencies": {
|
29
29
|
"@apidevtools/json-schema-ref-parser": "^10.1.0",
|
30
30
|
"@apidevtools/swagger-parser": "^10.1.0",
|
31
|
-
"@redocly/cli": "1.
|
32
|
-
"@stoplight/prism-cli": "5.
|
33
|
-
"@stoplight/spectral-cli": "6.
|
31
|
+
"@redocly/cli": "1.25.11",
|
32
|
+
"@stoplight/prism-cli": "5.12.0",
|
33
|
+
"@stoplight/spectral-cli": "6.14.1",
|
34
34
|
"ajv": "^8.12.0",
|
35
35
|
"command-exists": "^1.2.9",
|
36
36
|
"express": "^4.18.2",
|
@@ -38,6 +38,7 @@
|
|
38
38
|
"glob": "^10.2.1",
|
39
39
|
"js-yaml": "^4.1.0",
|
40
40
|
"json-schema-merge-allof": "^0.8.1",
|
41
|
+
"openapi-to-postmanv2": "4.24.0",
|
41
42
|
"openapi-typescript-validator-ext-ref": "^3.2.0-external-ref-support",
|
42
43
|
"swagger-ui-express": "^5.0.1",
|
43
44
|
"yamljs": "^0.3.0",
|
@@ -15,5 +15,9 @@ java -jar $binary generate \
|
|
15
15
|
|
16
16
|
cd out/$targetId
|
17
17
|
npm install
|
18
|
+
# This is a workaround for an issue with the angular generator. Root cause is the missing package-lock.json: https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/typescript-angular
|
19
|
+
# some of the transitive dependency has @types/node@": "*" in their package.json
|
20
|
+
# use "npm explain @types/node" in the generated folder (./out/$TARGET) to get more info
|
21
|
+
npm install --save-dev @types/node@20.15.0
|
18
22
|
npm run build
|
19
23
|
cd ../..
|
@@ -15,8 +15,10 @@
|
|
15
15
|
"pipes.ts": {
|
16
16
|
"templateType": "SupportingFiles"
|
17
17
|
},
|
18
|
-
"auth.guard.
|
19
|
-
"templateType": "SupportingFiles"
|
18
|
+
"auth.guard.mustache": {
|
19
|
+
"templateType": "SupportingFiles",
|
20
|
+
"folder": "",
|
21
|
+
"destinationFilename": "auth.guard.ts"
|
20
22
|
},
|
21
23
|
"exceptions.ts": {
|
22
24
|
"templateType": "SupportingFiles"
|
@@ -43,6 +45,7 @@
|
|
43
45
|
"inlineSchemaOptions": {
|
44
46
|
"ARRAY_ITEM_SUFFIX": "",
|
45
47
|
"MAP_ITEM_SUFFIX": "",
|
46
|
-
"SKIP_SCHEMA_REUSE": "true"
|
48
|
+
"SKIP_SCHEMA_REUSE": "true",
|
49
|
+
"RESOLVE_INLINE_ENUMS": "true"
|
47
50
|
}
|
48
51
|
}
|
@@ -10,7 +10,7 @@ import { FileInterceptor } from '@nestjs/platform-express';
|
|
10
10
|
|
11
11
|
import { OptionalParseIntPipe, OptionalParseFloatPipe, OptionalParseBoolPipe, OptionalParseEnumPipe, RequiredPipe } from '../pipes';
|
12
12
|
import { ApiParseArrayPipe, ApiValidationPipe } from '../pipes';
|
13
|
-
import { AuthGuard, AuthSchemes } from '../auth.guard';
|
13
|
+
import { AuthGuard, AuthSchemes, SecurityScheme } from '../auth.guard';
|
14
14
|
|
15
15
|
{{#imports}}
|
16
16
|
// @ts-ignore
|
@@ -46,7 +46,7 @@ export abstract class {{classname}} {
|
|
46
46
|
*/
|
47
47
|
|
48
48
|
{{#authMethods}}{{#-first}}
|
49
|
-
@AuthSchemes([{{#authMethods}}
|
49
|
+
@AuthSchemes([{{#authMethods}}SecurityScheme.{{name}}{{^-last}}, {{/-last}}{{/authMethods}}])
|
50
50
|
@UseGuards(AuthGuard) {{/-first}}{{/authMethods}}
|
51
51
|
//// @{{httpMethod}}('{{path}}'){{#isMultipart}}
|
52
52
|
@UseInterceptors(FileInterceptor({{#formParams}}{{#isFile}}'{{paramName}}'{{/isFile}}{{/formParams}})){{/isMultipart}}
|
@@ -3,15 +3,22 @@ import {
|
|
3
3
|
ExecutionContext,
|
4
4
|
Inject,
|
5
5
|
Injectable,
|
6
|
+
UnauthorizedException,
|
6
7
|
} from "@nestjs/common";
|
7
8
|
import { Reflector } from "@nestjs/core";
|
8
9
|
import { Observable } from "rxjs";
|
9
10
|
|
10
|
-
export
|
11
|
+
// export securityScheme names as enum
|
12
|
+
export enum SecurityScheme { {{#authMethods}}
|
13
|
+
{{name}} = "{{name}}",{{/authMethods}}{{^authMethods}}
|
14
|
+
NoScheme = "none",{{/authMethods}}
|
15
|
+
}
|
16
|
+
|
17
|
+
export const AuthSchemes = Reflector.createDecorator<SecurityScheme[]>();
|
11
18
|
|
12
19
|
export interface AuthServiceInterface {
|
13
20
|
validate: (
|
14
|
-
scheme:
|
21
|
+
scheme: SecurityScheme,
|
15
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
16
23
|
request: any
|
17
24
|
) => boolean | Promise<boolean> | Observable<boolean>;
|
@@ -30,9 +37,12 @@ export class AuthGuard implements CanActivate {
|
|
30
37
|
canActivate(
|
31
38
|
context: ExecutionContext
|
32
39
|
): boolean | Promise<boolean> | Observable<boolean> {
|
33
|
-
const schemes = this.reflector.get(AuthSchemes, context.getHandler());
|
40
|
+
const schemes = this.reflector.get<SecurityScheme[]>(AuthSchemes, context.getHandler());
|
34
41
|
const request = context.switchToHttp().getRequest();
|
35
42
|
|
36
|
-
|
43
|
+
if (schemes.some((scheme) => this.authService.validate(scheme, request)))
|
44
|
+
return true;
|
45
|
+
|
46
|
+
throw new UnauthorizedException();
|
37
47
|
}
|
38
48
|
}
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import { Type } from 'class-transformer';
|
2
2
|
|
3
3
|
import { IsOptional, IsDefined } from 'class-validator';
|
4
|
-
import { IsString,
|
5
|
-
import {
|
4
|
+
import { IsString, IsNumber, IsBoolean, IsEnum, IsArray, ValidateNested } from 'class-validator';
|
5
|
+
import { Max, Min, IsInt } from 'class-validator';
|
6
|
+
import { Matches, IsEmail, IsUUID } from 'class-validator';
|
7
|
+
import { IsISO8601 } from 'class-validator';
|
6
8
|
|
7
9
|
export class {{classname}}{{#allParents}}{{#-first}} extends {{/-first}}{{{.}}}{{^-last}}, {{/-last}}{{/allParents}} { {{>modelGenericAdditionalProperties}}
|
8
10
|
{{#vars}}
|
@@ -11,10 +13,44 @@ export class {{classname}}{{#allParents}}{{#-first}} extends {{/-first}}{{{.}}}{
|
|
11
13
|
* {{{.}}}
|
12
14
|
*/
|
13
15
|
{{/description}}
|
14
|
-
{{#required}}@IsDefined(){{/required}}{{^required}}@IsOptional(){{/required}}{{^isArray}}
|
15
|
-
|
16
|
-
@
|
17
|
-
|
16
|
+
{{#required}}@IsDefined(){{/required}}{{^required}}@IsOptional(){{/required}}{{^isArray}}{{#isString}}
|
17
|
+
@IsString(){{#pattern}}
|
18
|
+
@Matches({{{.}}}){{/pattern}}{{#isEmail}}
|
19
|
+
@IsEmail(){{/isEmail}}{{#isUuid}}
|
20
|
+
@IsUUID(){{/isUuid}}{{/isString}}{{#isDateTime}}
|
21
|
+
@IsString()
|
22
|
+
@IsISO8601({ strict: true, strictSeparator: true }){{/isDateTime}}{{#isInteger}}
|
23
|
+
@IsInt(){{/isInteger}}{{#isLong}}
|
24
|
+
@IsInt(){{/isLong}}{{#isShort}}
|
25
|
+
@IsInt(){{/isShort}}{{#isNumber}}
|
26
|
+
@IsNumber(){{/isNumber}}{{#isFloat}}
|
27
|
+
@IsNumber(){{/isFloat}}{{#isDouble}}
|
28
|
+
@IsNumber(){{/isDouble}}{{#isBoolean}}
|
29
|
+
@IsBoolean(){{/isBoolean}}{{#minimum}}
|
30
|
+
@Min({{minimum}}){{/minimum}}{{#maximum}}
|
31
|
+
@Max({{maximum}}){{/maximum}}{{#allowableValues}}{{^enumVars.empty}}
|
32
|
+
@IsEnum({{{dataType}}}){{/enumVars.empty}}{{/allowableValues}}{{#isModel}}
|
33
|
+
@ValidateNested()
|
34
|
+
@Type(() => {{{dataType}}}){{/isModel}}{{/isArray}}{{#isArray}}
|
35
|
+
@IsArray(){{#items}}{{#isString}}
|
36
|
+
@IsString({ each: true }){{#pattern}}
|
37
|
+
@Matches({{{.}}}, { each: true }){{/pattern}}{{#isEmail}}
|
38
|
+
@IsEmail(undefined, { each: true}){{/isEmail}}{{#isUuid}}
|
39
|
+
@IsUUID(undefined, { each: true}){{/isUuid}}{{/isString}}{{#isDateTime}}
|
40
|
+
@IsString({ each: true })
|
41
|
+
@IsISO8601({ strict: true, strictSeparator: true }, { each: true }){{/isDateTime}}{{#isInteger}}
|
42
|
+
@IsInt({ each: true }){{/isInteger}}{{#isLong}}
|
43
|
+
@IsInt({ each: true }){{/isLong}}{{#isShort}}
|
44
|
+
@IsInt({ each: true }){{/isShort}}{{#isNumber}}
|
45
|
+
@IsNumber(undefined, { each: true }){{/isNumber}}{{#isFloat}}
|
46
|
+
@IsNumber(undefined, { each: true }){{/isFloat}}{{#isDouble}}
|
47
|
+
@IsNumber(undefined, { each: true }){{/isDouble}}{{#isBoolean}}
|
48
|
+
@IsBoolean({ each: true }){{/isBoolean}}{{#minimum}}
|
49
|
+
@Min({{minimum}}, { each: true }){{/minimum}}{{#maximum}}
|
50
|
+
@Max({{maximum}}, { each: true }){{/maximum}}{{#allowableValues}}{{^enumVars.empty}}
|
51
|
+
@IsEnum({{{dataType}}}, { each: true }){{/enumVars.empty}}{{/allowableValues}}{{#isModel}}
|
52
|
+
@ValidateNested({ each: true }) @Type(() => {{{dataType}}}){{/isModel}}{{#isArray}}
|
53
|
+
// Multidimensional array validation not supported{{/isArray}}{{/items}}{{/isArray}}
|
18
54
|
{{#isReadOnly}}readonly {{/isReadOnly}}{{{name}}}{{^required}}?{{/required}}: {{{dataType}}}{{#isNullable}} | null{{/isNullable}};
|
19
55
|
|
20
56
|
{{/vars}}
|