Creates, extends, and implements OpenAPI 3.x specifications. Three modes – create spec (from scratch), extend spec (add to existing spec), and generate code (Java classes in BCE pattern). Use this skill for "create an API spec", "define the API", "extend the API", "generate code from the OpenAPI spec", "new OpenAPI spec" or when a REST API needs to be designed.
Creates, extends, and implements OpenAPI 3.x specifications. Supports three modes: create spec (from scratch), extend spec (add to existing spec), and generate code (Java classes in BCE pattern from a spec).
Philosophy: The OpenAPI spec is the contract. Whether it's being created, extended, or implemented – the contract is at the center. Design first, then build.
Create a new API spec for an order service
Extend the API in api/orders.yaml with a product endpoint
Generate code from the OpenAPI spec in api/openapi.yaml
Define a REST API for orders and products
Before every execution:
- Check
.claude/lessons-learned.md
The three modes (create, extend, generate code) lead to completely different workflows. Clarify the mode first with AskUserQuestion so no unnecessary work is done.
What would you like to do?
Options:
Jump to the corresponding steps based on mode:
Ask with AskUserQuestion:
| # | Question | Hint |
|---|---|---|
| 1 | API name | Short name, becomes filename: api/<name>.yaml |
| 2 | Description | One sentence: What does this API do? |
| 3 | Base path | e.g. /api/v1 – Default: /api/v1 |
Second question via AskUserQuestion:
What auth scheme should the API use?
Options:
First: Scan existing entities in the project (directories entity/, entity/model/, entity/dto/).
If entities are found, offer via AskUserQuestion (multiSelect):
The following entities were found in the project. Which should be adopted into the API?
Options: list found entity classes (max 4, rest via "Other").
Then: For each new data model, ask interactively:
| # | Question | Hint |
|---|---|---|
| 1 | Schema name | PascalCase, e.g. Order, Product, OrderItem |
| 2 | Fields | Name, type (string, integer, number, boolean, array, $ref), required? |
| 3 | Relationships | References to other schemas ($ref: '#/components/schemas/...') |
Repeat the query until the user signals that all models are defined.
Request/Response variants: For each schema, check if separate request and response variants are needed (e.g. CreateOrderRequest without id, OrderResponse with id and timestamps).
Per data model, ask via AskUserQuestion:
What operations should the resource [SchemaName] support?
Options (multiSelect):
For each endpoint, define:
/orders, /orders/{id})page, size, filtering)Output compact summary:
API: Order Service (v1.0.0)
Auth: Bearer JWT
Base: /api/v1
Schemas (4):
CreateOrderRequest, OrderResponse, ProductResponse, ErrorResponse
Endpoints (5):
GET /api/v1/orders → OrderResponse[]
POST /api/v1/orders → OrderResponse
GET /api/v1/orders/{id} → OrderResponse
GET /api/v1/products → ProductResponse[]
GET /api/v1/products/{id} → ProductResponse
File: api/order-service.yaml
Generate?
Only after confirmation generate the YAML file. Template: templates/openapi-spec.yaml.template.
After generation, ask:
Should code be generated directly from the new spec?
If yes → continue with Steps 1–4 (generate code).
Ask for path to existing spec (if not passed as argument). Read and analyze spec:
Existing spec: api/orders.yaml (v1.0.0)
Existing schemas (3):
CreateOrderRequest, OrderResponse, ErrorResponse
Existing endpoints (3):
GET /api/v1/orders
POST /api/v1/orders
GET /api/v1/orders/{id}
Like Step A2, but additionally show existing schemas as reference.
Existing schemas can be used in $ref references of new schemas.
Like Step A3, but only for new resources or additional operations on existing resources.
Summary shows only the new elements:
New schemas (2):
ProductResponse, CreateProductRequest
New endpoints (2):
GET /api/v1/products → ProductResponse[]
POST /api/v1/products → ProductResponse
Existing spec will be extended: api/orders.yaml
Proceed?
Read existing YAML, add new paths and schemas, overwrite file. Existing paths and schemas remain unchanged.
Before generation – if not already known:
If the skill is called with arguments (/openapi api/openapi.yaml), $ARGUMENTS is used as the spec path.
| # | Question | Hint |
|---|---|---|
| 1 | Path to OpenAPI spec | .yaml, .yml or .json; relative to project root. Omitted if passed as $ARGUMENTS. |
| 2 | Framework | Spring Boot or Quarkus |
| 3 | groupId / package | e.g. com.example.orders |
| 4 | DTO style | Java Record (default) or Class with Lombok |
| 5 | Include security annotations? | Yes → @RolesAllowed / @PreAuthorize from spec security section |
Read the OpenAPI spec and extract the following:
| What | From |
|---|---|
| All paths + methods (GET, POST, PUT, DELETE, PATCH) | paths |
| Request bodies (schema references) | requestBody.content.*.schema |
| Response schemas (all status codes) | responses.*.content.*.schema |
| Path and query parameters | parameters |
| Schema definitions | components/schemas |
| Security definitions | components/securitySchemes + security per operation |
| Tags | tags – used for grouping |
Before code generation, output a brief overview and get confirmation:
Found endpoints: 5
Found schemas (DTOs): 4
Framework: Quarkus
Package: com.example.orders
Planned files:
boundary/rest/OrderResource.java (3 endpoints: GET /orders, POST /orders, GET /orders/{id})
boundary/rest/ProductResource.java (2 endpoints: GET /products, GET /products/{id})
entity/dto/OrderRequest.java (Record)
entity/dto/OrderResponse.java (Record)
entity/dto/ProductResponse.java (Record)
entity/dto/ErrorResponse.java (Record)
Proceed?
Order: DTOs first, then endpoints, then service stubs.
@Nullable (JSpecify) + Optional<T> only when explicitly neededminLength / maxLength → @Sizeminimum / maximum → @Min / @Maxrequired → @NotNull / @NotBlankpattern → @Patternenum types in the same packageNaming convention:
| Spec Schema | Java Class |
|---|---|
OrderRequest | OrderRequest.java (Record) |
OrderResponse | OrderResponse.java (Record) |
CreateOrderRequest | CreateOrderRequest.java (Record) |
| Anonymous inline schema | Derive a descriptive name |
Grouping by OpenAPI tag: One tag → one class.
No tag → name class after first path segment (/orders/* → OrderResource).
Spring Boot Controller:
@RestController
@RequestMapping("/path")
@Validated
public class {{TAG}}Controller {
private final {{TAG}}Service {{tag}}Service;
// Constructor injection
@GetMapping("/{id}")
public ResponseEntity<{{ResponseDTO}}> findById(@PathVariable Long id) {
throw new UnsupportedOperationException("Not implemented yet");
}
}
Quarkus Resource:
@Path("/path")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class {{TAG}}Resource {
@Inject
{{TAG}}Service {{tag}}Service;
@GET
@Path("/{id}")
public {{ResponseDTO}} findById(@PathParam("id") Long id) {
throw new UnsupportedOperationException("Not implemented yet");
}
}
For each controller/resource, a matching empty service stub is created:
@ApplicationScoped // Quarkus
// @Service // Spring Boot
public class {{TAG}}Service {
public {{ResponseDTO}} findById(Long id) {
throw new UnsupportedOperationException("Not implemented yet");
}
}
| File | Description |
|---|---|
.claude/lessons-learned.md | Findings and corrections |
| templates/openapi-spec.yaml.template | OpenAPI spec template (Mode A/B) |
| templates/spring/Controller.java.template | Spring Boot controller template (Mode C) |
| templates/quarkus/Resource.java.template | Quarkus resource template (Mode C) |
| templates/Dto.java.template | DTO template (Java Record, Mode C) |
| templates/Service.java.template | Service stub template (Mode C) |
| Feature | Supported | Note |
|---|---|---|
| OpenAPI 3.0.x / 3.1.x | Yes | |
$ref to components/schemas | Yes | Resolved |
| Inline schemas | Yes | Name is derived |
oneOf / anyOf / allOf | Partial | Simplified to interface or common base class |
| Path parameters | Yes | |
| Query parameters | Yes | |
| Header parameters | Yes | |
| Request body | Yes | |
| Response body | Yes | Only 2xx responses |
Security (bearer, oauth2) | Yes | → @RolesAllowed / @PreAuthorize when enabled |
| Multipart / file upload | Partial | MultipartFormDataInput (Quarkus) / MultipartFile (Spring) |
| Webhooks | No | Not supported |
{{GROUP_ID}}.boundary.rest (endpoints), {{GROUP_ID}}.entity.dto (DTOs), {{GROUP_ID}}.control (service stubs)UnsupportedOperationException as placeholder – signals "not yet implemented"@author Co-Author: Claude (claude-sonnet-4-6, Anthropic) – generated via openapi[spec-feature] optional – business requirements
|
[openapi] <-- create spec OR extend OR generate code
|
[java-scaffold] framework: DB, messaging, infra – do NOT regenerate REST/DTOs
|
[review] code review
|
[doc] project documentation
Important for java-scaffold: If openapi has already generated code,
do not regenerate boundary/rest/ and entity/dto/ classes – only generate the rest
of the project framework (pom.xml, docker-compose, application.properties, Flyway, architecture test).