Skip to content
Development
Skill

/openapi-first

Use when the project follows API-first / OpenAPI-first approach: generating controller interfaces, DTOs, and clients from an OpenAPI spec. Use when you see openapi.yaml, openapi-generator-maven-plugin, or ApiDelegate pattern in the project.

From plugin
spring-boot-skills
33733 skills

Claude Code

$ npx -y skills add rrezartprebreza/spring-boot-skills --skill openapi-first --agent claude-code

SKILL.md

openapi-first.SKILL.md
name: openapi-first
description: >
  Use when the project follows API-first / OpenAPI-first approach: generating controller
  interfaces, DTOs, and clients from an OpenAPI spec. Use when you see openapi.yaml,
  openapi-generator-maven-plugin, or ApiDelegate pattern in the project.

OpenAPI-First Development

Maven Plugin Setup

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>7.5.0</version>
    <executions>
        <execution>
            <goals><goal>generate</goal></goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
                <generatorName>spring</generatorName>
                <apiPackage>com.example.api</apiPackage>
                <modelPackage>com.example.api.model</modelPackage>
                <configOptions>
                    <delegatePattern>true</delegatePattern>      <!-- implement delegate, not controller -->
                    <interfaceOnly>false</interfaceOnly>
                    <useSpringBoot3>true</useSpringBoot3>
                    <useTags>true</useTags>
                    <dateLibrary>java8</dateLibrary>
                    <openApiNullable>false</openApiNullable>
                    <skipDefaultInterface>false</skipDefaultInterface> <!-- must stay false with delegatePattern: the controller instantiates a no-op delegate -->
                </configOptions>
                <!-- NOT generateSupportingFiles=true: that adds a second @SpringBootApplication main class
                     (repackage fails: "Unable to find a single main class") and a SpringDocConfiguration -->
                <supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
                <modelNameSuffix>Dto</modelNameSuffix> <!-- OrderDto, not Order: no clash with domain types -->
                <output>${project.build.directory}/generated-sources/openapi</output>
            </configuration>
        </execution>
    </executions>
</plugin>

OpenAPI Spec Example

# src/main/resources/openapi.yaml
openapi: 3.0.3
info:
  title: Order Service API
  version: 1.0.0

paths:
  /api/v1/orders:
    post:
      tags: [Orders]
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '400':
          $ref: '#/components/responses/ValidationError'

    get:
      tags: [Orders]
      operationId: listOrders
      parameters:
        - name: page
          in: query
          schema: { type: integer, default: 0 }
        - name: size
          in: query
          schema: { type: integer, default: 20 }
      responses:
        '200':
          description: Paginated orders
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderPage'

components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [customerEmail, items]
      properties:
        customerEmail:
          type: string
          format: email
        items:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/OrderItemRequest'

    OrderResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELLED]
        customerEmail:
          type: string
        createdAt:
          type: string
          format: date-time

    OrderItemRequest:
      type: object
      required: [productId, quantity]
      properties:
        productId:
          type: string
          format: uuid
        quantity:
          type: integer
          minimum: 1

    OrderPage:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/OrderResponse'
        page:
          type: integer
        size:
          type: integer
        totalElements:
          type: integer
          format: int64

    ApiError:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: array
          items:
            type: string

  responses:
    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'

Implementing the Delegate

// Generated: OrdersApi interface with delegate
// Your implementation — never modify generated files

@Service
@RequiredArgsConstructor
public class OrdersApiDelegateImpl implements OrdersApiDelegate {

    private final OrderService orderService;

    @Override
    public ResponseEntity<OrderResponse> createOrder(CreateOrderRequest request) {
        Order order = orderService.createOrder(request);
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(OrderApiMapper.toResponse(order));
    }

    @Override
    public ResponseEntity<OrderPage> listOrders(Integer page, Integer size) {
        Page<Order> orders = orderService.findAll(PageRequest.of(page, size));
        return ResponseEntity.ok(OrderApiMapper.toPage(orders));
    }
}

.gitignore — Never Commit Generated Files

target/generated-sources/openapi/

Gotchas

  • Agent modifies generated controller files — NEVER modify generated code, implement delegate
  • Agent generates code without `useSpringBoot3=true` — uses old `javax.*` imports
  • Agent commits generated sources — add to `.gitignore`, generate on build
  • Agent sets `skipDefaultInterface=true` with `delega
Read more
@rrezartprebreza
Ships withspring-boot-skills

Production-grade Claude Code and Codex skills for Spring Boot developers

Stars on GitHub

Momentum

stars in total
337
Star history of rrezartprebreza/spring-boot-skills on GitHub, a chart by star-history.com

Other skills on spring-boot-skills.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about openapi-first.

Which coding agents can use openapi-first?
openapi-first installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.