Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in

Restish Logo

Works With Restish User Guide CI codecov Docs Go Report Card

Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in, like always having the latest API resources, fields, and operations available when they go live on the API without needing to install or update anything.

See the user guide to get started.

Features include:

This project started life as a fork of OpenAPI CLI Generator.

Comments
  • inconsistent usage of flags

    inconsistent usage of flags

    Running restish against https://petstore3.swagger.io/api/v3/openapi.json gives me the following endpoint usage message:

    Usage:
      restish petstore find-pets-by-status [flags]
    
    Aliases:
      find-pets-by-status, findpetsbystatus
    
    Flags:
      -h, --help            help for find-pets-by-status
          --status string   Status values that need to be considered for filter (default "available")
    
    

    Running restish petstore findpetsbystatus --status available yields

    HTTP/2.0 400 Bad Request
    

    while restish petstore findpetsbystatus -q status=available yields the expected response.

    So the flag --status seems not to work as expected as described in the usage message.

    But it works with restish petstore findpetsbytags --tags animal although it has a similar usage:

    Usage:
      restish petstore findpetsbytags [flags]
    
    Flags:
      -h, --help           help for findpetsbytags
          --tags strings   Tags to filter by
    
  • How to use a Self Signed CA Cert with an API

    How to use a Self Signed CA Cert with an API

    Is there a way to use a Self Signed CA Cert (Corporate CA) with a specific API without having to add it to the System CA Cert location? We do not necessarily have root access on our deployment agents in which to load the CA Cert ..

  • OpenAPI v3.1 Support

    OpenAPI v3.1 Support

    Hello! As the maintainer of openapi.tools, and as somebody works with Linux Foundation helping out in OpenAPI-land, I'm reaching out to tooling vendors to track the progress towards supporting OpenAPI v3.1, to see what roadblocks there are beyond folks just generally being busy at this ridiculous time.

    I saw this, and I am going to guess it means 3.0 only:

    In general, OpenAPI 3 just works with Restish. There are a couple of things you can do to make sure your users can more easily use Restish with your API.

    OpenAPI v3.1 has a bunch of great little changes, solving problems like the the JSON Schema <!=> OpenAPI Schema Object divergence. It also fixes some other inconsistencies and duplicate ways of doing things. It's the best version and everyone should be using it, but we need tooling to catch up. Just in case folks didn't notice, or don't have resources to simplify the process, I'm here to give a friendly prod and send over some handy links.

    Here are a few articles showing off the differences between OpenAPI v3.0 and v3.1.

    • https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
    • https://www.apimatic.io/blog/2021/09/migrating-to-and-from-openapi-3-1/
    • https://nordicapis.com/whats-new-in-openapi-3-1-0/

    Here are some example files which can make for handy pass/fail test cases:

    https://github.com/Mermade/openapi3-examples/tree/master/3.1

    If you're looking for the JSON Schema that defines a valid OpenAPI document, that'll be right over here:

    https://github.com/OAI/OpenAPI-Specification/tree/main/schemas/v3.1

    No rush, but when you're starting work on it, please update this issue so I can update openapi.tools to reflect that, and folks will have a way to subscribe for updates.

    LMK if you have any questions!

  • "Unexpected Escape Sequence" when using menu with arrow keys

    While using the api configure menus, the arrow keys cause an error. I can select menu options buy starting to type the text for the option.

    % restish api configure example
    ? Base URI http://example.org
    Setting up a `default` profile
    ? Select option for profile `default`  [Use arrows to move, type to filter]
    > Add header
      Add query param
      Setup auth
      Finished with profile
    ERROR: Caught error: Unexpected Escape Sequence: ['\x1b' 'O']
    

    I'm using the regular terminal emulator on MacOS with zsh

  • Usage as a library

    Usage as a library

    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!

  • Comparison with curl and httpie

    Comparison with curl and httpie

    It would be helpful for prospective adopters to see a direct comparison of features (or main stand-out differences) between restish and alternative tools like curl and httpie.

    For example, a comparison table like the ones shown by delta or zola, or even a hello world comparison like what's done in the Chain.jl README, would be very helpful to encourage people to explore this tool further.

  • openapi: avoid adding non required parameters with no default value

    openapi: avoid adding non required parameters with no default value

    Hey,

    I have an openapi endpoint with some non required query parameters with no default value set in spec.

    Restish sets these implicitly. I suggest avoiding this as it puts empty values which may not always work well.

    Thanks.

  • feat!: OpenAPI 3.1 support, fixes #115

    feat!: OpenAPI 3.1 support, fixes #115

    This PR implements OpenAPI 3.1 support by switching to https://github.com/pb33f/libopenapi as the underlying Golang OpenAPI library. Every effort is being made to make this a backward-compatible change, however it's possible something may break or change slightly. Included with this change are:

    • Some improvements to example generation
    • Grouping of responses with the same model (commonly found in error responses)
    • Improved test coverage
    • Basic support for allOf, anyOf, oneOf

    Related upstream issues:

    • https://github.com/pb33f/libopenapi/issues/5
    • https://github.com/pb33f/libopenapi/issues/6
    • https://github.com/pb33f/libopenapi/pull/7
    • https://github.com/pb33f/libopenapi/issues/15
    • https://github.com/pb33f/libopenapi/pull/16
    • https://github.com/pb33f/libopenapi/pull/21
    • https://github.com/pb33f/libopenapi/issues/24
  • Version 0.11.0 stop working

    Version 0.11.0 stop working

    I upgraded to 0.11.0 version and now I get this error every time I want to run restish command

    ERROR: Caught error: yaml: unmarshal errors: line 1: cannot unmarshal !!seq into map[string]interface {}

  • got error while file is correct in swagger and redocly

    got error while file is correct in swagger and redocly

    goroutine 1 [running]: github.com/danielgtaylor/restish/cli.Run() /home/runner/work/restish/restish/cli/cli.go:496 +0x94c main.main() /home/runner/work/restish/restish/main.go:27 +0x238

    How I can verify openapi file with restish and get more information?

  • Not using OpenAPI v2 json spec

    Not using OpenAPI v2 json spec

    My api is using a json openapi v2 spec hosted at /openapi.json. When I configure it there is no error and I see in the server logs that both /openapi.yaml and /openapi.json are requested. But when I try restish example --help or anything else I get the below error and in the server log I see that only the yaml is requested.

    % restish example --help
    panic: could not detect API type: http://localhost:8080/
    
    goroutine 1 [running]:
    github.com/danielgtaylor/restish/cli.Run()
    	/home/runner/work/restish/restish/cli/cli.go:447 +0x777
    main.main()
    	/home/runner/work/restish/restish/main.go:27 +0x177
    

    I installed using homebrew.

  • Path parameters description invisible in --help

    Path parameters description invisible in --help

    Hello,

    I want to use restish to generate command line tools with good documentation. But it seems the path parameters is not well documented in --help, for example: The restish example OpenAPI:

    restish1

    The command line help for get-image: restish2

    The "type" parameter is not described in --help, so the user may need refer to other document to know which "type" could be.

    I'm not sure if it is a new requirement? Or some bug?

    Thanks in advance! A very potential tool.

  • proof of concept for a rate limiter

    proof of concept for a rate limiter

    Proof of concept for https://github.com/danielgtaylor/restish/issues/134 only for generic commands for now, let me know what you think. Can be used with -R 10 -l 2

  • Persistent header is not used correctly

    Persistent header is not used correctly

    Hello,

    We want to use Restish in our system to call some API routes already documented with OpenAPI. We are using Restish in dockerized environment. For a few routes, we only want to make them callable by the CLI. To do so, a unique token is generated when the container start and is added to the Restish user config. The token is also added in env variable so the backend can use it to check if the API call came from the CLI. From the Restish point of view, we want it to add the token in the custom header X-Cli-Secret for every request it's sending to our API. To set the configuration up, we used restish api configure admin command and we followed the Persistent Header documentation and also the OpenAPI Auto Configuration documentation.

    We have a weird issue and we can't understand why: the persistent header we configure in the Restish user config is never set when sending the API call to our API but it is actually send when fetching the OpenAPI documentation. We don't understand why the persistent header is not present in the actual API call...

    I added all the data we have at the end of this issue.

    Can you help us find what is wrong with our setup?

    Thank you for your help and for this amazing tool!

    Data

    Restish user config available in /home/node/.restish/apis.json
    {
      "admin": {
        "base": "http://localhost:3000/apidoc/cli-json",
        "profiles": {
          "default": {
            "headers": {
              "x-cli-secret": "819d23ba-3ebd-408c-95ac-78abc93edc2c"
            },
            "auth": {
              "name": "CliSecret"
            }
          }
        },
        "tls": {}
      }
    }
    
    OpenAPI document (served by http://localhost:3000/apidoc/cli-json)
    {
        "openapi": "3.0.0",
        "paths": {
            "/cli/subscriptions": {
                "post": {
                    "operationId": "SubscriptionController_startSchedulerCycle",
                    "parameters": [],
                    "responses": {
                        "204": {
                            "description": ""
                        }
                    },
                    "tags": [
                        "Subscription CLI API"
                    ],
                    "security": [
                        {
                            "CliSecret": []
                        }
                    ]
                }
            }
        },
        "info": {
            "title": "CLI API",
            "description": "",
            "version": "1.0.0",
            "contact": {}
        },
        "tags": [],
        "servers": [],
        "components": {
            "securitySchemes": {
                "CliSecret": {
                    "type": "apiKey",
                    "name": "x-cli-secret",
                    "description": "CLI-Secret token",
                    "in": "header"
                }
            },
            "schemas": {}
        },
        "security": [
            {
                "CliSecret": []
            }
        ],
        "x-cli-config": {
            "security": "CliSecret"
        }
    }
    
    Command & ouput

    Restish command :

    restish admin subscription-controller-start-scheduler-cycle -v --rsh-no-cache
    

    Ouput :

    DEBUG: Checking API entrypoint http://localhost:3000/apidoc/cli-json/
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /apidoc/cli-json/ HTTP/1.1
    Host: localhost:3000
    Accept: application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    X-Cli-Secret: 4417b5ed-ff8a-45f6-aeac-6a9d85c84e60
    
    
    DEBUG: Got response from server in 8.953ms:
    HTTP/1.1 200 OK
    Content-Length: 562
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"232-0U0hjEODOIqXVdfFBBEU2uIz31E"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"openapi":"3.0.0","paths":{"/cli/subscriptions":{"post":{"operationId":"SubscriptionController_startSchedulerCycle","parameters":[],"responses":{"204":{"description":""}},"tags":["Subscription CLI API"],"security":[{"CliSecret":[]}]}}},"info":{"title":"Guidap V2 CLI API","description":"","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"CliSecret":{"type":"apiKey","name":"x-cli-secret","description":"CLI-Secret token","in":"header"}},"schemas":{}},"security":[{"CliSecret":[]}],"x-cli-config":{"security":"CliSecret"}}
    DEBUG: Unmarshalling from application/json
    DEBUG: Checking http://localhost:3000/openapi.json
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /openapi.json HTTP/1.1
    Host: localhost:3000
    Accept: application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    
    
    DEBUG: Got response from server in 4.8148ms:
    HTTP/1.1 404 Not Found
    Content-Length: 1440
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5a0-rgioFpE8qs9dgBPWEv9D19ExH4Y"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"statusCode":404,"code":"NotFoundException","message":"Cannot GET /openapi.json","timestamp":1671440691695,"stackTrace":"NotFoundException: Cannot GET /openapi.json\n    at callback (/usr/src/app/node_modules/@nestjs/core/router/routes-resolver.js:77:19)\n    at /usr/src/app/node_modules/@nestjs/core/router/router-proxy.js:9:23\n    at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)\n    at trim_prefix (/usr/src/app/node_modules/express/lib/router/index.js:323:13)\n    at /usr/src/app/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/usr/src/app/node_modules/express/lib/router/index.js:341:12)\n    at next (/usr/src/app/node_modules/express/lib/router/index.js:275:10)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:127:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)"}
    DEBUG: Checking http://localhost:3000/openapi.yaml
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /openapi.yaml HTTP/1.1
    Host: localhost:3000
    Accept: application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    
    
    DEBUG: Got response from server in 3.5798ms:
    HTTP/1.1 404 Not Found
    Content-Length: 1440
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5a0-sM+ZWzS94S0FALo0tDPatPOwpI4"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"statusCode":404,"code":"NotFoundException","message":"Cannot GET /openapi.yaml","timestamp":1671440691699,"stackTrace":"NotFoundException: Cannot GET /openapi.yaml\n    at callback (/usr/src/app/node_modules/@nestjs/core/router/routes-resolver.js:77:19)\n    at /usr/src/app/node_modules/@nestjs/core/router/router-proxy.js:9:23\n    at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)\n    at trim_prefix (/usr/src/app/node_modules/express/lib/router/index.js:323:13)\n    at /usr/src/app/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/usr/src/app/node_modules/express/lib/router/index.js:341:12)\n    at next (/usr/src/app/node_modules/express/lib/router/index.js:275:10)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:127:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)"}
    DEBUG: Checking http://localhost:3000/apidoc/cli-json/openapi.json
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /apidoc/cli-json/openapi.json HTTP/1.1
    Host: localhost:3000
    Accept: application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,application/cbor;q=0.9,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    X-Cli-Secret: 4417b5ed-ff8a-45f6-aeac-6a9d85c84e60
    
    
    DEBUG: Got response from server in 7.1564ms:
    HTTP/1.1 404 Not Found
    Content-Length: 1472
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5c0-fi1Jz4PRlrdYKf0TQLzUvbIMEyI"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"statusCode":404,"code":"NotFoundException","message":"Cannot GET /apidoc/cli-json/openapi.json","timestamp":1671440691703,"stackTrace":"NotFoundException: Cannot GET /apidoc/cli-json/openapi.json\n    at callback (/usr/src/app/node_modules/@nestjs/core/router/routes-resolver.js:77:19)\n    at /usr/src/app/node_modules/@nestjs/core/router/router-proxy.js:9:23\n    at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)\n    at trim_prefix (/usr/src/app/node_modules/express/lib/router/index.js:323:13)\n    at /usr/src/app/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/usr/src/app/node_modules/express/lib/router/index.js:341:12)\n    at next (/usr/src/app/node_modules/express/lib/router/index.js:275:10)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:127:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)"}
    DEBUG: Checking http://localhost:3000/apidoc/cli-json/openapi.yaml
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /apidoc/cli-json/openapi.yaml HTTP/1.1
    Host: localhost:3000
    Accept: text/*;q=0.2,application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    X-Cli-Secret: 4417b5ed-ff8a-45f6-aeac-6a9d85c84e60
    
    
    DEBUG: Got response from server in 3.8443ms:
    HTTP/1.1 404 Not Found
    Content-Length: 1472
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5c0-foX7DW5d75ANfxDzvONwAdqsrT4"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"statusCode":404,"code":"NotFoundException","message":"Cannot GET /apidoc/cli-json/openapi.yaml","timestamp":1671440691710,"stackTrace":"NotFoundException: Cannot GET /apidoc/cli-json/openapi.yaml\n    at callback (/usr/src/app/node_modules/@nestjs/core/router/routes-resolver.js:77:19)\n    at /usr/src/app/node_modules/@nestjs/core/router/router-proxy.js:9:23\n    at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)\n    at trim_prefix (/usr/src/app/node_modules/express/lib/router/index.js:323:13)\n    at /usr/src/app/node_modules/express/lib/router/index.js:284:7\n    at Function.process_params (/usr/src/app/node_modules/express/lib/router/index.js:341:12)\n    at next (/usr/src/app/node_modules/express/lib/router/index.js:275:10)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:127:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)\n    at next (/usr/src/app/node_modules/express/lib/router/route.js:131:14)"}
    DEBUG: Checking http://localhost:3000/apidoc/cli-json/
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    GET /apidoc/cli-json/ HTTP/1.1
    Host: localhost:3000
    Accept: application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    X-Cli-Secret: 4417b5ed-ff8a-45f6-aeac-6a9d85c84e60
    
    
    DEBUG: Got response from server in 3.638ms:
    HTTP/1.1 200 OK
    Content-Length: 562
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"232-0U0hjEODOIqXVdfFBBEU2uIz31E"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"openapi":"3.0.0","paths":{"/cli/subscriptions":{"post":{"operationId":"SubscriptionController_startSchedulerCycle","parameters":[],"responses":{"204":{"description":""}},"tags":["Subscription CLI API"],"security":[{"CliSecret":[]}]}}},"info":{"title":"Guidap V2 CLI API","description":"","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"CliSecret":{"type":"apiKey","name":"x-cli-secret","description":"CLI-Secret token","in":"header"}},"schemas":{}},"security":[{"CliSecret":[]}],"x-cli-config":{"security":"CliSecret"}}
    DEBUG: API loading took 47.1928ms
    DEBUG: Configuration: map[app-name:restish config-directory:/home/node/.restish rsh-ca-cert: rsh-client-cert: rsh-client-key: rsh-filter: rsh-header:[] rsh-insecure:false rsh-no-cache:true rsh-no-paginate:false rsh-output-format:auto rsh-profile:default rsh-query:[] rsh-raw:false rsh-server: rsh-verbose:true server-index:0]
    DEBUG: Adding TLS configuration
    DEBUG: Making request:
    POST /cli/subscriptions HTTP/1.1
    Host: localhost:3000
    Accept: application/cbor;q=0.9,application/msgpack;q=0.8,application/ion;q=0.6,application/json;q=0.5,application/yaml;q=0.5,text/*;q=0.2,*/*
    Accept-Encoding: gzip, br
    User-Agent: restish-0.15.1
    
    
    DEBUG: Got response from server in 5.3336ms:
    HTTP/1.1 401 Unauthorized
    Content-Length: 1513
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5e9-qrJKwpkMWVAoizAjzSpKJI2iyIU"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {"statusCode":401,"code":"UnauthorizedException","message":"Unauthorized","timestamp":1671440691735,"stackTrace":"UnauthorizedException: Unauthorized\n    at CliSecretAuthGuard.handleRequest (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:68:30)\n    at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:49:128\n    at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:91:24\n    at allFailed (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:110:18)\n    at attempt (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:183:28)\n    at CliSecretStrategy.strategy.fail (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:305:9)\n    at CliSecretStrategy.Strategy.authenticate (/usr/src/app/node_modules/passport-headerapikey/lib/Strategy.js:48:25)\n    at attempt (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:369:16)\n    at authenticate (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:370:7)\n    at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:96:3\n    at new Promise (<anonymous>)\n    at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:88:83\n    at CliSecretAuthGuard.<anonymous> (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:49:36)\n    at Generator.next (<anonymous>)\n    at fulfilled (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:17:58)\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)"}
    DEBUG: Unmarshalling from application/json
    HTTP/1.1 401 Unauthorized
    Access-Control-Allow-Origin: *
    Connection: keep-alive
    Content-Length: 1513
    Content-Security-Policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
    Content-Type: application/json; charset=utf-8
    Date: Mon, 19 Dec 2022 09:04:51 GMT
    Etag: W/"5e9-qrJKwpkMWVAoizAjzSpKJI2iyIU"
    Expect-Ct: max-age=0
    Keep-Alive: timeout=5
    Referrer-Policy: no-referrer
    Strict-Transport-Security: max-age=15552000; includeSubDomains
    X-Content-Type-Options: nosniff
    X-Dns-Prefetch-Control: off
    X-Download-Options: noopen
    X-Frame-Options: SAMEORIGIN
    X-Permitted-Cross-Domain-Policies: none
    X-Xss-Protection: 0
    
    {
      code: "UnauthorizedException"
      message: "Unauthorized"
      stackTrace: "UnauthorizedException: Unauthorized
            at CliSecretAuthGuard.handleRequest (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:68:30)
            at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:49:128
            at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:91:24
            at allFailed (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:110:18)
            at attempt (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:183:28)
            at CliSecretStrategy.strategy.fail (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:305:9)
            at CliSecretStrategy.Strategy.authenticate (/usr/src/app/node_modules/passport-headerapikey/lib/Strategy.js:48:25)
            at attempt (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:369:16)
            at authenticate (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:370:7)
            at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:96:3
            at new Promise (<anonymous>)
            at /usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:88:83
            at CliSecretAuthGuard.<anonymous> (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:49:36)
            at Generator.next (<anonymous>)
            at fulfilled (/usr/src/app/node_modules/@nestjs/passport/dist/auth.guard.js:17:58)
            at processTicksAndRejections (node:internal/process/task_queues:96:5)"
      statusCode: 401
      timestamp: 1671440691735
    }
    
  • parameters in reference are not picked up.

    parameters in reference are not picked up.

    Looks like support is missing in the upstream openapi library. Being worked on at https://github.com/pb33f/libopenapi/issues/25

    A failing test.

    ›› git diff
    diff --git a/openapi/testdata/petstore/openapi.yaml b/openapi/testdata/petstore/openapi.yaml
    index 030f21f..ee08372 100644
    --- a/openapi/testdata/petstore/openapi.yaml
    +++ b/openapi/testdata/petstore/openapi.yaml
    @@ -60,12 +60,7 @@ paths:
           tags:
             - pets
           parameters:
    -        - name: petId
    -          in: path
    -          required: true
    -          description: The id of the pet to retrieve
    -          schema:
    -            type: string
    +        - $ref: '#/components/parameters/petId'
           responses:
             "200":
               description: Expected response to a valid request
    @@ -109,3 +104,11 @@ components:
               format: int32
             message:
               type: string
    +  parameters:
    +    petId:
    +    in: path
    +    required: true
    +    description: The id of the pet to retrieve
    +    schema:
    +      type: string
    +
    ›› go test ./...
    ok      github.com/danielgtaylor/restish        (cached) [no tests to run]
    ok      github.com/danielgtaylor/restish/cli    (cached)
    ?       github.com/danielgtaylor/restish/oauth  [no test files]
    --- FAIL: TestLoader (0.03s)
        --- FAIL: TestLoader/petstore (0.00s)
            openapi_test.go:240:
                    Error Trace:    /home/r4um/src/restish/openapi/openapi_test.go:240
                    Error:          Not equal:
                                    expected: cli.API{RestishVersion:"", Short:"Swagger Petstore", Long:"", Operations:[]cli.Operation{cli.Operation{Name:"create-pets", Group:"pets", Aliases:[]string{"createpets"}, Short:"Create a pet", Long:"## Response 201\n\nNull response\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"POST", URITemplate:"http://api.example.com/pets", PathParams:[]*cli.Param(nil), QueryParams:[]*cli.Param(nil), HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}, cli.Operation{Name:"list-pets", Group:"pets", Aliases:[]string{"listpets"}, Short:"List all pets", Long:"## Response 200 (application/json)\n\nA paged array of pets\n\nHeaders: Next\n\n```schema\n[\n  {\n    id*: (integer format:int64)\n    name*: (string)\n    tag: (string)\n  }\n]\n```\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"GET", URITemplate:"http://api.example.com/pets", PathParams:[]*cli.Param(nil), QueryParams:[]*cli.Param{(*cli.Param)(0xc0002a8070)}, HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}, cli.Operation{Name:"show-pet-by-id", Group:"pets", Aliases:[]string{"showpetbyid"}, Short:"Info for a specific pet", Long:"## Response 200 (application/json)\n\nExpected response to a valid request\n\n```schema\n{\n  id*: (integer format:int64)\n  name*: (string)\n  tag: (string)\n}\n```\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"GET", URITemplate:"http://api.example.com/pets/{petId}", PathParams:[]*cli.Param{(*cli.Param)(0xc0002a80e0)}, QueryParams:[]*cli.Param(nil), HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}}, Auth:[]cli.APIAuth(nil), AutoConfig:cli.AutoConfig{Headers:map[string]string(nil), Prompt:map[string]cli.AutoConfigVar(nil), Auth:cli.APIAuth{Name:"", Params:map[string]string(nil)}}}
                                    actual  : cli.API{RestishVersion:"", Short:"Swagger Petstore", Long:"", Operations:[]cli.Operation{cli.Operation{Name:"create-pets", Group:"pets", Aliases:[]string{"createpets"}, Short:"Create a pet", Long:"## Response 201\n\nNull response\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"POST", URITemplate:"http://api.example.com/pets", PathParams:[]*cli.Param(nil), QueryParams:[]*cli.Param(nil), HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}, cli.Operation{Name:"list-pets", Group:"pets", Aliases:[]string{"listpets"}, Short:"List all pets", Long:"## Response 200 (application/json)\n\nA paged array of pets\n\nHeaders: Next\n\n```schema\n[\n  {\n    id*: (integer format:int64)\n    name*: (string)\n    tag: (string)\n  }\n]\n```\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"GET", URITemplate:"http://api.example.com/pets", PathParams:[]*cli.Param(nil), QueryParams:[]*cli.Param{(*cli.Param)(0xc0002a8b60)}, HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}, cli.Operation{Name:"show-pet-by-id", Group:"pets", Aliases:[]string{"showpetbyid"}, Short:"Info for a specific pet", Long:"## Response 200 (application/json)\n\nExpected response to a valid request\n\n```schema\n{\n  id*: (integer format:int64)\n  name*: (string)\n  tag: (string)\n}\n```\n\n## Response default (application/json)\n\nunexpected error\n\n```schema\n{\n  code*: (integer format:int32)\n  message*: (string)\n}\n```\n", Method:"GET", URITemplate:"http://api.example.com/pets/{petId}", PathParams:[]*cli.Param(nil), QueryParams:[]*cli.Param(nil), HeaderParams:[]*cli.Param(nil), BodyMediaType:"", Examples:[]string(nil), Hidden:false, Deprecated:""}}, Auth:[]cli.APIAuth(nil), AutoConfig:cli.AutoConfig{Headers:map[string]string(nil), Prompt:map[string]cli.AutoConfigVar(nil), Auth:cli.APIAuth{Name:"", Params:map[string]string(nil)}}}
    
                                    Diff:
                                    --- Expected
                                    +++ Actual
                                    @@ -62,14 +62,3 @@
                                        URITemplate: (string) (len=35) "http://api.example.com/pets/{petId}",
                                    -   PathParams: ([]*cli.Param) (len=1) {
                                    -    (*cli.Param)({
                                    -     Type: (string) (len=6) "string",
                                    -     Name: (string) (len=5) "petId",
                                    -     DisplayName: (string) "",
                                    -     Description: (string) (len=29) "The id of the pet to retrieve",
                                    -     Style: (cli.Style) 0,
                                    -     Explode: (bool) false,
                                    -     Default: (interface {}) <nil>,
                                    -     Example: (interface {}) <nil>
                                    -    })
                                    -   },
                                    +   PathParams: ([]*cli.Param) <nil>,
                                        QueryParams: ([]*cli.Param) <nil>,
                    Test:           TestLoader/petstore
    FAIL
    FAIL    github.com/danielgtaylor/restish/openapi        0.064s
    FAIL
    
  • add multiple requests option flag

    add multiple requests option flag

    I wanted to use restish for some load testing, by importing an openapi definition and having some option like -l which would set the amount of requests per minute or second; the query params or payload could be randomly generated based on the definition, or maybe by providing some input. Have you thought of this kind of usage? I could do some pr as proof of concept.

  • number parsing: raw results != non raw results

    number parsing: raw results != non raw results

    Steps to reproduce:

    1. Create eg: mock api with reply {"id": 573311229116900865}
    2. Use restish, observe number getting "truncated"
    3. Use restish -r, observe raw response

    I know javascript engines will have an issue with eg: this number:

    ❯ node                   
    Welcome to Node.js v13.1.0.
    Type ".help" for more information.
    > 573311229116900865
    573311229116900860
    >
    

    Please advise if this is expected behaviour.

Go net/http configurable handler to handle CORS requests

Go CORS handler CORS is a net/http handler implementing Cross Origin Resource Sharing W3 specification in Golang. Getting Started After installing Go

Jan 7, 2023
Go net/http handler to transparently manage posted JSON

Go JSON handler FormJSON is a net/http handler implementing content negotiation for posted data in order to transparently expose posted JSON as if it

Sep 27, 2022
Fault injection library in Go using standard http middleware

Fault The fault package provides go http middleware that makes it easy to inject faults into your service. Use the fault package to reject incoming re

Dec 25, 2022
Go (golang) library for creating and consuming HTTP Server-Timing headers
Go (golang) library for creating and consuming HTTP Server-Timing headers

HTTP Server-Timing for Go This is a library including middleware for using HTTP Server-Timing with Go. This header allows a server to send timing info

Dec 8, 2022
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Jan 4, 2023
哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务
哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务

哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务

Jan 8, 2023
A SimpleHTTPServer written in Go, enhanced with features and with a nice design
A SimpleHTTPServer written in Go, enhanced with features and with a nice design

goshs is a replacement for Python's SimpleHTTPServer. It allows uploading and downloading via HTTP/S with either self-signed certificate or user provi

Dec 28, 2022
Api-product - A basic REST-ish API that allows you to perform CRUD operations for Products

Description A basic REST-ish API that allows you to perform CRUD operations for

Jan 3, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Jan 2, 2023
protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats

protoCURL protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text forma

Jan 6, 2023
A CLI tool for interacting with Kafka through the Confluent Kafka Rest Proxy

kafkactl Table of contents kafkactl Table of contents Overview Build Development Overview kafkactl is a CLI tool to interact with Kafka through the Co

Nov 1, 2021
ORM-ish library for Go

We've moved! gorp is now officially maintained at: https://github.com/go-gorp/gorp This fork was created when the project was moved, and is provided f

Aug 23, 2022
a high-performance, POSIX-ish Amazon S3 file system written in Go
a high-performance, POSIX-ish Amazon S3 file system written in Go

Goofys allows you to mount an S3 bucket as a filey system.

Dec 23, 2022
GeeseFS is a high-performance, POSIX-ish S3 (Yandex, Amazon) file system written in Go
GeeseFS is a high-performance, POSIX-ish S3 (Yandex, Amazon) file system written in Go

GeeseFS is a high-performance, POSIX-ish S3 (Yandex, Amazon) file system written in Go Overview GeeseFS allows you to mount an S3 bucket as a file sys

Jan 1, 2023
Goofys is a high-performance, POSIX-ish Amazon S3 file system written in Go
Goofys is a high-performance, POSIX-ish Amazon S3 file system written in Go

Goofys is a high-performance, POSIX-ish Amazon S3 file system written in Go Overview Goofys allows you to mount an S3 bucket as a filey system. It's a

Jan 8, 2023
Try - Idiomatic monadic-ish error handling for go

Try Idiomatic monadic-ish error handling for go. Examples import

Jan 24, 2022
A software architecture style example for APIs that utilizes the features of SOLID-Principle.
A software architecture style example for APIs that utilizes the features of SOLID-Principle.

Engelbyte's Waterbyte Clean Architecture A software architecture style example for APIs that utilizes the features of SOLID-Principle. The example sho

Feb 9, 2022
REST based Redis client built on top of Upstash REST API

An HTTP/REST based Redis client built on top of Upstash REST API.

Jul 31, 2022
That's right - order that nice pizza 🍕 with `kubectl`

pizza-controller making kubernetes do what it was always meant to do: order pizza. https://gum.co/kubernetes-crds to get up to speed with custom resou

Sep 27, 2022
🎀 a nice lil shell for lua people made with go and lua

Hilbish ?? a nice lil shell for lua people made with go and lua It is currently in a mostly beta state but is very much usable (I'm using it right now

Jan 3, 2023