第30章:CDC入門+CI+運用まとめ(最終章)🎓✅✨
この章でゴールにすること🎯✨
- CDC(Consumer-Driven Contract)の考え方を「言葉」じゃなく「流れ」で説明できる🙆♀️💡
- TypeScriptで、**最小のCDC(契約生成→検証)**を動かせる🧪✅
- CIで「契約が壊れたら止まる🚦」を作れる
- CHANGELOG / リリースノート / ADR まで含めて、守り続ける運用にできる📚🛠️✨
1) CDCってなに?🤝📜(ざっくり1分で)
CDCはひとことで言うと…
「使う側(Consumer)が “こう動いてほしい!” を契約(Contract)として残して、提供側(Provider)がそれを守れてるか確認する」 って考え方だよ😊✨ この契約をCIで回すと、“いつの間にか壊れてた😱” をかなり減らせるのが強み!⚡
代表的な実装として Pact が有名で、HTTP/RESTだけじゃなくイベント駆動にも対応してるよ📣✨ (GitHub)
2) 全体像(5行で)🗺️✨

- Consumerが「期待するやりとり」をテストで書く🧪
- その結果、**契約ファイル(pact)**が生成される📄
- 契約ファイルを共有場所(Broker)に置く📦 (Pact Docs)
- Providerは契約を取りに行って「守れてるか」を検証する✅ (Pact Docs)
- CIで落とす(守れてないならマージ/デプロイ不可🚫)
3) まずは最小のCDCをTypeScriptで体験しよ〜!🧁🧪✨
今日のお題(小さくてかわいいAPI)🍬
GET /todos/1 がこう返す、って約束にするよ👇
id: number(必須)title: string(必須)done: boolean(必須)
4) ハンズオン構成📦✨(ミニモノレポ風)
フォルダはこんな感じにするよ👇
-
cdc-demo/consumer/(使う側🧑💻)provider/(提供する側🧑🍳)
5) Provider(提供側)を用意する🍳🌐
provider は Expressで最小APIを作るよ✨
provider/package.json(イメージ)📦
{
"name": "provider",
"private": true,
"type": "module",
"scripts": {
"dev": "node src/server.js",
"test:contract": "node src/verify-pact.js"
},
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"@pact-foundation/pact": "^13.0.0"
}
}
provider/src/server.js 🌐
import express from "express";
export function createApp() {
const app = express();
app.get("/todos/1", (_req, res) => {
res.json({ id: 1, title: "buy milk", done: false });
});
return app;
}
if (import.meta.url === `file://${process.argv[1]}`) {
const app = createApp();
const port = process.env.PORT ?? 3001;
app.listen(port, () => console.log(`provider listening on ${port}`));
}
6) Consumer(利用側)で「期待」をテストにする🧑💻🧪✨
Consumerは モックProviderに対してテストを書くよ! このテストが通ると pactファイルが出力される📄✨
consumer/package.json(イメージ)📦
{
"name": "consumer",
"private": true,
"type": "module",
"scripts": {
"test": "node src/consumer.pact.test.js"
},
"devDependencies": {
"@pact-foundation/pact": "^13.0.0"
}
}
consumer/src/consumer.pact.test.js 🧪
import path from "node:path";
import { PactV3, MatchersV3 } from "@pact-foundation/pact";
const { like, integer, boolean } = MatchersV3;
const provider = new PactV3({
consumer: "todo-web",
provider: "todo-api",
dir: path.resolve(process.cwd(), "pacts")
});
async function fetchTodo1(baseUrl) {
const res = await fetch(`${baseUrl}/todos/1`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
(async () => {
await provider
.given("todo 1 exists")
.uponReceiving("a request for todo 1")
.withRequest({
method: "GET",
path: "/todos/1"
})
.willRespondWith({
status: 200,
headers: { "Content-Type": "application/json; charset=utf-8" },
body: {
id: integer(1),
title: like("buy milk"),
done: boolean(false)
}
});
await provider.executeTest(async (mockServer) => {
const todo = await fetchTodo1(mockServer.url);
if (typeof todo.id !== "number") throw new Error("id must be number");
if (typeof todo.title !== "string") throw new Error("title must be string");
if (typeof todo.done !== "boolean") throw new Error("done must be boolean");
});
console.log("✅ pact generated!");
})();
✅ ここでやってること:
- Consumerが「この形で返ってきてね💖」を定義
- その定義が **契約(pact)**として保存される
7) Providerが「契約を守れてるか」検証する✅🧪✨
Provider側は pactファイルを入力にして検証するよ。 Pactの流れは「契約を取り込んで、Providerを叩いて、期待どおりかチェック」って感じ! (GitHub)
provider/src/verify-pact.js ✅
import path from "node:path";
import { Verifier } from "@pact-foundation/pact";
import { createApp } from "./server.js";
const port = 3001;
const pactPath = path.resolve(process.cwd(), "..", "consumer", "pacts");
const app = createApp();
const server = app.listen(port, async () => {
try {
const verifier = new Verifier({
providerBaseUrl: `http://localhost:${port}`,
pactUrls: [
// consumer が出した pact ファイルを読む(最小構成)
`${pactPath}/todo-web-todo-api.json`
]
});
const output = await verifier.verifyProvider();
console.log(output);
console.log("✅ provider verified the pact!");
} catch (e) {
console.error("❌ provider verification failed!");
console.error(e);
process.exitCode = 1;
} finally {
server.close();
}
});
8) ここまでの実行手順(PowerShell想定)🪟✨
1) Consumerで契約生成📄
cd cdc-demo\consumer
npm test
2) Providerで契約検証✅
cd ..\provider
npm run test:contract
9) 「契約の共有」をちゃんとやる(Broker)📦🌍

チーム開発だと、pactファイルを手渡しはつらい😭 だから 契約を集める場所=Broker を使うのが王道!
そして強いのが Can I Deploy? 🚦 「今デプロイして安全?」をBrokerの情報から判定できる思想だよ✨ (Pact Docs)
10) CIに入れる(壊したら止める🚦)🧯✨
CIで止めたいポイント(最小セット)✅
- Consumer:契約生成(pact作る)🧪📄
- Consumer:契約を共有(Brokerへ)📦 (Pact Docs)
- Provider:契約を取得して検証✅ (Pact Docs)
- (できたら)Can I Deploy?でデプロイ可否を判定🚦 (Pact Docs)
GitHub Actionsの例(超ミニ)🤖✨
GitHub の actions/setup-node は依存のキャッシュもサポートしてるよ📦⚡(node_modules自体じゃなく、依存取得を速くする感じ) (GitHub)
consumer/.github/workflows/contract.yml(例)
name: consumer-contract
on:
push:
paths:
- "consumer/**"
jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
cache: "npm"
cache-dependency-path: "consumer/package-lock.json"
- name: Install
working-directory: consumer
run: npm ci
- name: Generate pact
working-directory: consumer
run: npm test
# ここで pact を Broker に publish する(本番運用)
# Pact Docs: "Sharing Pacts with the Pact Broker" の流れを参照✨
# (publish 自体は pact-cli 等で行うのが一般的)
Broker共有の全体の流れは Pactの “Sharing Pacts” が分かりやすいよ📦✨ (Pact Docs)
※
publishはpact-cli(Docker等)でやることが多いよ📦🐳(環境や運用方針で変えてOK) (GitHub)
11) 運用まとめ(CHANGELOG / リリースノート / ADR)📰📚✨
CDCを回し始めると、次に効いてくるのが「伝え方」だよ🫶 守る仕組みは テストだけじゃ完成しない からね!
11-1) CHANGELOG(何が変わったかの公式ノート)📝✨
Keep a Changelogは CHANGELOGの型として有名だよ📚
- 「重要な変更を、時系列で、バージョンごとに」
- 読む人(利用者)が迷子になりにくい🧭✨ (Keep a Changelog)
CHANGELOG.md(最小テンプレ)
## Changelog
## [Unreleased]
### Added
- ...
### Changed
- ...
### Fixed
- ...
## [1.2.0] - 2026-02-04
### Added
- ...
11-2) バージョン運用(SemVer)🔢✨
SemVerは「バージョン番号に意味を持たせる」ルールだよ📌 (Semantic Versioning)
- MAJOR:破壊的変更💥
- MINOR:後方互換のある機能追加➕
- PATCH:後方互換のある修正🩹
CDCと相性いい理由: “破壊的変更をしたら、契約が落ちる” → “MAJORにしよう” が自然に決まる😊✨
11-3) コミット規約(Conventional Commits)🧾✨
Conventional Commitsは、コミットメッセージを機械が読める形にするルールだよ🧠 これがあると、自動CHANGELOG生成や自動リリースがやりやすい! (Conventional Commits)
例:
feat: add filtering to listfix: handle null titlefeat!: change response schema(破壊的変更)
11-4) 自動で版上げ&CHANGELOG(Changesets / semantic-release)🦋🚀
- Changesets:版上げとCHANGELOGを扱いやすくする仕組み(特に複数パッケージに強い) (changesets-docs.vercel.app)
- semantic-release:コミット規約から次バージョン・CHANGELOG・リリースを自動化しやすい (semantic-release.gitbook.io)
「まずは手動でいい」→「慣れたら自動化」って段階でOKだよ😊✨
11-5) ADR(意思決定のメモ)🧠📌✨
ADRは「なんでこの設計にしたっけ?」を未来の自分に残すメモ! 有名な型(Nygard ADR)だと👇が基本セットだよ✨ (Architectural Decision Records)
- Title
- Status
- Context
- Decision
- Consequences
ADRの最小テンプレ(例)
## ADR 0001: Use Pact for CDC
## Status
Accepted
## Context
- ...
## Decision
- ...
## Consequences
- ...
12) 最終キャップストーン(提出物セット📦🧾)🎓✨
ここまでの全部を、1セットにまとめよう!💖
お題(どれか1つ選ぶ)🎮
A. 小さなHTTP API(例:Todo / Notes / Bookmark)🌐
B. 小さなnpmライブラリ(例:日付フォーマット / バリデータ)📦
C. 小さなイベント(例:TodoCreated みたいなメッセージ)📣
提出物(これが“運用できる契約”の完成形)✅✨
- 契約(仕様):入力/出力(JSON)とルール📜
- 互換ポリシー:破壊変更の定義、非推奨期間、サポート期限⏳
- 移行計画:旧新併存のステップ(4段くらい)🪜
- 互換性テスト:CDC(pact)+最低限のユニット🧪
- リリースノート:今回何が変わった?どう移行する?📰
- ADR 1本:「なぜその方式にした?」📌
採点(セルフチェック)💯✨
- Consumerの期待が「具体的」になってる?(曖昧ワード少なめ)
- Provider検証がCIで回る?(落ちると分かる)
- 破壊変更の扱い(MAJOR / 非推奨)が説明できる?
- CHANGELOGとリリースノートが、初見の人に優しい?🫶
- ADRに「迷いどころ」が書いてある?(未来で効く!)
13) “契約を守り続ける”ための最終チェックリスト🚦✨
PR前(開発者の儀式🧙♀️)
- 変更は「公開API/JSON/イベント」に触れてる?
- 触れてるなら、互換性はOK?(追加はOK寄り、削除や型変更は危険寄り⚠️)
- CDCテスト(Consumer/Provider)どっちが落ちる?を想像できる?
マージ前(CIの門番👮♀️)
リリース時(伝える力💌)
- CHANGELOG更新(Keep a Changelog形式だと読みやすい) (Keep a Changelog)
- バージョン番号が妥当(SemVer) (Semantic Versioning)
- 破壊変更なら移行ガイドがある🧭
14) AI活用(レビュー係にして強くする🔍🤖✨)
コピペで使えるプロンプト例だよ💖(レビューが一気に楽になる!)
- 「この変更は契約(公開API/JSON)を壊してる?壊してるなら理由と代替案も」🧠
- 「CDCの観点で、Consumerが期待するべきレスポンス例を3パターン出して」🧪
- 「このCHANGELOG、利用者が移行できる書き方になってる?不足を指摘して」📰
- 「ADRとして残すべき意思決定ポイントを箇条書きにして」📌
まとめ🎀✨
CDCは「契約を作る」だけじゃなくて、 CIで止める🚦+CHANGELOGで伝える📰+ADRで残す📌 が揃ったときに完成するよ😊💖
この第30章のキャップストーンを1回やると、もう“契約を守る運用”が一生モノになるはず!🎓✨