{"id":19990048,"url":"https://github.com/jnwltr/swagger-angular-generator","last_synced_at":"2026-02-14T04:10:28.311Z","repository":{"id":26327344,"uuid":"107537562","full_name":"jnwltr/swagger-angular-generator","owner":"jnwltr","description":"Generator of API layer in TypeScript for Angular 2+ apps","archived":false,"fork":false,"pushed_at":"2024-01-11T04:22:26.000Z","size":1682,"stargazers_count":91,"open_issues_count":30,"forks_count":46,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-30T13:23:46.932Z","etag":null,"topics":["angular","api","form","generator","ngrx","openapi","swagger","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jnwltr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-19T11:29:26.000Z","updated_at":"2024-10-18T08:16:30.000Z","dependencies_parsed_at":"2024-06-18T16:55:20.380Z","dependency_job_id":"5834145b-afe0-4d7d-97b9-9d825f684454","html_url":"https://github.com/jnwltr/swagger-angular-generator","commit_stats":{"total_commits":141,"total_committers":9,"mean_commits":"15.666666666666666","dds":0.3049645390070922,"last_synced_commit":"fb0452a1aec33aa207ab10eb9b758b815e5c8fd0"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnwltr%2Fswagger-angular-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnwltr%2Fswagger-angular-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnwltr%2Fswagger-angular-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnwltr%2Fswagger-angular-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jnwltr","download_url":"https://codeload.github.com/jnwltr/swagger-angular-generator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224391390,"owners_count":17303609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","api","form","generator","ngrx","openapi","swagger","typescript"],"created_at":"2024-11-13T04:50:55.197Z","updated_at":"2026-02-14T04:10:28.272Z","avatar_url":"https://github.com/jnwltr.png","language":"TypeScript","readme":"## Purpose\n\nGenerate minimalistic TypeScript API layer for Angular with full type reflection of backend model.\n- Source: [swagger scheme](https://swagger.io/specification/)\n- Destination: [Angular-cli](https://cli.angular.io/) based [Angular](https://angular.io/) app.\n\n## What is generated\n\n### Services for back-end / API communication\n- connect to your API in no-time\n\n### Interfaces\n- request and response interfaces are created\n\n### Forms services for the PUT and POST methods\n- forms can be created by merely importing a service and using it in HTML templates (see below)\n\n### NGRX modules for endpoints (optional)\n- so that the server responses can be reached in the redux store\n- requests can be triggered by dispatching an action\n\n##### Have a look at the [demo generated files](demo/generated) to get better understanding what is being generated.\n\n## Install\n`npm i swagger-angular-generator`\n\n## Options\n`-h` - show help\n`-s`, `--src` - source directory\n`-d`, `--dest` - destination directory, default: `src/api`\n`--no-store` - do not generate the ngrx modules\n`-u, --swagger-URL-path` - swagger URL path, where the swagger ui documentation can be found; default: `/swagger`, i.e. the resulting address would be `http://example/swagger`\n`-o, --omit-version` - disables API version information to be generated in comments for each file\n\n\n## Use\n\n### Run generator\n\n1. get the swagger scheme (typically at http(s)://[server]/[app-path]/v2/api/api-docs)\n1. save it to json file in input directory and optionally **format** it for better diff\n1. run via\n    1. **directly** `./node_modules/.bin/swagger-angular-generator`\n    1. **as module** `swagger-angular-generator` package, `npm run generate`\n        ```javascript\n        \"script\": {\n          \"generate\": \"swagger-angular-generator -s src/api/scheme.json -d src/api/generated\"\n          ...\n        }\n        ```\n    1. or **programatically** as a method invocation\n        ```typescript\n        import {generate} from 'swagger-angular-generator';\n        // or using CommonJS loader\n        const {generate} = require('swagger-angular-generator');\n\n        generate('conf/api/api-docs.json', 'src/api');\n        ```\n\nThe resulting API layer contains the following structure in the destination directory:\n\n1. `controllers` directory stores services containing all API methods devided by controllers\n1. `defs` directory stores all response interfaces and enums\n1. `store` directory has modules, which contain associated form service and NGRX actions, reducers and effects\n1. `model.ts` file reexports all of them together for a simple access\n\nWhen updating your code for new backend version, we recommend you to follow these steps:\n\n1. `git diff` the changes\n1. run `tsc` for immediate problems\n1. adjust the code, solve problems\n1. commit\n\n### Use\n\nIn order to consume generated model, follow the steps **1-9** in the following example to use generated API model.\n\n#### API service usage in component\n\n```typescript\n// 1. import used response interfaces\nimport {ItemDto, PageDto} from '[relative-path-to-destination-directory]/model';\n// 2. import used API service and optionally param interfaces\nimport {DataService, MethodParams} from '[relative-path-to-destination-directory]/api/DataService';\n\n@Component({\n  ...\n  // 3. make the service injectable (can be also imported in the module)\n  providers: [DataService],\n})\nexport class MyComponent implements OnInit {\n  // 4. declare response object variables based on the generated API interfaces\n  public items: ItemDto[] = [];\n  public page: PageDto;\n\n  // 5. declare request params based on the generated API interface (all params are passed together in one object)\n  private params: MethodParams = {\n    page: 0,\n    size: 10,\n    sort: ['name:asc']\n  };\n\n  // 6. inject the API service\n  constructor(private dataService: DataService) {}\n\n  public ngOnInit() {\n    // 7. the returned observable is fully typed\n    this.dataService\n      .get(this.params)\n      // 8. returned data are fully typed\n      .subscribe(data =\u003e {\n        // 9. assignments are type-checked\n        this.items = data.content;\n        this.page = data.page;\n      });\n  }\n}\n```\n\n#### Usage of Forms services\n- the `exampleFormService` service is generated and holds the `FormGroup` definition that corresponds\n  with the request data structure\n- Array-like structures use `FormArrayExtended` that extends native Angulars' `FormArray` and holds the definition of array item so new items can be created for data via `.setValue()` or empty via `.createControl()`.\n- Map-like structures use `FormMap` that extends native Angulars' `FormGroup` and holds the definition of map value item so new items can be created for data via `.setValue()` or empty via `.createControl()`.\n- there's a helper method `safeSetValue()` that sets the shape and data of all `AbstractControl`'s ancestors and never fails (compatible data form the shape and are set, the rest is ignored).\n- use it in the template the following way\n- check the details in the generated test files, e.g.\n  - [generated form](demo/generated/store/structures/map/map.service.ts),\n  - [array tests](demo/src/tests/form/array.spec.ts),\n  - [map tests](demo/src/tests/form/map.spec.ts).\n\n```html\n\u003cform [formGroup]=\"exampleFormService.form\" (ngSubmit)=\"sendForm()\" class=\"full-width\"\u003e\n    \u003cinput type=\"text\" name=\"email\" placeholder=\"email\"\n           formControlName=\"email\" /\u003e\n    \u003cbutton type=\"submit\"\n            [disabled]=\"exampleFormService.form.invalid\"\u003eSave\u003c/button\u003e\n\u003c/form\u003e\n```\n\n- this is the corresponding component\n```typescript\n@Component({\n  selector: 'example-component',\n  templateUrl: 'example-component.html',\n})\nexport class ExampleComponent implements OnDestroy {\n  constructor(public exampleFormService: ExampleFormService) {}\n  sendForm() {...}\n}\n```\n\n- the generated service looks like this\n```typescript\nexport class ExampleFormService {\n  form: FormGroup;\n  constructor(private exampleService: ExampleService) {\n    this.form = new FormGroup({\n      email: new FormControl(undefined, [Validators.email, Validators.required]),\n    });\n  }\n}\n```\n\n#### NGRX workflow with generated modules, actions, effects, reducers and form services\n\n##### Import the generated module\n```typescript\n@NgModule({\n  imports: [\n    ...,\n    ExampleModule,\n    ...,\n  ],\n})\nexport class YourModule {}\n```\n\n- the generated module looks like this\n```typescript\n@NgModule({\n  imports: [\n    FormsSharedModule,\n    NgrxStoreModule.forFeature(selectorName, ExampleReducer),\n    NgrxEffectsModule.forFeature([ExampleEffects]),\n  ],\n  providers: [\n    ExampleService,\n    ExampleFormService,\n  ],\n})\nexport class ExampleModule {}\n```\n\n##### Component (created by you)\n\nIn the component, send the above created form via `sendForm()` method. Notice the way a generated anction is dispatched.\n\n```typescript\nimport {Component, OnDestroy} from '@angular/core';\nimport {Store} from '@ngrx/store';\nimport {takeUntil} from 'rxjs/operators';\nimport {Subject} from 'rxjs/Subject';\nimport {ExampleFormService} from '../../generated/store/example/exampleModule/example.service';\nimport {Start as ExampleStart} from '../../generated/store/example/exampleModule/states/actions';\nimport {AppState} from '../states/exmaple.models';\n\n@Component({\n  selector: 'example-component',\n  templateUrl: 'example-component.html',\n})\nexport class ExampleComponent implements OnDestroy {\n\n  constructor(\n    public exampleFormService: ExampleFormService,\n    private store: Store\u003cAppState\u003e,\n  ) {}\n\n  sendForm() {\n    this.store.dispatch(new ExampleStart(this.exampleFormService.form.value));\n  }\n\n  ngOnDestroy() {\n    this.ngDestroy.next();\n    this.ngDestroy.complete();\n  }\n}\n```\n\n##### Effect (generated)\n- the dispatched method is intercepted by an effect which calls the API via the generated API service\n- upon success, a `Success` action is dispatched (payload is the server response data)\n- upon error, an `Error` action is dispatched (payload is the error message sent from the server)\n\n```typescript\n@Injectable()\nexport class ExampleEffects {\n  CreateProductCategory = createEffect(() =\u003e this.storeActions.pipe(\n    ofType\u003cactions.Start\u003e(actions.Actions.START),\n    switchMap((action: actions.Start) =\u003e this.exampleService.exampleEndpointMethod(action.payload)\n      .pipe(\n        map(result =\u003e new actions.Success(result)),\n        catchError((error: HttpErrorResponse) =\u003e of(new actions.Error(error.message))),\n      ),\n    ),\n  ));  \n  \n  constructor(\n    private storeActions: Actions,\n    private adminproductService: AdminProductService,\n  ) {}\n}\n```\n\n##### Reducer (generated)\n- the reducer catches the `Success` / `Error` actions dispatched by the generated effect and stores the payloads to the store\n```typescript\nexport interface ExampleState {\n  data: __model.ExampleServerResponseInterface;\n  loading: boolean;\n  error: string;\n}\n\nexport const initialExampleState: ExampleState = {\n  data: null,\n  loading: false,\n  error: null,\n};\n\nexport const selectorName = 'Example';\nexport const getExampleSelector = createFeatureSelector\u003cExampleState\u003e(selectorName);\n\nexport function ExampleReducer(\n  state: ExampleState = initialExampleState,\n  action: actions.ExampleAction): ExampleState {\n  switch (action.type) {\n    case actions.Actions.START: return {...state, loading: true, error: null};\n    case actions.Actions.SUCCESS: return {...state, data: action.payload, loading: false};\n    case actions.Actions.ERROR: return {...state, error: action.payload, loading: false};\n    default: return state;\n  }\n}\n```\n\n##### Component (again)\n- the data can be retrieved by subscribing to the store\n\n```typescript\nngOnInit() {\n    this.exampleState = this.store.pipe(\n      takeUntil(this.ngDestroy),\n      select(getExampleSelector));\n    // OR\n    this.data = this.store.select(s =\u003e ExampleState.data)\n    this.loading = this.store.select(s =\u003e ExampleState.loading)\n    this.error = this.store.select(s =\u003e ExampleState.error)\n}\n```\n\n## Assumptions / limitations\n\n1. swagger file is in [version 2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) format, it must be json\n1. each endpoint must have a `tags` attribute defined. In addition, there must be exactly one tag defined.\nThe http methods are grouped to services based on the tags, i.e. if two methods have tag \"order\", both will be\ngenerated inside Order.ts\n1. `get` and `delete` methods do not contain `body`\n1. swagger file should contain values for the keys `host` and `basePath` so that each generated service method can contain a link to the swagger UI method reference, e.g. `http://example.com/swagger/swagger-ui.html#!/Order/Order`\n1. `definitions` section in swagger file does not contain types with inline definitions, i.e. only named subtypes work\n\n#### Usage of NGRX modules\n\n## Development\n\n* at least Node.js 10 is needed\n\n### Testing\n\n#### How the testing works\n\n* tests are written in the tests folder\n* the test swagger file can be found in demo/swagger-files\n* upon these swagger files, interfaces and services are generated\n* unit tests are located in `tests` folder\n\n#### Running the tests\n\nTo run client tests in interactive mode:\n\n1. `npm test`\n\n---\n\n### Release\n\n* `git checkout -b tech/release` on master or other branch you want to release\n* `npm version patch` or other version change you want\n* make a PR\n* once merged `npm publish`\n\n\n### _Pull requests are welcome!_\n\nPlease do the following before making a PR:\n\n1. Build the app and regenerate testing files via `npm run build`.\n1. Check test pass via `npm test`.\n1. Check files lint via `npm run eslint`.\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjnwltr%2Fswagger-angular-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjnwltr%2Fswagger-angular-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjnwltr%2Fswagger-angular-generator/lists"}