Skip to content

Commit

Permalink
[names] use x-cli-name
Browse files Browse the repository at this point in the history
  • Loading branch information
lispyclouds committed Dec 15, 2024
1 parent 91711b6 commit 0c282ce
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 102 deletions.
94 changes: 7 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,106 +25,26 @@ Experimental, in dev flux and looking for design/usage feedback!
go get github.com/lispyclouds/climate
```

### How it works and usage
### Rationale

climate allows the server to influence the CLI behaviour by using OpenAPI's [extensions](https://swagger.io/docs/specification/v3_0/openapi-extensions/). It encourages [spec-first](https://www.atlassian.com/blog/technology/spec-first-api-development) practices thereby keeping both users and maintenance manageable. It does just enough to handle the spec and nothing more.

Overall, the way it works:
- Each operation is converted to a Cobra command
- Each parameter is converted to a flag with its corresponding type
- Request bodies are a flag as of now, subject to change
- Request bodies are a flag as of now, subject to change. Name defaults to `climate-data` unless specified via `x-cli-name`
- The provided handlers are attached to each command, grouped and attached to the rootCmd

Influenced by some of the ideas behind [restish](https://rest.sh/) it uses the following extensions as of now:
- `x-cli-aliases`: A list of strings which would be used as the alternate names for:
- Operations: If set, will prefer the first of the list otherwise the `operationId`. Will use the rest as cobra aliases
- Request Body: Same preference as above but would a default of `climate-data` as the name of the param if not set
- `x-cli-aliases`: A list of strings which would be used as the alternate names for an operation
- `x-cli-group`: A string to allow grouping subcommands together. All operations in the same group would become subcommands in that group name
- `x-cli-hidden`: A boolean to hide the operation from the CLI menu. Same behaviour as a cobra command hide: it's present and expects a handler
- `x-cli-ignored`: A boolean to tell climate to omit the operation completely
- `x-cli-name`: A string to specify a different name. Applies to operations and request bodies as of now

Given an OpenAPI spec in `api.yaml`:

```yaml
openapi: "3.0.0"

info:
title: My calculator
version: "0.1.0"
description: My awesome calc!

paths:
"/add/{n1}/{n2}":
get:
operationId: AddGet
summary: Adds two numbers
x-cli-group: ops
x-cli-aliases:
- add-get
- ag

parameters:
- name: n1
required: true
in: path
description: The first number
schema:
type: integer
- name: n2
required: true
in: path
description: The second number
schema:
type: integer
post:
operationId: AddPost
summary: Adds two numbers via POST
x-cli-group: ops
x-cli-aliases:
- add-post
- ap

requestBody:
description: The numbers map
required: true
x-cli-aliases:
- nmap
content:
application/json:
schema:
$ref: "#/components/schemas/NumbersMap"
"/health":
get:
operationId: HealthCheck
summary: Returns Ok if all is well
x-cli-aliases:
- ping
"/meta":
get:
operationId: GetMeta
summary: Returns meta
x-cli-ignored: true
"/info":
get:
operationId: GetInfo
summary: Returns info
x-cli-group: info

components:
schemas:
NumbersMap:
type: object
required:
- n1
- n2
properties:
n1:
type: integer
description: The first number
n2:
type: integer
description: The second number
```
### Usage

Given an OpenAPI spec like [api.yaml](/api.yaml)

Load the spec:

Expand Down
10 changes: 4 additions & 6 deletions api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ paths:
get:
operationId: AddGet
summary: Adds two numbers
x-cli-name: add-get
x-cli-group: ops
x-cli-aliases:
- add-get
- ag

parameters:
Expand All @@ -31,16 +31,15 @@ paths:
post:
operationId: AddPost
summary: Adds two numbers via POST
x-cli-name: add-post
x-cli-group: ops
x-cli-aliases:
- add-post
- ap

requestBody:
description: The numebers map
required: true
x-cli-aliases:
- nmap
x-cli-name: nmap
content:
application/json:
schema:
Expand All @@ -49,8 +48,7 @@ paths:
get:
operationId: HealthCheck
summary: Returns Ok if all is well
x-cli-aliases:
- ping
x-cli-name: ping
"/meta":
get:
operationId: GetMeta
Expand Down
14 changes: 8 additions & 6 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type extensions struct {
aliases []string
group string
ignored bool
name string
}

func parseExtensions(exts *orderedmap.Map[string, *yaml.Node]) (*extensions, error) {
Expand All @@ -71,6 +72,8 @@ func parseExtensions(exts *orderedmap.Map[string, *yaml.Node]) (*extensions, err
ex.group = opts.(string)
case "x-cli-ignored":
ex.ignored = opts.(bool)
case "x-cli-name":
ex.name = opts.(string)
}
}

Expand Down Expand Up @@ -138,8 +141,8 @@ func addRequestBody(cmd *cobra.Command, op *v3.Operation, handlerData *HandlerDa
}

paramName := "climate-data"
if aliases := bExts.aliases; len(aliases) > 0 {
paramName = aliases[0]
if altName := bExts.name; altName != "" {
paramName = altName
}

// TODO: Handle all the different MIME types and schemas from body.Content
Expand Down Expand Up @@ -210,6 +213,7 @@ func BootstrapV3(rootCmd *cobra.Command, model libopenapi.DocumentModel[v3.Docum
}

cmd.Hidden = exts.hidden
cmd.Aliases = exts.aliases
cmd.Short = op.Description
if op.Summary != "" {
cmd.Short = op.Summary
Expand All @@ -219,11 +223,9 @@ func BootstrapV3(rootCmd *cobra.Command, model libopenapi.DocumentModel[v3.Docum
handler(opts, args, hData)
}

// TODO: hammock on better ways to handle aliases, prefers the first one as of now
cmd.Use = op.OperationId // default
if aliases := exts.aliases; len(exts.aliases) > 0 {
cmd.Use = aliases[0]
cmd.Aliases = aliases
if altName := exts.name; altName != "" {
cmd.Use = altName
}

if g := exts.group; g != "" {
Expand Down
6 changes: 3 additions & 3 deletions lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ func TestBootstrapV3(t *testing.T) {
"calc/ops/add-get": {
"Use": "add-get",
"Short": "Adds two numbers",
"Aliases": []string{"add-get", "ag"},
"Aliases": []string{"ag"},
},
"calc/ops/add-post": {
"Use": "add-post",
"Short": "Adds two numbers via POST",
"Aliases": []string{"add-post", "ap"},
"Aliases": []string{"ap"},
},
"calc/ping": {
"Use": "ping",
"Short": "Returns Ok if all is well",
"Aliases": []string{"ping"},
"Aliases": noAlias,
},
}

Expand Down

0 comments on commit 0c282ce

Please sign in to comment.