10 KiB
OpenAPI Clean Architecture Generator
Angular code generator that creates clean architecture boilerplate from OpenAPI/Swagger specifications. Automates the creation of DTOs, repositories, mappers, use cases and dependency injection providers.
📦 Requirements
🚀 Installation
Option 0: Prebuilt binary (no dependencies)
Download the binary for your platform from the releases page and run it directly — no Node, Bun or Java required:
# macOS (Apple Silicon)
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-macos-arm64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# macOS (Intel)
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-macos-x64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# Linux x64
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-linux-x64 -o generate-clean-arch
chmod +x generate-clean-arch && ./generate-clean-arch -i swagger.yaml
# Windows (PowerShell)
curl -L https://git.blassanto.me/blas/openapi-clean-arch-gen/releases/latest/download/generate-clean-arch-windows-x64.exe -o generate-clean-arch.exe
.\generate-clean-arch.exe -i swagger.yaml
Option 1: Install as a global CLI from npm
bun add -g @0kmpo/openapi-clean-arch-generator
Then run:
generate-clean-arch -i swagger.yaml
Option 2: Clone and use locally
git clone <repo>
cd openapi-clean-arch-generator
bun install
bun run setup # installs openapi-generator-cli globally
📖 Usage
Basic command
# Installed globally
generate-clean-arch -i swagger.yaml
# From the repository (compiled)
bun run generate -- -i swagger.yaml
# From the repository (development, no compilation needed)
bun run generate:dev -- -i swagger.yaml
Available options
Options:
-V, --version Show version
-i, --input <file> OpenAPI/Swagger file (yaml or json) [default: swagger.yaml]
-o, --output <dir> Output directory [default: ./src/app]
-t, --templates <dir> Custom templates directory [default: ./templates]
-s, --select-endpoints Interactively select tags and endpoints to generate
-c, --config <file> Use a JSON configuration file (skips interactive prompts)
--init-config [file] Generate a JSON configuration file instead of generating code
--skip-install Skip dependency installation
--skip-lint Skip post-generation linting and formatting
--dry-run Simulate without writing files
-h, --help Show help
Examples
# Generate from swagger.yaml into src/app
generate-clean-arch -i swagger.yaml -o ./src/app
# Interactively select tags/endpoints
generate-clean-arch -i api.yaml -s
# Use custom templates
generate-clean-arch -i api.yaml -t ./my-templates
# Dry run (no files written)
generate-clean-arch -i swagger.yaml --dry-run
# Skip linting after generation
generate-clean-arch -i swagger.yaml --skip-lint
# Generate a config file to reuse later
generate-clean-arch --init-config generation-config.json
# Run using a config file (no interactive prompts)
generate-clean-arch -c generation-config.json
# Full example with all options
generate-clean-arch -i ./docs/api.yaml -o ./frontend/src/app -t ./custom-templates
📁 Generated Structure
The generator creates the following structure following Clean Architecture:
src/app/
├── data/ # Data layer
│ ├── dtos/ # Data Transfer Objects
│ │ ├── node/
│ │ │ ├── node.dto.ts
│ │ │ └── node.dto.mock.ts
│ │ ├── order-type/
│ │ │ ├── order-type.dto.ts
│ │ │ └── order-type.dto.mock.ts
│ │ └── supply-mode/
│ │ ├── supply-mode.dto.ts
│ │ └── supply-mode.dto.mock.ts
│ ├── repositories/ # Repository implementations
│ │ ├── node.repository.impl.ts
│ │ ├── node.repository.impl.mock.ts
│ │ ├── node.repository.impl.spec.ts
│ │ ├── order-type.repository.impl.ts
│ │ ├── order-type.repository.impl.mock.ts
│ │ ├── order-type.repository.impl.spec.ts
│ │ └── ...
│ └── mappers/ # DTO → Entity transformers
│ ├── node.mapper.ts
│ ├── node.mapper.spec.ts
│ ├── order-type.mapper.ts
│ ├── order-type.mapper.spec.ts
│ └── ...
├── domain/ # Domain layer
│ ├── repositories/ # Repository contracts
│ │ ├── node.repository.contract.ts
│ │ └── ...
│ └── use-cases/ # Use cases
│ ├── node/
│ │ ├── node.use-cases.contract.ts
│ │ ├── node.use-cases.impl.ts
│ │ ├── node.use-cases.mock.ts
│ │ └── node.use-cases.impl.spec.ts
│ └── ...
├── di/ # Dependency injection
│ ├── repositories/ # Repository providers
│ │ ├── node.repository.provider.ts
│ │ ├── node.repository.provider.mock.ts
│ │ └── ...
│ └── use-cases/ # Use case providers
│ ├── node.use-cases.provider.ts
│ ├── node.use-cases.provider.mock.ts
│ └── ...
└── entities/ # Domain entities
└── models/
├── node.model.ts
├── node.model.mock.ts
├── node.model.spec.ts
└── ...
🔧 Template Customization
Templates live in templates/ and use Mustache syntax. Override them by passing your own directory with -t.
| Template | Generates |
|---|---|
model.mustache |
DTOs |
model.mock.mustache |
DTO mocks |
dto.mock.mustache |
DTO mocks (alternative) |
model-entity.mustache |
Domain entity models |
model-entity.spec.mustache |
Entity model specs |
mapper.mustache |
DTO → Entity mappers |
mapper.spec.mustache |
Mapper specs |
api.repository.contract.mustache |
Repository contracts |
api.repository.impl.mustache |
Repository implementations |
api.repository.impl.mock.mustache |
Repository mocks |
api.repository.impl.spec.mustache |
Repository specs |
api.use-cases.contract.mustache |
Use case contracts |
api.use-cases.impl.mustache |
Use case implementations |
api.use-cases.mock.mustache |
Use case mocks |
api.use-cases.impl.spec.mustache |
Use case specs |
repository.provider.mustache |
Repository DI providers |
repository.provider.mock.mustache |
Repository provider mocks |
use-cases.provider.mustache |
Use case DI providers |
use-cases.provider.mock.mustache |
Use case provider mocks |
Available Mustache variables
{{classname}} - Class name (e.g. "OrderType")
{{classVarName}} - camelCase name (e.g. "orderType")
{{classFilename}} - File name (e.g. "order-type")
{{constantName}} - UPPER_SNAKE_CASE constant (e.g. "ORDER_TYPE")
{{description}} - Schema description
{{httpMethod}} - HTTP method (get, post, put, delete…)
{{path}} - Endpoint path
{{nickname}} - Method name
{{allParams}} - All endpoint parameters
{{returnType}} - Return type
{{vars}} - Model variables
📊 Generation Report
After each run a generation-report.json file is created:
{
"timestamp": "2025-01-15T10:30:00.000Z",
"tags": 3,
"endpoints": 8,
"tagDetails": [
{ "name": "User", "description": "User operations", "endpoints": 3 },
{ "name": "Product", "description": "Product operations", "endpoints": 2 }
],
"outputDirectory": "./src/app",
"linting": {
"prettier": { "ran": true, "filesFormatted": 42 },
"eslint": { "ran": true, "filesFixed": 42 }
},
"structure": {
"dtos": 15,
"repositories": 9,
"mappers": 5,
"useCases": 6,
"providers": 12,
"mocks": 18,
"specs": 14
}
}
🎯 Angular Integration Example
1. Generate code
generate-clean-arch -i ./docs/api.yaml -o ./src/app
2. Register providers
In your app.config.ts (Angular 17+ standalone):
import { ApplicationConfig } from '@angular/core';
import { NodeRepositoryProvider } from './di/repositories/node.repository.provider';
import { NodeUseCasesProvider } from './di/use-cases/node.use-cases.provider';
export const appConfig: ApplicationConfig = {
providers: [
NodeRepositoryProvider,
NodeUseCasesProvider,
// ... rest of generated providers
]
};
3. Use in components
import { Component, inject } from '@angular/core';
import { NODE_USE_CASES } from './domain/use-cases/node/node.use-cases.contract';
@Component({
selector: 'app-nodes',
template: `...`
})
export class NodesComponent {
readonly #nodeUseCases = inject(NODE_USE_CASES);
loadNodes(): void {
this.#nodeUseCases.getNodes().subscribe((nodes) => {
console.log(nodes);
});
}
}
🐛 Troubleshooting
openapi-generator-cli not found
bun run setup
# or manually:
bun add -g @openapitools/openapi-generator-cli
swagger.yaml file not found
Specify the correct path with -i:
generate-clean-arch -i ./path/to/your/api.yaml
Path aliases @/ not resolving
Configure the aliases in your Angular project's tsconfig.json:
{
"compilerOptions": {
"paths": {
"@/*": ["src/app/*"]
}
}
}
Templates not generating expected code
- Make sure your templates are in
./templates/or pass the path with-t - Check the Mustache syntax
- Use
--dry-runto simulate without writing files
📝 Notes
- The generator produces ready-to-use
.tsfiles, it does not compile them - Providers must be registered manually in your Angular module or config
- Requires Angular 17+ (uses the
inject()function) - Compatible with both standalone and module-based projects
🤝 Contributing
Found a bug or have an improvement? Open an issue or PR in the repository.
📄 License
MIT