danielgtaylor / restish

Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in
https://rest.sh/
MIT License
913 stars 74 forks source link

Usage as a library #124

Closed lispyclouds closed 2 years ago

lispyclouds commented 2 years ago

I have a project and its corresponding OpenAPI spec and I'm in the process of making a CLI for it. I had very similar ideas as restish and I'm so glad all the hard work has already been done! Thanks for that!

For the CLI, I want to "embed" the ability to control the project as a subcommand as I would like to have more things in the CLI which aren't talking to the API. Would such a thing be possible here? Mainly im interesed in picking up the parsing of the openapi yaml and maybe getting back a list of cobra.Commands or something so that I can add it to my CLI as a subcommand.

Would such a feature be useful? If yes, I'm happy to contribute it too! 😄

Thanks again for building this!

danielgtaylor commented 2 years ago

It's possible to add your own custom formats, auth, commands, etc to Restish pretty easily, for example the main.go setup just looks like this:

cli.Init("restish", version)

// Register default encodings, content type handlers, and link parsers.
cli.Defaults()

// Register format loaders to auto-discover API descriptions
cli.AddLoader(openapi.New())

// Register auth schemes
cli.AddAuth("oauth-client-credentials", &oauth.ClientCredentialsHandler{})
cli.AddAuth("oauth-authorization-code", &oauth.AuthorizationCodeHandler{})

// Run the CLI, parsing arguments, making requests, and printing responses.
cli.Run()

You can do a cli.Root.AddCommand(&cobra.Command{......}) before calling cli.Run().

If you prefer to just get a bunch of pre-configured commands and inject those into your CLI, I haven't tried that but you might be able to. There is a cli.Load(entrypoint string, root *cobra.Command) you can try to use. You'll still need to cli.AddLoader(openapi.New()) if you want it to recognize OpenAPI.

Any improvements to make this easier or better are welcome! :+1:


Edit: I'm also contemplating whether it would be worth supporting some kind of plugin or scripting functionality to enable custom commands. 🤔

lispyclouds commented 2 years ago

Thanks a lot for the pointers, will try them out soon! 😄 As for the extensibility aspects, it would be great, at least for me, if I can just hook in my commands which aren't necessarily talking to the API. Also maybe a way to customise the handler of the OperationId, the way i was thinking before I found restish is taking a map like:

map[string]func(params map[string]any) error{
  "opid1": func(params map[string]any) error {
    // some potential side-effects
    return err
  },
  ...
}

and passing it along to the init or something? I think having something like this enables more custom behaviour while still keeping the underlying things same?

danielgtaylor commented 2 years ago

As for the extensibility aspects, it would be great, at least for me, if I can just hook in my commands which aren't necessarily talking to the API.

Using cli.Root.AddCommand(&cobra.Command{......}) lets you add any custom command you want, for example:

cli.Init("my-cli", "1.0.0")

cli.Root.AddCommand(&cobra.Command{
    Use:  "hello",
    Args: cobra.ExactArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        // You can do anything you want here, no need to talk to any API!
        fmt.Printf("Hello, %s!\n", args[0])
    },
})

cli.Run()

Then you can try it out:

$ go run . hello lispyclouds
Hello lispyclouds!
lispyclouds commented 2 years ago

Thanks a lot for the ideas! Looks good for me to go explore things, will get back if something more could be done! 😄