|
1 | 1 | # climate
|
2 | 2 |
|
3 | 3 | Go is a fantastic language to build CLI tooling, specially the ones for interacting with an API server. `<your tool>ctl` anyone?
|
4 |
| - |
5 | 4 | But if you're tired of building bespoke CLIs everytime or think that the swagger codegen isn't just good enough, look no further.
|
6 | 5 |
|
7 |
| -What if you can influence the CLI behaviour from the server? |
| 6 | +What if you can influence the CLI behaviour from the server? This enables you to bootstrap your [cobra](https://cobra.dev/) CLI tooling from an [OpenAPI](https://swagger.io/specification/) spec. |
| 7 | + |
| 8 | +## Getting started |
| 9 | + |
| 10 | +### Status |
| 11 | + |
| 12 | +Experimental, in dev flux and looking for design/usage feedback! |
| 13 | + |
| 14 | +### Installation |
| 15 | + |
| 16 | +```bash |
| 17 | +go get github.com/lispyclouds/climate |
| 18 | +``` |
| 19 | + |
| 20 | +### How it works and usage |
| 21 | + |
| 22 | +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. |
| 23 | + |
| 24 | +Overall, the way it works: |
| 25 | +- Each operation is converted to a Cobra command |
| 26 | +- Each parameter is converted to a flag with its corresponding type |
| 27 | +- Request bodies are a flag as of now, subject to change |
| 28 | +- The provided handlers are attached to each command, grouped and attached to the rootCmd |
| 29 | + |
| 30 | +Influenced by some of the ideas behind [restish](https://rest.sh/) it uses the following extensions as of now: |
| 31 | +- `x-cli-aliases`: A list of strings which would be used as the alternate names for: |
| 32 | + - Operations: If set, will prefer the first of the list otherwise the `operationId`. Will use the rest as cobra aliases |
| 33 | + - Request Body: Same preference as above but would a default of `climate-data` as the name of the param if not set |
| 34 | +- `x-cli-group`: A string to allow grouping subcommands together. All operations in the same group would become subcommands in that group name |
| 35 | +- `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 |
| 36 | +- `x-cli-ignored`: A boolean to tell climate to omit the operation completely |
| 37 | + |
| 38 | +Given an OpenAPI spec in `api.yaml`: |
| 39 | + |
| 40 | +```yaml |
| 41 | +openapi: "3.0.0" |
| 42 | + |
| 43 | +info: |
| 44 | + title: My calculator |
| 45 | + version: "0.1.0" |
| 46 | + description: My awesome calc! |
| 47 | + |
| 48 | +paths: |
| 49 | + "/add/{n1}/{n2}": |
| 50 | + get: |
| 51 | + operationId: AddGet |
| 52 | + summary: Adds two numbers |
| 53 | + x-cli-group: ops |
| 54 | + x-cli-aliases: |
| 55 | + - add-get |
| 56 | + - ag |
| 57 | + |
| 58 | + parameters: |
| 59 | + - name: n1 |
| 60 | + required: true |
| 61 | + in: path |
| 62 | + description: The first number |
| 63 | + schema: |
| 64 | + type: integer |
| 65 | + - name: n2 |
| 66 | + required: true |
| 67 | + in: path |
| 68 | + description: The second number |
| 69 | + schema: |
| 70 | + type: integer |
| 71 | + post: |
| 72 | + operationId: AddPost |
| 73 | + summary: Adds two numbers via POST |
| 74 | + x-cli-group: ops |
| 75 | + x-cli-aliases: |
| 76 | + - add-post |
| 77 | + - ap |
| 78 | + |
| 79 | + requestBody: |
| 80 | + description: The numebers map |
| 81 | + required: true |
| 82 | + x-cli-aliases: |
| 83 | + - nmap |
| 84 | + content: |
| 85 | + application/json: |
| 86 | + schema: |
| 87 | + $ref: "#/components/schemas/NumbersMap" |
| 88 | + "/health": |
| 89 | + get: |
| 90 | + operationId: HealthCheck |
| 91 | + summary: Returns Ok if all is well |
| 92 | + x-cli-aliases: |
| 93 | + - ping |
| 94 | + "/meta": |
| 95 | + get: |
| 96 | + operationId: GetMeta |
| 97 | + summary: Returns meta |
| 98 | + x-cli-ignored: true |
| 99 | + "/info": |
| 100 | + get: |
| 101 | + operationId: GetInfo |
| 102 | + summary: Returns info |
| 103 | + x-cli-group: info |
| 104 | + |
| 105 | +components: |
| 106 | + schemas: |
| 107 | + NumbersMap: |
| 108 | + type: object |
| 109 | + required: |
| 110 | + - n1 |
| 111 | + - n2 |
| 112 | + properties: |
| 113 | + n1: |
| 114 | + type: integer |
| 115 | + description: The first number |
| 116 | + n2: |
| 117 | + type: integer |
| 118 | + description: The second number |
| 119 | +``` |
| 120 | +
|
| 121 | +Load the spec: |
| 122 | +
|
| 123 | +```go |
| 124 | +model, err := climate.LoadFileV3("api.yaml") // or climate.LoadV3 with []byte |
| 125 | +``` |
| 126 | + |
| 127 | +Define a cobra root command: |
| 128 | + |
| 129 | +```go |
| 130 | +rootCmd := &cobra.Command{ |
| 131 | + Use: "calc", |
| 132 | + Short: "My Calc", |
| 133 | + Long: "My Calc powered by OpenAPI", |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +Define one or more handler functions of the following signature: |
| 138 | +```go |
| 139 | +func handler(opts *cobra.Command, args []string, data climate.HandlerData) { |
| 140 | + // do something more useful |
| 141 | + slog.Info("called!", "data", fmt.Sprintf("%+v", data)) |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +Define the handlers for the necessary operations. These map to the `operationId` field of each operation: |
| 146 | + |
| 147 | +```go |
| 148 | +handlers := map[string]Handler{ |
| 149 | + "AddGet": handler, |
| 150 | + "AddPost": handler, |
| 151 | + "HealthCheck": handler, |
| 152 | + "GetInfo": handler, |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +Bootstrap the root command: |
| 157 | + |
| 158 | +```go |
| 159 | +err := climate.BootstrapV3(rootCmd, *model, handlers) |
| 160 | +``` |
| 161 | + |
| 162 | +Continue adding more commands and/or execute: |
| 163 | + |
| 164 | +```go |
| 165 | +// add more commands not from the spec |
| 166 | + |
| 167 | +rootCmd.Execute() |
| 168 | +``` |
| 169 | + |
| 170 | +## License |
| 171 | +Copyright © 2024- Rahul De |
8 | 172 |
|
9 |
| -## Docs coming soon, work in progress. |
| 173 | +Distributed under the MIT License. See LICENSE. |
0 commit comments