-
-
Save ikenna/d7834f652f14b93e9e3df7698a486b52 to your computer and use it in GitHub Desktop.
| const fs = require('fs'); | |
| const yaml = require('js-yaml'); | |
| function listEndpoints(openapiFile) { | |
| try { | |
| const openapiData = yaml.safeLoad(fs.readFileSync(openapiFile, 'utf8')); | |
| const paths = openapiData.paths || {}; | |
| const endpoints = []; | |
| for (const path in paths) { | |
| const methods = paths[path]; | |
| for (const method in methods) { | |
| const endpoint = `${method.toUpperCase()} ${path}`; | |
| endpoints.push(endpoint); | |
| } | |
| } | |
| return endpoints; | |
| } catch (error) { | |
| console.error(`Error loading OpenAPI file: ${error}`); | |
| return []; | |
| } | |
| } | |
| // Usage example | |
| const openapiFile = 'your-openapi.yaml'; | |
| const endpoints = listEndpoints(openapiFile); | |
| for (const endpoint of endpoints) { | |
| console.log(endpoint); | |
| } |
This might be of interest for anyone landing here too.
yq + qsv + csview - Extract to CSV + markdown table output
Using the same Docker OpenAPI document (direct YAML link) as before, here is a way to extract the desired data with yq and do some extra processing with qsv to format it:
# yq will filter and format the data into an array of values we want from the input
# The comments within the string value are safe to copy/paste as a shell command.
# yq outputs CSV for qsv to then adds the column headers and sort by column order.
# csview then renders this out in the preferred style such as formatted markdown.
yq -o=csv '.paths[] | .[] | [
.tags | join(" "), # An array, can be used to assign the endpoint to a group
(parent | key), # The URL path for this endpoint
key | upcase, # The HTTP method uppercased `get => GET`
.operationId # Unique identifier for the endpoint
]' api.yaml \
| qsv rename --no-headers GROUP,PATH,METHOD,ID \
| qsv sort \
| csview --style markdownThis will output a table like this:
Markdown output (rendered)
| GROUP | PATH | METHOD | ID |
|---|---|---|---|
| Config | /configs | GET | ConfigList |
| Config | /configs/create | POST | ConfigCreate |
| Config | /configs/{id} | DELETE | ConfigDelete |
| Config | /configs/{id} | GET | ConfigInspect |
| Config | /configs/{id}/update | POST | ConfigUpdate |
| Container | /containers/create | POST | ContainerCreate |
| Container | /containers/json | GET | ContainerList |
| Container | /containers/prune | POST | ContainerPrune |
| Container | /containers/{id} | DELETE | ContainerDelete |
| Container | /containers/{id}/archive | GET | ContainerArchive |
| Container | /containers/{id}/archive | HEAD | ContainerArchiveInfo |
| Container | /containers/{id}/archive | PUT | PutContainerArchive |
| Container | /containers/{id}/attach | POST | ContainerAttach |
| Container | /containers/{id}/attach/ws | GET | ContainerAttachWebsocket |
| Container | /containers/{id}/changes | GET | ContainerChanges |
| Container | /containers/{id}/export | GET | ContainerExport |
| Container | /containers/{id}/json | GET | ContainerInspect |
| Container | /containers/{id}/kill | POST | ContainerKill |
| Container | /containers/{id}/logs | GET | ContainerLogs |
| Container | /containers/{id}/pause | POST | ContainerPause |
| Container | /containers/{id}/rename | POST | ContainerRename |
| Container | /containers/{id}/resize | POST | ContainerResize |
| Container | /containers/{id}/restart | POST | ContainerRestart |
| Container | /containers/{id}/start | POST | ContainerStart |
| Container | /containers/{id}/stats | GET | ContainerStats |
| Container | /containers/{id}/stop | POST | ContainerStop |
| Container | /containers/{id}/top | GET | ContainerTop |
| Container | /containers/{id}/unpause | POST | ContainerUnpause |
| Container | /containers/{id}/update | POST | ContainerUpdate |
| Container | /containers/{id}/wait | POST | ContainerWait |
| Distribution | /distribution/{name}/json | GET | DistributionInspect |
| Exec | /containers/{id}/exec | POST | ContainerExec |
| Exec | /exec/{id}/json | GET | ExecInspect |
| Exec | /exec/{id}/resize | POST | ExecResize |
| Exec | /exec/{id}/start | POST | ExecStart |
| Image | /build | POST | ImageBuild |
| Image | /build/prune | POST | BuildPrune |
| Image | /commit | POST | ImageCommit |
| Image | /images/create | POST | ImageCreate |
| Image | /images/get | GET | ImageGetAll |
| Image | /images/json | GET | ImageList |
| Image | /images/load | POST | ImageLoad |
| Image | /images/prune | POST | ImagePrune |
| Image | /images/search | GET | ImageSearch |
| Image | /images/{name} | DELETE | ImageDelete |
| Image | /images/{name}/get | GET | ImageGet |
| Image | /images/{name}/history | GET | ImageHistory |
| Image | /images/{name}/json | GET | ImageInspect |
| Image | /images/{name}/push | POST | ImagePush |
| Image | /images/{name}/tag | POST | ImageTag |
| Network | /networks | GET | NetworkList |
| Network | /networks/create | POST | NetworkCreate |
| Network | /networks/prune | POST | NetworkPrune |
| Network | /networks/{id} | DELETE | NetworkDelete |
| Network | /networks/{id} | GET | NetworkInspect |
| Network | /networks/{id}/connect | POST | NetworkConnect |
| Network | /networks/{id}/disconnect | POST | NetworkDisconnect |
| Node | /nodes | GET | NodeList |
| Node | /nodes/{id} | DELETE | NodeDelete |
| Node | /nodes/{id} | GET | NodeInspect |
| Node | /nodes/{id}/update | POST | NodeUpdate |
| Plugin | /plugins | GET | PluginList |
| Plugin | /plugins/create | POST | PluginCreate |
| Plugin | /plugins/privileges | GET | GetPluginPrivileges |
| Plugin | /plugins/pull | POST | PluginPull |
| Plugin | /plugins/{name} | DELETE | PluginDelete |
| Plugin | /plugins/{name}/disable | POST | PluginDisable |
| Plugin | /plugins/{name}/enable | POST | PluginEnable |
| Plugin | /plugins/{name}/json | GET | PluginInspect |
| Plugin | /plugins/{name}/push | POST | PluginPush |
| Plugin | /plugins/{name}/set | POST | PluginSet |
| Plugin | /plugins/{name}/upgrade | POST | PluginUpgrade |
| Secret | /secrets | GET | SecretList |
| Secret | /secrets/create | POST | SecretCreate |
| Secret | /secrets/{id} | DELETE | SecretDelete |
| Secret | /secrets/{id} | GET | SecretInspect |
| Secret | /secrets/{id}/update | POST | SecretUpdate |
| Service | /services | GET | ServiceList |
| Service | /services/create | POST | ServiceCreate |
| Service | /services/{id} | DELETE | ServiceDelete |
| Service | /services/{id} | GET | ServiceInspect |
| Service | /services/{id}/logs | GET | ServiceLogs |
| Service | /services/{id}/update | POST | ServiceUpdate |
| Session | /session | POST | Session |
| Swarm | /swarm | GET | SwarmInspect |
| Swarm | /swarm/init | POST | SwarmInit |
| Swarm | /swarm/join | POST | SwarmJoin |
| Swarm | /swarm/leave | POST | SwarmLeave |
| Swarm | /swarm/unlock | POST | SwarmUnlock |
| Swarm | /swarm/unlockkey | GET | SwarmUnlockkey |
| Swarm | /swarm/update | POST | SwarmUpdate |
| System | /_ping | GET | SystemPing |
| System | /_ping | HEAD | SystemPingHead |
| System | /auth | POST | SystemAuth |
| System | /events | GET | SystemEvents |
| System | /info | GET | SystemInfo |
| System | /system/df | GET | SystemDataUsage |
| System | /version | GET | SystemVersion |
| Task | /tasks | GET | TaskList |
| Task | /tasks/{id} | GET | TaskInspect |
| Task | /tasks/{id}/logs | GET | TaskLogs |
| Volume | /volumes | GET | VolumeList |
| Volume | /volumes/create | POST | VolumeCreate |
| Volume | /volumes/prune | POST | VolumePrune |
| Volume | /volumes/{name} | DELETE | VolumeDelete |
| Volume | /volumes/{name} | GET | VolumeInspect |
| Volume | /volumes/{name} | PUT | VolumeUpdate |
Markdown output (raw)
| GROUP | PATH | METHOD | ID |
|--------------|----------------------------|--------|--------------------------|
| Config | /configs | GET | ConfigList |
| Config | /configs/create | POST | ConfigCreate |
| Config | /configs/{id} | DELETE | ConfigDelete |
| Config | /configs/{id} | GET | ConfigInspect |
| Config | /configs/{id}/update | POST | ConfigUpdate |
| Container | /containers/create | POST | ContainerCreate |
| Container | /containers/json | GET | ContainerList |
| Container | /containers/prune | POST | ContainerPrune |
| Container | /containers/{id} | DELETE | ContainerDelete |
| Container | /containers/{id}/archive | GET | ContainerArchive |
| Container | /containers/{id}/archive | HEAD | ContainerArchiveInfo |
| Container | /containers/{id}/archive | PUT | PutContainerArchive |
| Container | /containers/{id}/attach | POST | ContainerAttach |
| Container | /containers/{id}/attach/ws | GET | ContainerAttachWebsocket |
| Container | /containers/{id}/changes | GET | ContainerChanges |
| Container | /containers/{id}/export | GET | ContainerExport |
| Container | /containers/{id}/json | GET | ContainerInspect |
| Container | /containers/{id}/kill | POST | ContainerKill |
| Container | /containers/{id}/logs | GET | ContainerLogs |
| Container | /containers/{id}/pause | POST | ContainerPause |
| Container | /containers/{id}/rename | POST | ContainerRename |
| Container | /containers/{id}/resize | POST | ContainerResize |
| Container | /containers/{id}/restart | POST | ContainerRestart |
| Container | /containers/{id}/start | POST | ContainerStart |
| Container | /containers/{id}/stats | GET | ContainerStats |
| Container | /containers/{id}/stop | POST | ContainerStop |
| Container | /containers/{id}/top | GET | ContainerTop |
| Container | /containers/{id}/unpause | POST | ContainerUnpause |
| Container | /containers/{id}/update | POST | ContainerUpdate |
| Container | /containers/{id}/wait | POST | ContainerWait |
| Distribution | /distribution/{name}/json | GET | DistributionInspect |
| Exec | /containers/{id}/exec | POST | ContainerExec |
| Exec | /exec/{id}/json | GET | ExecInspect |
| Exec | /exec/{id}/resize | POST | ExecResize |
| Exec | /exec/{id}/start | POST | ExecStart |
| Image | /build | POST | ImageBuild |
| Image | /build/prune | POST | BuildPrune |
| Image | /commit | POST | ImageCommit |
| Image | /images/create | POST | ImageCreate |
| Image | /images/get | GET | ImageGetAll |
| Image | /images/json | GET | ImageList |
| Image | /images/load | POST | ImageLoad |
| Image | /images/prune | POST | ImagePrune |
| Image | /images/search | GET | ImageSearch |
| Image | /images/{name} | DELETE | ImageDelete |
| Image | /images/{name}/get | GET | ImageGet |
| Image | /images/{name}/history | GET | ImageHistory |
| Image | /images/{name}/json | GET | ImageInspect |
| Image | /images/{name}/push | POST | ImagePush |
| Image | /images/{name}/tag | POST | ImageTag |
| Network | /networks | GET | NetworkList |
| Network | /networks/create | POST | NetworkCreate |
| Network | /networks/prune | POST | NetworkPrune |
| Network | /networks/{id} | DELETE | NetworkDelete |
| Network | /networks/{id} | GET | NetworkInspect |
| Network | /networks/{id}/connect | POST | NetworkConnect |
| Network | /networks/{id}/disconnect | POST | NetworkDisconnect |
| Node | /nodes | GET | NodeList |
| Node | /nodes/{id} | DELETE | NodeDelete |
| Node | /nodes/{id} | GET | NodeInspect |
| Node | /nodes/{id}/update | POST | NodeUpdate |
| Plugin | /plugins | GET | PluginList |
| Plugin | /plugins/create | POST | PluginCreate |
| Plugin | /plugins/privileges | GET | GetPluginPrivileges |
| Plugin | /plugins/pull | POST | PluginPull |
| Plugin | /plugins/{name} | DELETE | PluginDelete |
| Plugin | /plugins/{name}/disable | POST | PluginDisable |
| Plugin | /plugins/{name}/enable | POST | PluginEnable |
| Plugin | /plugins/{name}/json | GET | PluginInspect |
| Plugin | /plugins/{name}/push | POST | PluginPush |
| Plugin | /plugins/{name}/set | POST | PluginSet |
| Plugin | /plugins/{name}/upgrade | POST | PluginUpgrade |
| Secret | /secrets | GET | SecretList |
| Secret | /secrets/create | POST | SecretCreate |
| Secret | /secrets/{id} | DELETE | SecretDelete |
| Secret | /secrets/{id} | GET | SecretInspect |
| Secret | /secrets/{id}/update | POST | SecretUpdate |
| Service | /services | GET | ServiceList |
| Service | /services/create | POST | ServiceCreate |
| Service | /services/{id} | DELETE | ServiceDelete |
| Service | /services/{id} | GET | ServiceInspect |
| Service | /services/{id}/logs | GET | ServiceLogs |
| Service | /services/{id}/update | POST | ServiceUpdate |
| Session | /session | POST | Session |
| Swarm | /swarm | GET | SwarmInspect |
| Swarm | /swarm/init | POST | SwarmInit |
| Swarm | /swarm/join | POST | SwarmJoin |
| Swarm | /swarm/leave | POST | SwarmLeave |
| Swarm | /swarm/unlock | POST | SwarmUnlock |
| Swarm | /swarm/unlockkey | GET | SwarmUnlockkey |
| Swarm | /swarm/update | POST | SwarmUpdate |
| System | /_ping | GET | SystemPing |
| System | /_ping | HEAD | SystemPingHead |
| System | /auth | POST | SystemAuth |
| System | /events | GET | SystemEvents |
| System | /info | GET | SystemInfo |
| System | /system/df | GET | SystemDataUsage |
| System | /version | GET | SystemVersion |
| Task | /tasks | GET | TaskList |
| Task | /tasks/{id} | GET | TaskInspect |
| Task | /tasks/{id}/logs | GET | TaskLogs |
| Volume | /volumes | GET | VolumeList |
| Volume | /volumes/create | POST | VolumeCreate |
| Volume | /volumes/prune | POST | VolumePrune |
| Volume | /volumes/{name} | DELETE | VolumeDelete |
| Volume | /volumes/{name} | GET | VolumeInspect |
| Volume | /volumes/{name} | PUT | VolumeUpdate |With qsv you can rearrange the columns, omit columns, etc quite easily.
Advanced processing with QSV
This example that transforms that same CSV output from yq to a filtered subset rearranged and sorted to different requirements:
# Same yq operation as before, but now qsv will filter rows of the GROUP column
# Then for any PATH values that have a URL parameter substring, replace it with `*`
# The METHOD and PATH columns are extracted via `select` with new column positions
# Instead of sorting by the 1st colum (METHOD), sort by 2nd colum (PATH)
# Finally `table` will output an unstyled table of the data, tail to remove headers
yq -o=csv '.paths[] | .[] | [
.tags | join(" "), # An array, can be used to assign the endpoint to a group
(parent | key), # The URL path for this endpoint
key | upcase, # The HTTP method uppercased `get => GET`
.operationId # Unique identifier for the endpoint
]' api.yaml \
| qsv rename --no-headers GROUP,PATH,METHOD,ID \
| qsv search --ignore-case --literal --select GROUP secret \
| qsv replace --quiet --select PATH '\{.+\}' '*' \
| qsv select METHOD,PATH \
| qsv sort --select PATH \
| qsv table | tail -n +2
# Result:
GET /secrets
GET /secrets/*
DELETE /secrets/*
POST /secrets/*/update
POST /secrets/createThat output is more aligned with the original JS example (extra processing aside).
Swapping qsv table | tail -n +2 for csview --style markdown we get the same data formatted for rendering:
| METHOD | PATH |
|---|---|
| GET | /secrets |
| GET | /secrets/* |
| DELETE | /secrets/* |
| POST | /secrets/*/update |
| POST | /secrets/create |
JS to yq port
The actual minimal equivalent for the JS example output would be:
# Output as space delimited strings:
yq '.paths[][] | (key|upcase) + " " + (parent|key)' api.yaml
# Result:
GET /secrets
POST /secrets/create
GET /secrets/{id}
DELETE /secrets/{id}
POST /secrets/{id}/update# With QSV for better column aligned output, uses arrays with CSV output:
yq -o=csv '.paths[] | [.[] | [
(key|upcase), # The HTTP method uppercased `get => GET`
(parent|key) # The URL path for this endpoint
]]' api.yaml | qsv table
# Result:
GET /secrets
POST /secrets/create
GET /secrets/{id}
DELETE /secrets/{id}
POST /secrets/{id}/updateNOTE: Result outputs were filtered with grep secrets for brevity, unlike the prior advanced example which actually filtered results by specific column via qsv search.
You can use the
yqCLI tool as another way which can be simpler in this case (you only need to change the yaml filename):For example on the Docker Engine API:
If you need another output format like JSON you can use
-o json👍The above may not be as friendly if you need an object with standard keys to query.
A more complex example that outputs an array of objects with an additional
idfield that better identifies the endpoint:Output example:
With `yq -o=json` for JSON output
yqstarts to be less pleasant the more complex the expression gets, especially if you need more flexibility there the approach with JS is easier to grok :)