openapi-first について
OpenAPI 仕様から API を構築する Java・Spring チーム向けの開発スキルです。コード生成、デリゲートによる実装、ジェネレーター設定の注意点を扱います。
主な機能
- 01OpenAPI Generator Maven 設定
- 02API 仕様の構成
- 03デリゲートによる実装
- 04生成ソースの管理
- 05ジェネレーター設定のガイダンス
活用シーン
- 01OpenAPI ファイルから Spring API コードを生成
- 02生成コントローラーを変更せずに操作を実装
- 03生成ソースをバージョン管理から除外
- 04Spring Boot 3 の生成設定を確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rrezartprebreza/ spring-boot-skills --skill openapi-firstインストール後、Claude Code で/openapi-firstを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlexamples/bad-delegate-impl.javagood-delegate-impl.javatemplates/openapi.yaml詳細
OpenAPI ファースト開発
Maven プラグインのセットアップ
<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>
<interfaceOnly>false</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<useTags>true</useTags>
<dateLibrary>java8</dateLibrary>
<openApiNullable>false</openApiNullable>
<skipDefaultInterface>false</skipDefaultInterface>
</configOptions>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
<modelNameSuffix>Dto</modelNameSuffix>
<output>${project.build.directory}/generated-sources/openapi</output>
</configuration>
</execution>
</executions>
</plugin>
OpenAPI 仕様の例
# 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'
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 — 生成ファイルは絶対にコミットしない
target/generated-sources/openapi/
注意点
- エージェントが生成されたコントローラーファイルを変更する — 生成コードは絶対に変更せず、delegate を実装してください
- エージェントが
useSpringBoot3=trueを指定せずにコードを生成する — 古いjavax.*インポートが使用されます - エージェントが生成されたソースをコミットする —
.gitignoreに追加し、ビルド時に生成してください - エージェントが
delegatePattern=trueとともにskipDefaultInterface=trueを設定する — 生成されたコントローラーが何もしない delegate をインスタンス化するため、コンパイルできなくなります。falseのままにし、すべての操作をコントラクトテストで網羅してください - エージェントが
generateSupportingFiles=trueを設定する — 2 つ目の@SpringBootApplicationと SpringDoc の設定が生成されます。supportingFilesToGenerateにはApiUtil.javaのみを指定してください - エージェントが生成モデルと手書きモデルを混在させる — それぞれを分けてください
コメント
Markdown 対応