Skip to content

Commit

Permalink
Merge pull request #145 from danielgtaylor/openapi31
Browse files Browse the repository at this point in the history
feat!: OpenAPI 3.1 support, fixes #115
  • Loading branch information
danielgtaylor committed Dec 5, 2022
2 parents aaf1e82 + c59001f commit c145bbb
Show file tree
Hide file tree
Showing 31 changed files with 2,033 additions and 953 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Features include:
- [RFC 8631](https://tools.ietf.org/html/rfc8631) `service-desc` link relation
- [RFC 5988](https://tools.ietf.org/html/rfc5988#section-6.2.2) `describedby` link relation
- Supported formats
- [OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) and [JSON Schema](https://json-schema.org/)
- OpenAPI [3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) / [3.1](https://spec.openapis.org/oas/v3.1.0.html) and [JSON Schema](https://json-schema.org/)
- Automatic configuration of API auth if advertised by the API
- Shell command completion for Bash, Fish, Zsh, Powershell
- Automatic pagination of resource collections via [RFC 5988](https://tools.ietf.org/html/rfc5988) `prev` and `next` hypermedia links
Expand Down
18 changes: 11 additions & 7 deletions cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import (
// around available resources, operations, and links. An API is produced by
// a Loader and cached by the CLI in-between runs when possible.
type API struct {
Short string `json:"short"`
Long string `json:"long,omitempty"`
Operations []Operation `json:"operations,omitempty"`
Auth []APIAuth `json:"auth,omitempty"`
AutoConfig AutoConfig `json:"autoconfig,omitempty"`
RestishVersion string `json:"restish_version" yaml:"restish_version"`
Short string `json:"short" yaml:"short"`
Long string `json:"long,omitempty" yaml:"long,omitempty"`
Operations []Operation `json:"operations,omitempty" yaml:"operations,omitempty"`
Auth []APIAuth `json:"auth,omitempty" yaml:"auth,omitempty"`
AutoConfig AutoConfig `json:"auto_config,omitempty" yaml:"auto_config,omitempty"`
}

// Merge two APIs together. Takes the description if none is set and merges
Expand Down Expand Up @@ -133,8 +134,10 @@ func Load(entrypoint string, root *cobra.Command) (API, error) {
filename := path.Join(viper.GetString("config-directory"), name+".cbor")
if data, err := os.ReadFile(filename); err == nil {
if err := cbor.Unmarshal(data, &cached); err == nil {
setupRootFromAPI(root, &cached)
return cached, nil
if cached.RestishVersion == root.Version {
setupRootFromAPI(root, &cached)
return cached, nil
}
}
}
}
Expand Down Expand Up @@ -182,6 +185,7 @@ func Load(entrypoint string, root *cobra.Command) (API, error) {
}

if found {
desc.RestishVersion = root.Version
cacheAPI(name, &desc)
return desc, nil
}
Expand Down
28 changes: 14 additions & 14 deletions cli/apiconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,34 @@ var apis *viper.Viper

// APIAuth describes the auth type and parameters for an API.
type APIAuth struct {
Name string `json:"name"`
Params map[string]string `json:"params,omitempty"`
Name string `json:"name" yaml:"name"`
Params map[string]string `json:"params,omitempty" yaml:"params,omitempty"`
}

// TLSConfig contains the TLS setup for the HTTP client
type TLSConfig struct {
InsecureSkipVerify bool `json:"insecure,omitempty" mapstructure:"insecure"`
Cert string `json:"cert,omitempty"`
Key string `json:"key,omitempty"`
CACert string `json:"ca_cert,omitempty" mapstructure:"ca_cert"`
InsecureSkipVerify bool `json:"insecure,omitempty" yaml:"insecure,omitempty" mapstructure:"insecure"`
Cert string `json:"cert,omitempty" yaml:"cert,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
CACert string `json:"ca_cert,omitempty" yaml:"ca_cert,omitempty" mapstructure:"ca_cert"`
}

// APIProfile contains account-specific API information
type APIProfile struct {
Base string `json:"base,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Query map[string]string `json:"query,omitempty"`
Auth *APIAuth `json:"auth,omitempty"`
Base string `json:"base,omitempty" yaml:"base,omitempty"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
Query map[string]string `json:"query,omitempty" yaml:"query,omitempty"`
Auth *APIAuth `json:"auth,omitempty" yaml:"auth,omitempty"`
}

// APIConfig describes per-API configuration options like the base URI and
// auth scheme, if any.
type APIConfig struct {
name string
Base string `json:"base"`
SpecFiles []string `json:"spec_files,omitempty" mapstructure:"spec_files,omitempty"`
Profiles map[string]*APIProfile `json:"profiles,omitempty" mapstructure:",omitempty"`
TLS *TLSConfig `json:"tls,omitempty" mapstructure:",omitempty"`
Base string `json:"base" yaml:"base"`
SpecFiles []string `json:"spec_files,omitempty" yaml:"spec_files,omitempty" mapstructure:"spec_files,omitempty"`
Profiles map[string]*APIProfile `json:"profiles,omitempty" yaml:"profiles,omitempty" mapstructure:",omitempty"`
TLS *TLSConfig `json:"tls,omitempty" yaml:"tls,omitempty" mapstructure:",omitempty"`
}

// Save the API configuration to disk.
Expand Down
14 changes: 7 additions & 7 deletions cli/autoconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package cli
// AutoConfigVar represents a variable given by the user when prompted during
// auto-configuration setup of an API.
type AutoConfigVar struct {
Description string `json:"description,omitempty"`
Example string `json:"example,omitempty"`
Default interface{} `json:"default,omitempty"`
Enum []interface{} `json:"enum,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Example string `json:"example,omitempty" yaml:"example,omitempty"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`

// Exclude the value from being sent to the server. This essentially makes
// it a value which is only used in param templates.
Expand All @@ -17,7 +17,7 @@ type AutoConfigVar struct {
// are advertised via OpenAPI extension and picked up by the CLI to make it
// easier to get started using an API.
type AutoConfig struct {
Headers map[string]string `json:"headers,omitempty"`
Prompt map[string]AutoConfigVar `json:"prompt,omitempty"`
Auth APIAuth `json:"auth,omitempty"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
Prompt map[string]AutoConfigVar `json:"prompt,omitempty" yaml:"prompt,omitempty"`
Auth APIAuth `json:"auth,omitempty" yaml:"auth,omitempty"`
}
7 changes: 7 additions & 0 deletions cli/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ func setTable(data []interface{}) ([]byte, error) {
// Will get out of order otherwise
for _, cellKey := range headerCells {
if val, ok := mapData[cellKey.Text]; ok {
if s, ok := val.([]any); ok {
converted := make([]string, len(s))
for i := 0; i < len(s); i++ {
converted[i] = fmt.Sprintf("%v", s[i])
}
val = strings.Join(converted, ", ")
}
bodyCells = append(bodyCells, &simpletable.Cell{Align: simpletable.AlignRight, Text: fmt.Sprintf("%v", val)})
} else {
return nil, fmt.Errorf("error building table. Header Key not found in repeating object: %s", cellKey.Text)
Expand Down
2 changes: 1 addition & 1 deletion cli/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ func NewDefaultFormatter(tty, color bool) *DefaultFormatter {
func (f *DefaultFormatter) filterData(filter string, data map[string]any) (any, error) {
keys := maps.Keys(data)
sort.Strings(keys)
found := strings.HasPrefix(filter, "*") || strings.HasPrefix(filter, "..")
found := strings.HasPrefix(filter, "*") || strings.HasPrefix(filter, "..") || strings.HasPrefix(filter, "{")
if !found {
for _, k := range keys {
if strings.HasPrefix(filter, k) {
Expand Down
8 changes: 8 additions & 0 deletions cli/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ var SchemaLexer = lexers.Register(chroma.MustNewLazyLexer(
},
"value": {
chroma.Include("whitespace"),
{
Pattern: `allOf|anyOf|oneOf`,
Type: chroma.NameBuiltin,
},
{
Pattern: `(\()([^ )]+)`,
Type: chroma.ByGroups(chroma.Text, chroma.Keyword),
Expand All @@ -172,6 +176,10 @@ var SchemaLexer = lexers.Register(chroma.MustNewLazyLexer(
},
"row": {
chroma.Include("whitespace"),
{
Pattern: `allOf|anyOf|oneOf`,
Type: chroma.NameBuiltin,
},
{
Pattern: `([^*:\n]+)(\*?)(:)`,
Type: chroma.ByGroups(chroma.NameTag, chroma.GenericStrong, chroma.Text),
Expand Down
28 changes: 14 additions & 14 deletions cli/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ import (

// Operation represents an API action, e.g. list-things or create-user
type Operation struct {
Name string `json:"name"`
Group string `json:"group,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Short string `json:"short,omitempty"`
Long string `json:"long,omitempty"`
Method string `json:"method,omitempty"`
URITemplate string `json:"uriTemplate"`
PathParams []*Param `json:"pathParams,omitempty"`
QueryParams []*Param `json:"queryParams,omitempty"`
HeaderParams []*Param `json:"headerParams,omitempty"`
BodyMediaType string `json:"bodyMediaType,omitempty"`
Examples []string `json:"examples,omitempty"`
Hidden bool `json:"hidden,omitempty"`
Deprecated string `json:"deprecated,omitempty"`
Name string `json:"name" yaml:"name"`
Group string `json:"group,omitempty" yaml:"group,omitempty"`
Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`
Short string `json:"short,omitempty" yaml:"short,omitempty"`
Long string `json:"long,omitempty" yaml:"long,omitempty"`
Method string `json:"method,omitempty" yaml:"method,omitempty"`
URITemplate string `json:"uri_template" yaml:"uri_template"`
PathParams []*Param `json:"path_params,omitempty" yaml:"path_params,omitempty"`
QueryParams []*Param `json:"query_params,omitempty" yaml:"query_params,omitempty"`
HeaderParams []*Param `json:"header_params,omitempty" yaml:"header_params,omitempty"`
BodyMediaType string `json:"body_media_type,omitempty" yaml:"body_media_type,omitempty"`
Examples []string `json:"examples,omitempty" yaml:"examples,omitempty"`
Hidden bool `json:"hidden,omitempty" yaml:"hidden,omitempty"`
Deprecated string `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
}

// command returns a Cobra command instance for this operation.
Expand Down
16 changes: 8 additions & 8 deletions cli/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ func typeConvert(from, to interface{}) interface{} {

// Param represents an API operation input parameter.
type Param struct {
Type string `json:"type"`
Name string `json:"name"`
DisplayName string `json:"displayName,omitempty"`
Description string `json:"description,omitempty"`
Style Style `json:"style,omitempty"`
Explode bool `json:"explode,omitempty"`
Default interface{} `json:"default,omitempty"`
Example interface{} `json:"example,omitempty"`
Type string `json:"type" yaml:"type"`
Name string `json:"name" yaml:"name"`
DisplayName string `json:"display_name,omitempty" yaml:"display_name,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Style Style `json:"style,omitempty" yaml:"style,omitempty"`
Explode bool `json:"explode,omitempty" yaml:"explide,omitempty"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
}

// Parse the parameter from a string input (e.g. command line argument)
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
- [RFC 8631](https://tools.ietf.org/html/rfc8631) `service-desc` link relation
- [RFC 5988](https://tools.ietf.org/html/rfc5988#section-6.2.2) `describedby` link relation
- Supported formats
- [OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) and [JSON Schema](https://json-schema.org/)
- OpenAPI [3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) / [3.1](https://spec.openapis.org/oas/v3.1.0.html) and [JSON Schema](https://json-schema.org/)
- Automatic configuration of API auth if advertised by the API
- Shell command completion for Bash, Fish, Zsh, Powershell
- Automatic pagination of resource collections via [RFC 5988](https://tools.ietf.org/html/rfc5988) `prev` and `next` hypermedia links
Expand Down
9 changes: 5 additions & 4 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,11 @@ Accept-Ranges: bytes

APIs can be registered in order to provide API description auto-discovery (e.g. OpenAPI 3) with convenience commands and authentication. The following API description formats and versions are supported:

| Format | Version | Notes |
| ------- | ------- | --------------------------------------------------------------------------------------------------- |
| OpenAPI | 3.0 | Fully supported |
| OpenAPI | 3.1 | Partially supported, waiting on [kin-openapi#230](https://github.com/getkin/kin-openapi/issues/230) |
| Format | Version | Notes |
| ------- | ------- | ---------------------------------- |
| Swagger | 2.0 | :x: Not supported |
| OpenAPI | 3.0 | :white_check_mark: Fully supported |
| OpenAPI | 3.1 | :white_check_mark: Fully supported |

APIs are registered with a short nickname. For example the GitHub v3 API might be called `github` or the Digital Ocean API might be called `do`.

Expand Down
42 changes: 19 additions & 23 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,43 @@ module github.com/danielgtaylor/restish

go 1.18

// replace github.com/pb33f/libopenapi => ../libopenapi

require (
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/alecthomas/chroma v0.10.0
github.com/alexeyco/simpletable v1.0.0
github.com/amzn/ion-go v1.1.3
github.com/andybalholm/brotli v1.0.4
github.com/charmbracelet/glamour v0.5.1-0.20221024082230-3c5ceaed91cc
github.com/charmbracelet/glamour v0.6.0
github.com/danielgtaylor/casing v0.0.0-20210126043903-4e55e6373ac3
github.com/danielgtaylor/shorthand/v2 v2.0.0-beta2
github.com/danielgtaylor/shorthand/v2 v2.0.1
github.com/eliukblau/pixterm v1.3.1
github.com/fxamacker/cbor/v2 v2.4.0
github.com/gbl08ma/httpcache v1.0.2
github.com/getkin/kin-openapi v0.107.0
github.com/ghodss/yaml v1.0.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/gosimple/slug v1.13.1
github.com/hexops/gotextdiff v1.0.3
github.com/iancoleman/strcase v0.2.0
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/lucasjones/reggen v0.0.0-20200904144131-37ba4fa293bb
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.16
github.com/mitchellh/mapstructure v1.5.0
github.com/pb33f/libopenapi v0.3.4
github.com/shamaton/msgpack/v2 v2.1.1
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.13.0
github.com/spf13/viper v1.14.0
github.com/stretchr/testify v1.8.1
github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9
golang.org/x/exp v0.0.0-20221108223516-5d533826c662
golang.org/x/oauth2 v0.1.0
golang.org/x/term v0.1.0
golang.org/x/text v0.4.0
golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb
golang.org/x/oauth2 v0.2.0
golang.org/x/term v0.2.0
golang.org/x/text v0.5.0
gopkg.in/h2non/gock.v1 v1.1.2
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand All @@ -47,48 +50,41 @@ require (
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.13.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.2 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/twpayne/httpcache v1.0.0 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark v1.5.3 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/image v0.1.0 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
)
Loading

0 comments on commit c145bbb

Please sign in to comment.