This project uses OpenAPI Generator to automatically generate the API client services and models based on the Apache Fineract Swagger specification.
The generator is configured in package.json and uses custom templates located in templates/openapi-generator/.
src/app/api/public/api/fineract.json (preprocessed into api-spec/fineract.json during generation)templates/openapi-generator/licenseInfo.mustache (adds Apache License header to all files)scripts/preprocess-spec.mjs (rewrites operationIds for stable method names — see below)Generated method names are stable across spec versions by design. Without intervention, the typescript-angular generator names methods from the spec's operationIds, which the Fineract spec reuses across hundreds of endpoints; the generator then disambiguates them with a global, document-order counter (retrieveAll21, create6, ...). Any spec change reshuffles every number and breaks call sites throughout the app.
To prevent this, npm run copy-swagger runs scripts/preprocess-spec.mjs, which rewrites every operationId to a deterministic value derived from the HTTP method + request path:
| Endpoint | Generated method |
|---|---|
GET /v1/clients | getClients |
GET /v1/clients/{clientId} | getClientsClientId |
PUT /v1/savingsaccounts/{id} | putSavingsaccountsAccountId |
Because (method, path) is unique per OpenAPI, these names are collision-free and independent of document order, so regenerating against a newer Fineract spec does not churn names. The preprocessor also fills in any missing responses.*.description, so generation passes validation without --skip-validate-spec. The committed spec (public/api/fineract.json) is never modified — only the throwaway api-spec/fineract.json copy the generator consumes.
The rationale and alternatives considered are recorded in DOCS/adr/0001-stable-openapi-operation-ids.md.
To (re)generate the API client, run:
npm run generate-api
This command will:
copy-swagger): run scripts/preprocess-spec.mjs to rewrite operationIds and patch missing response descriptions, writing api-spec/fineract.json.clean-api): remove src/app/api/api and src/app/api/model so endpoints removed upstream do not leave orphan files behind (the generator never prunes).typescript-angular, ngVersion=22.0.7) with the custom license header template.This is automated. .github/workflows/api-spec-sync.yml runs weekly, and opens a pull request whenever Apache Fineract‘s spec changes — with the removed operations and their call sites listed in the body. See ADR 0002. To run it on demand, use the workflow’s workflow_dispatch trigger; dry_run: true does everything except open the PR.
To do it by hand, replace public/api/fineract.json and run npm run generate-api. You can also point at a spec elsewhere via the FINERACT_SWAGGER_PATH environment variable. Because method names are stable (see above), most call sites continue to compile; only genuinely added/removed/renamed endpoints need attention.
Upstream serves the spec minified; the committed copy is Prettier-formatted, and
public/is not in.prettierignore. Runnpm run formatafter replacing the file or CI'sformatjob fails on a single 1.4 MB line.
The spec can be read straight out of the published image without booting anything:
CID=$(docker create apache/fineract:latest) docker cp "$CID:/app/resources/static/fineract.json" ./fineract.json docker rm -f "$CID"
public/api/fineract.provenance.json records where the committed spec came from: the image reference and digest, the upstream commit, info.version, path/operation/schema counts, and hashes of both the raw upstream bytes and the committed file. It is written by the sync workflow — do not edit it by hand.
If you need to customize the generated code further (e.g., adding common interceptors or changing the way models are generated), you can add more .mustache files to the templates/openapi-generator/ directory.
To prevent the generator from overwriting or creating certain files, add them to the .openapi-generator-ignore file in the root of the project. Currently ignored:
git_push.shREADME.md (inside src/app/api/).gitignore (inside src/app/api/)