Skip to content

Commit 5a64235

Browse files
committed
feat: Add OpenAPI contract validation CI and shared TypeScript types
- Add GitHub Action workflow for API contract drift detection - Create shared/contracts infrastructure for TypeScript types - Add generate:types script with openapi-typescript - Update frontend components with typed imports - Add @shared path alias to tsconfig - Add API Contracts badge to README
1 parent 9ddf982 commit 5a64235

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# =============================================================================
2+
# API Contract Validation Workflow
3+
# =============================================================================
4+
# This workflow ensures TypeScript types stay in sync with the FastAPI backend.
5+
# It starts the backend, regenerates types from OpenAPI spec, and fails if
6+
# the generated types differ from committed types.
7+
#
8+
# Runs on: Push to main, PRs to main, Manual trigger
9+
# =============================================================================
10+
11+
name: API Contract Validation
12+
13+
on:
14+
push:
15+
branches: [main]
16+
paths:
17+
- 'backend/**'
18+
- 'shared/contracts/**'
19+
- 'scripts/generate-api-types.js'
20+
pull_request:
21+
branches: [main]
22+
paths:
23+
- 'backend/**'
24+
- 'shared/contracts/**'
25+
workflow_dispatch: # Allow manual trigger
26+
27+
jobs:
28+
validate-contracts:
29+
name: Validate API Contracts
30+
runs-on: ubuntu-latest
31+
32+
steps:
33+
# -----------------------------------------------------------------------
34+
# Step 1: Checkout repository
35+
# -----------------------------------------------------------------------
36+
- name: Checkout repository
37+
uses: actions/checkout@v4
38+
39+
# -----------------------------------------------------------------------
40+
# Step 2: Setup Python for FastAPI backend
41+
# -----------------------------------------------------------------------
42+
- name: Setup Python
43+
uses: actions/setup-python@v5
44+
with:
45+
python-version: '3.10'
46+
cache: 'pip'
47+
48+
# -----------------------------------------------------------------------
49+
# Step 3: Install Python dependencies
50+
# -----------------------------------------------------------------------
51+
- name: Install Python dependencies
52+
run: |
53+
pip install -r requirements.txt
54+
55+
# -----------------------------------------------------------------------
56+
# Step 4: Setup Node.js for TypeScript generation
57+
# -----------------------------------------------------------------------
58+
- name: Setup Node.js
59+
uses: actions/setup-node@v4
60+
with:
61+
node-version: '18'
62+
cache: 'npm'
63+
64+
# -----------------------------------------------------------------------
65+
# Step 5: Install Node dependencies
66+
# -----------------------------------------------------------------------
67+
- name: Install Node dependencies
68+
run: npm install
69+
70+
# -----------------------------------------------------------------------
71+
# Step 6: Start FastAPI backend in background
72+
# We need the backend running to fetch the OpenAPI spec
73+
# -----------------------------------------------------------------------
74+
- name: Start FastAPI backend
75+
run: |
76+
cd backend
77+
python app.py &
78+
# Wait for backend to be ready
79+
echo "Waiting for backend to start..."
80+
sleep 10
81+
# Verify backend is responding
82+
curl --retry 5 --retry-delay 2 --retry-connrefused http://localhost:8000/health || exit 1
83+
echo "Backend is ready!"
84+
85+
# -----------------------------------------------------------------------
86+
# Step 7: Backup existing types (if committed)
87+
# -----------------------------------------------------------------------
88+
- name: Backup existing types
89+
run: |
90+
if [ -f shared/contracts/index.d.ts ]; then
91+
cp shared/contracts/index.d.ts shared/contracts/index.d.ts.backup
92+
echo "Backed up existing types"
93+
else
94+
echo "No existing types to backup (first run)"
95+
touch shared/contracts/index.d.ts.backup
96+
fi
97+
98+
# -----------------------------------------------------------------------
99+
# Step 8: Fetch OpenAPI spec and regenerate types
100+
# -----------------------------------------------------------------------
101+
- name: Regenerate TypeScript types
102+
run: |
103+
npm run generate:types
104+
echo "Types regenerated successfully"
105+
106+
# -----------------------------------------------------------------------
107+
# Step 9: Compare generated types with committed types
108+
# Fails if there's any difference (drift detected)
109+
# -----------------------------------------------------------------------
110+
- name: Check for type drift
111+
run: |
112+
if [ -s shared/contracts/index.d.ts.backup ]; then
113+
echo "Comparing generated types with committed types..."
114+
if diff -q shared/contracts/index.d.ts shared/contracts/index.d.ts.backup > /dev/null 2>&1; then
115+
echo "✅ No drift detected - types are in sync!"
116+
else
117+
echo "❌ DRIFT DETECTED - Types have changed!"
118+
echo ""
119+
echo "The OpenAPI spec has changed but committed types are outdated."
120+
echo "Run 'npm run generate:types' locally and commit the updated types."
121+
echo ""
122+
echo "=== Diff ==="
123+
diff shared/contracts/index.d.ts shared/contracts/index.d.ts.backup || true
124+
exit 1
125+
fi
126+
else
127+
echo "⚠️ No committed types found - this is expected for first run"
128+
echo "Generated types are at: shared/contracts/index.d.ts"
129+
fi
130+
131+
# -----------------------------------------------------------------------
132+
# Step 10: Upload generated types as artifact (for debugging)
133+
# -----------------------------------------------------------------------
134+
- name: Upload generated types
135+
uses: actions/upload-artifact@v4
136+
if: always()
137+
with:
138+
name: generated-types
139+
path: |
140+
shared/contracts/index.d.ts
141+
shared/contracts/openapi.json
142+
retention-days: 7

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
55
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
66
[![Build Status](https://img.shields.io/github/actions/workflow/status/cliff-de-tech/linkedin-post-bot/ci.yml?branch=main&label=build)](https://github.com/cliff-de-tech/linkedin-post-bot/actions)
7+
[![API Contracts](https://img.shields.io/github/actions/workflow/status/cliff-de-tech/linkedin-post-bot/api-contracts.yml?branch=main&label=api%20contracts)](https://github.com/cliff-de-tech/linkedin-post-bot/actions/workflows/api-contracts.yml)
78
[![Next.js](https://img.shields.io/badge/Next.js-14-black?logo=next.js)](https://nextjs.org/)
89
[![Python](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](https://python.org/)
910
[![FastAPI](https://img.shields.io/badge/FastAPI-0.100+-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/)
1011
[![Tailwind CSS](https://img.shields.io/badge/Tailwind-3.3-38B2AC?logo=tailwind-css&logoColor=white)](https://tailwindcss.com/)
1112

1213
---
1314

15+
1416
## Why This Tool Exists
1517

1618
Most developers are active on GitHub but invisible on LinkedIn. Writing engaging posts takes time, and consistency is hard. This tool bridges the gap by:

0 commit comments

Comments
 (0)