Skip to content

Commit b561543

Browse files
committed
Add GitHub Pages docs site
1 parent 7c78751 commit b561543

12 files changed

Lines changed: 1293 additions & 0 deletions

.github/workflows/pages.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Deploy docs to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
paths:
7+
- "docs/**"
8+
- ".github/workflows/pages.yml"
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
pages: write
14+
id-token: write
15+
16+
concurrency:
17+
group: "pages"
18+
cancel-in-progress: false
19+
20+
jobs:
21+
deploy:
22+
environment:
23+
name: github-pages
24+
url: ${{ steps.deployment.outputs.page_url }}
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
30+
- name: Setup Pages
31+
uses: actions/configure-pages@v5
32+
33+
- name: Upload docs
34+
uses: actions/upload-pages-artifact@v3
35+
with:
36+
path: docs
37+
38+
- name: Deploy
39+
id: deployment
40+
uses: actions/deploy-pages@v4

docs/.nojekyll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
---
2+
title: "Turn an OpenAPI Spec Into a CLI People Can Actually Use"
3+
description: "OpenAPI specs are not only for SDKs and docs. They can generate human-facing Python CLIs with typed flags, auth, table output, and nested request bodies flattened into command options."
4+
tags: ["openapi", "python", "cli", "fastapi", "developer-tools"]
5+
canonical_url: "https://github.com/shivaam/openapi-cli-gen"
6+
---
7+
8+
# Turn an OpenAPI Spec Into a CLI People Can Actually Use
9+
10+
Most teams already have more API structure than they use.
11+
12+
If you have a FastAPI app, a Swagger spec, or any OpenAPI 3.x document, the spec
13+
already knows your paths, methods, query parameters, path parameters, request
14+
bodies, auth schemes, enums, and validation rules.
15+
16+
And yet, a lot of internal API workflows still end up as copied `curl` commands:
17+
18+
```bash
19+
curl -X POST "$API_URL/users" \
20+
-H "Authorization: Bearer $TOKEN" \
21+
-H "Content-Type: application/json" \
22+
-d '{"name":"Jane","email":"jane@example.com","address":{"city":"NYC","state":"NY"}}'
23+
```
24+
25+
That works, but it is not a great interface.
26+
27+
It is easy to mistype. It is hard to discover. It asks humans to write JSON even
28+
when the schema already knows the fields. It also tends to sprawl across
29+
runbooks, Slack messages, CI jobs, and one-off scripts.
30+
31+
I built [`openapi-cli-gen`](https://github.com/shivaam/openapi-cli-gen) to
32+
explore a narrower idea:
33+
34+
> What if an OpenAPI spec could become a human-facing command line app?
35+
36+
## The Basic Idea
37+
38+
Instead of making users paste JSON:
39+
40+
```bash
41+
curl -X POST /api/users \
42+
-H "Content-Type: application/json" \
43+
-d '{"name":"Jane","address":{"city":"NYC","state":"NY"}}'
44+
```
45+
46+
generate commands like this:
47+
48+
```bash
49+
mycli users create \
50+
--name Jane \
51+
--address.city NYC \
52+
--address.state NY
53+
```
54+
55+
The OpenAPI spec provides the structure. The generated CLI exposes that
56+
structure as command groups, options, environment variables, and output formats.
57+
58+
## Why Not Just Use OpenAPI Generator?
59+
60+
OpenAPI Generator is excellent when you need SDKs, server stubs, models, or
61+
language-specific client libraries.
62+
63+
That is not the same job.
64+
65+
`openapi-cli-gen` is aimed at a smaller workflow:
66+
67+
- give support teams repeatable commands;
68+
- give ops teams admin tools;
69+
- give QA teams setup and cleanup commands;
70+
- give API maintainers a quick internal CLI;
71+
- give users a scriptable wrapper around a REST API.
72+
73+
The distinction is:
74+
75+
```text
76+
SDK generator: produce code developers import.
77+
CLI generator: produce commands humans and scripts run.
78+
```
79+
80+
Both can be useful. They just serve different moments.
81+
82+
## FastAPI Is A Natural Fit
83+
84+
FastAPI publishes an OpenAPI spec at `/openapi.json` by default.
85+
86+
That means a running FastAPI app can become a CLI without adding a separate API
87+
description file:
88+
89+
```bash
90+
openapi-cli-gen generate \
91+
--spec http://localhost:8000/openapi.json \
92+
--name internal-admin
93+
```
94+
95+
Then:
96+
97+
```bash
98+
cd internal-admin
99+
pip install -e .
100+
internal-admin --help
101+
```
102+
103+
For internal tools, this can be enough to turn an API into something support,
104+
ops, and QA can actually use.
105+
106+
## Nested Request Bodies Are The Pain Point
107+
108+
The easy part of an API CLI is path and query parameters.
109+
110+
The annoying part is request bodies.
111+
112+
FastAPI and Pydantic apps often use nested models:
113+
114+
```python
115+
from pydantic import BaseModel
116+
117+
118+
class Address(BaseModel):
119+
city: str
120+
state: str
121+
122+
123+
class UserCreate(BaseModel):
124+
name: str
125+
email: str
126+
address: Address
127+
```
128+
129+
The generated command can expose nested fields as dot flags:
130+
131+
```bash
132+
internal-admin users create \
133+
--name Jane \
134+
--email jane@example.com \
135+
--address.city NYC \
136+
--address.state NY
137+
```
138+
139+
For complex cases, JSON fallback is still available:
140+
141+
```bash
142+
internal-admin users create \
143+
--address '{"city":"NYC","state":"NY"}'
144+
```
145+
146+
That combination is important. Simple cases should feel simple. Complex cases
147+
should still be possible.
148+
149+
## Runtime Mode vs Generated Packages
150+
151+
Sometimes you just want to try a spec:
152+
153+
```bash
154+
openapi-cli-gen run \
155+
--spec https://catfact.ninja/docs \
156+
--base-url https://catfact.ninja \
157+
facts get-random
158+
```
159+
160+
Sometimes you want a real package:
161+
162+
```bash
163+
openapi-cli-gen generate \
164+
--spec https://api.example.com/openapi.json \
165+
--name example-cli
166+
```
167+
168+
The generated package can be installed locally or shipped to users:
169+
170+
```bash
171+
cd example-cli
172+
pip install -e .
173+
example-cli --help
174+
```
175+
176+
## Where This Helps
177+
178+
Generated CLIs seem most useful for APIs with repeated operational workflows:
179+
180+
- internal admin APIs;
181+
- FastAPI services;
182+
- self-hosted apps;
183+
- search and vector databases;
184+
- import/export tools;
185+
- media libraries;
186+
- provider sync/debug APIs;
187+
- QA and smoke-test endpoints.
188+
189+
The wrapper does not need to replace an SDK. It gives people a terminal surface
190+
when a terminal surface is the right shape.
191+
192+
## The Tradeoff
193+
194+
Generated CLIs inherit the shape of the OpenAPI spec.
195+
196+
If the spec has clean tags and operation IDs, commands can feel good quickly. If
197+
the spec has long generated operation IDs, the commands may need wrapper-level
198+
aliases for the most common workflows.
199+
200+
That is still a useful starting point:
201+
202+
1. generate the full API surface;
203+
2. verify real commands;
204+
3. add aliases only where humans actually need them.
205+
206+
## Try It
207+
208+
Install:
209+
210+
```bash
211+
pipx install openapi-cli-gen
212+
```
213+
214+
Inspect a spec:
215+
216+
```bash
217+
openapi-cli-gen inspect \
218+
--spec https://petstore3.swagger.io/api/v3/openapi.json
219+
```
220+
221+
Generate a CLI:
222+
223+
```bash
224+
openapi-cli-gen generate \
225+
--spec https://api.example.com/openapi.json \
226+
--name mycli
227+
```
228+
229+
Project:
230+
231+
<https://github.com/shivaam/openapi-cli-gen>
232+
233+
I am especially interested in real OpenAPI specs that make generated CLIs
234+
awkward: unusual auth, nested bodies, arrays of objects, multipart uploads,
235+
unions, or very large schemas. Those are the cases that make the tool better.

docs/blog/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Blog Drafts
2+
3+
Long-form posts for GitHub Pages, dev.to, Hashnode, GitHub Discussions, or a
4+
personal blog.
5+
6+
Use these when the repo docs are pushed and the links resolve publicly.
7+
8+
Site home:
9+
10+
- [Docs home](../index.md)
11+
12+
## Drafts
13+
14+
- [Turn an OpenAPI Spec Into a CLI People Can Actually Use](2026-05-26-openapi-spec-to-cli.md)
15+
16+
## Publishing Assets
17+
18+
- [Publishing Pack](publishing-pack.md)
19+
20+
## Publishing Checklist
21+
22+
Before publishing:
23+
24+
- Confirm README/docs links work on GitHub.
25+
- Confirm the current PyPI page has the latest README if the post links PyPI.
26+
- Use the canonical repo URL: `https://github.com/shivaam/openapi-cli-gen`.
27+
- Do not ask for stars in the post body.
28+
- Ask for real specs, workflow feedback, or APIs that should have CLIs.
29+
- After publishing, record the URL in `docs/marketing/tracking.md`.

0 commit comments

Comments
 (0)