Coder Social home page Coder Social logo

danielgtaylor / apisprout Goto Github PK

View Code? Open in Web Editor NEW
693.0 13.0 74.0 176 KB

Lightweight, blazing fast, cross-platform OpenAPI 3 mock server with validation

License: MIT License

Go 98.41% Shell 0.84% Dockerfile 0.75%
openapi openapi3 mock-server docker-image examples hacktoberfest

apisprout's Introduction

API Sprout

Go Report Card Build Status GitHub tag (latest SemVer) Docker Pulls

A simple, quick, cross-platform API mock server that returns examples specified in an API description document. Features include:

  • OpenAPI 3.x support
    • Uses operation examples or generates examples from schema
  • Load from a URL or local file (auto reload with --watch)
  • CORS headers enabled by default
  • Accept header content negotiation
    • Example: Accept: application/*
  • Prefer header to select response to test specific cases
    • Example: Prefer: status=409
  • Server validation (enabled with --validate-server)
    • Validates scheme, hostname/port, and base path
    • Supports localhost out of the box
    • Use the --add-server flag, in conjunction with --validate-server, to dynamically include more servers in the validation logic
  • Request parameter & body validation (enabled with --validate-request)
  • Configuration via:
    • Files (/etc/apisprout/config.json|yaml)
    • Environment (prefixed with SPROUT_, e.g. SPROUT_VALIDATE_SERVER)
    • Commandline flags

Usage is simple:

# Load from a local file
apisprout my-api.yaml

# Validate server name and use base path
apisprout --validate-server my-api.yaml

# Dynamically Include a new server / path in the validation
apisprout --add-server http://localhost:8080/mock --validate-server my-api.yaml

# Load from a URL
apisprout https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/api-with-examples.yaml

Docker Image

A hosted API Sprout Docker image is provided that makes it easy to deploy mock servers or run locally. For example:

docker pull danielgtaylor/apisprout
docker run -p 8000:8000 danielgtaylor/apisprout http://example.com/my-api.yaml

Configuration can be passed via environment variables, e.g. setting SPROUT_VALIDATE_REQUEST=1, or by passing commandline flags. It is also possible to use a local API description file via Docker Volumes:

# Remember to put the full path to local archive YAML in -v
docker run -p 8000:8000 -v $FULLPATH/localfile.yaml:/api.yaml danielgtaylor/apisprout /api.yaml

Installation

Download the appropriate binary from the releases page.

Alternatively, you can use go get:

go get github.com/danielgtaylor/apisprout

Extra Features

Remote Reload

If your API spec is loaded from a remote URL, you can live-reload it by hitting the /__reload endpoint.

Health Check

A simple endpoint which returns status code 200 is available at /__health. This endpoint successfully returns 200 even if --validate-server is turned on, and the endpoint is being accessed from a non-validated host.

Contributing

Contributions are very welcome. Please open a tracking issue or pull request and we can work to get things merged in.

Release Process

The following describes the steps to make a new release of API Sprout.

  1. Merge open PRs you want to release.
  2. Select a new semver version number (major/minor/patch depending on changes).
  3. Update CHANGELOG.md to describe changes.
  4. Create a commit for the release.
  5. Tag the commit with git tag -a -m 'Tagging x.y.z release' vx.y.z.
  6. Build release binaries with ./release.sh.
  7. Push the commit and tags.
  8. Upload the release binaries.

License

Copyright Β© 2018-2019 Daniel G. Taylor

http://dgt.mit-license.org/

apisprout's People

Contributors

adamgall avatar ahx avatar arthuroz avatar danielgtaylor avatar dannycodes avatar deo986 avatar impl avatar pruser avatar shirou avatar timaschew avatar zakcodes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apisprout's Issues

Custom configuration for CORS headers

Summary
CORS headers cannot be customized. As a consequence, we can't ser the Access-Control-Allow-Credentials header, nor set extra headers for Access-Control-Allow-Headers.

Steps to reproduce
Case 1: Mock any valid schema, and make a CORS request with a custom header such as x-foo: bar
Case 2: Mock any valid schema, and make a CORS request using withCredentials (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)

Actual result
The request fails indicating some of this errors, depending on the case:
Case 1: [...] Request header field x-foo is not allowed by Access-Control-Allow-Headers in preflight response
Case 2: [...] Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute

Expected result
The mock server should be able to:

  1. Set/add allowed headers whether via configuration or API schema custom fields
  2. Set CORS allow credentials property (in this case, it should set the header Access-Control-Allow-Credentials: true, and set the Access-Control-Allow-Origin with a dynamic value (with allow-credentials, origin cannot be a wildcard)

DateTime vs "date-time"

Hi, there was a bug in the format validation of the type string. That has been fixed on the master of github.com/getkin/kin-openapi, can you please make a new release and update the docker image. Cheers.

Support __reload for swagger file

Watch is a nice feature but one may wish to control when reloading occurs when file is updated

__reload is currently restricted to http loaded API definition although there is no reason why it should not be allowed for files as well

Will Submit PR based on my previous PR for custom header support during reloading

requestBodies not supported

We are trying to create definitions for requestBodies but get the following issues:

2019/04/28 02:19:58 expected prefix '#/components/schemas/' in URI '#/components/requestBodies/login'

Is this a known issue?

Provide endpoint to reload definition

First of alll, thanks for this awesome tool!

Would be nice to have an endpoint, for instance /__reload which reloads the definition in case it was loaded via an URL. So it’s a kind of an workaround for watch mode on URLs

stack overflow: stack exceeds 1000000000-byte limit fatal error:

When I start my mock server I get a following error after several time:

🌱 Sprouting Eurobank Traktor Payment on port 10000
2019/07/21 08:42:15 POST /v1/authentication/authenticate (Accept application/json) (authenticateUsingPOST) => 201 ()
2019/07/21 08:42:22 POST /v1/authentication/authenticate (Accept application/json) (authenticateUsingPOST) => 200 (application/json)
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x95d16e, 0xe)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/panic.go:617 +0x72
runtime.newstack()
	/usr/local/Cellar/go/1.12/libexec/src/runtime/stack.go:1041 +0x6f0
runtime.morestack()
	/usr/local/Cellar/go/1.12/libexec/src/runtime/asm_amd64.s:429 +0x8f

goroutine 18 [running]:
runtime.heapBitsSetType(0xc01615c7a0, 0x10, 0x10, 0x8a9ee0)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/mbitmap.go:938 +0xa55 fp=0xc024000318 sp=0xc024000310 pc=0x415905
runtime.mallocgc(0x10, 0x8a9ee0, 0x1, 0x8)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/malloc.go:969 +0x51c fp=0xc0240003b8 sp=0xc024000318 pc=0x40b81c
runtime.convTstring(0x95a360, 0x6, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/iface.go:355 +0x5b fp=0xc0240003e8 sp=0xc0240003b8 pc=0x4093eb
main.OpenAPIExample(0x1, 0xc000258b60, 0xc024000628, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:157 +0x1c6 fp=0xc024000540 sp=0xc0240003e8 pc=0x858a26
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c790, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024000698 sp=0xc024000540 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165958, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240007f0 sp=0xc024000698 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c770, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024000948 sp=0xc0240007f0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165838, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024000aa0 sp=0xc024000948 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c750, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024000bf8 sp=0xc024000aa0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165718, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024000d50 sp=0xc024000bf8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c730, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024000ea8 sp=0xc024000d50 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161655f8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024001000 sp=0xc024000ea8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c710, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024001158 sp=0xc024001000 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161654d8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240012b0 sp=0xc024001158 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c6f0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024001408 sp=0xc0240012b0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161653c8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024001560 sp=0xc024001408 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240016b8 sp=0xc024001560 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0240018f8, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024001810 sp=0xc0240016b8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c6c0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024001968 sp=0xc024001810 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165298, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024001ac0 sp=0xc024001968 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c6a0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024001c18 sp=0xc024001ac0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165178, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024001d70 sp=0xc024001c18 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c680, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024001ec8 sp=0xc024001d70 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016165058, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024002020 sp=0xc024001ec8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c660, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024002178 sp=0xc024002020 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164f38, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240022d0 sp=0xc024002178 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c640, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024002428 sp=0xc0240022d0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164e18, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024002580 sp=0xc024002428 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240026d8 sp=0xc024002580 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024002918, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024002830 sp=0xc0240026d8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c620, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024002988 sp=0xc024002830 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164cf8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024002ae0 sp=0xc024002988 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024002c38 sp=0xc024002ae0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024002e78, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024002d90 sp=0xc024002c38 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c600, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024002ee8 sp=0xc024002d90 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164be8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024003040 sp=0xc024002ee8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c5d0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024003198 sp=0xc024003040 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164ac8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240032f0 sp=0xc024003198 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c5a0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024003448 sp=0xc0240032f0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164998, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240035a0 sp=0xc024003448 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240036f8 sp=0xc0240035a0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024003938, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024003850 sp=0xc0240036f8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c580, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240039a8 sp=0xc024003850 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164878, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024003b00 sp=0xc0240039a8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c560, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024003c58 sp=0xc024003b00 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164758, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024003db0 sp=0xc024003c58 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c540, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024003f08 sp=0xc024003db0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164638, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024004060 sp=0xc024003f08 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c520, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240041b8 sp=0xc024004060 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016164518, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024004310 sp=0xc0240041b8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x203005, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024004468 sp=0xc024004310 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161643e8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240045c0 sp=0xc024004468 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x203005, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024004718 sp=0xc0240045c0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161642c8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024004870 sp=0xc024004718 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240049c8 sp=0xc024004870 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024004c08, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024004b20 sp=0xc0240049c8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c4e0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024004c78 sp=0xc024004b20 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161641b8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024004dd0 sp=0xc024004c78 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c4c0, 0x7f240e333488, 0x0, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024004f28 sp=0xc024004dd0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161640a8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024005080 sp=0xc024004f28 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c490, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240051d8 sp=0xc024005080 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163f08, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024005330 sp=0xc0240051d8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c460, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024005488 sp=0xc024005330 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163dd8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240055e0 sp=0xc024005488 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c440, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024005738 sp=0xc0240055e0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163cb8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024005890 sp=0xc024005738 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240059e8 sp=0xc024005890 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024005c28, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024005b40 sp=0xc0240059e8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c420, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024005c98 sp=0xc024005b40 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163b98, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024005df0 sp=0xc024005c98 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c400, 0x0, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024005f48 sp=0xc024005df0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163a78, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240060a0 sp=0xc024005f48 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c3e0, 0x7f240e3331b8, 0x203005, 0x203005)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240061f8 sp=0xc0240060a0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163958, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024006350 sp=0xc0240061f8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c3c0, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240064a8 sp=0xc024006350 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163848, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024006600 sp=0xc0240064a8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c390, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024006758 sp=0xc024006600 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163728, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240068b0 sp=0xc024006758 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x203005, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024006a08 sp=0xc0240068b0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161635e8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024006b60 sp=0xc024006a08 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x203005, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024006cb8 sp=0xc024006b60 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161634c8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024006e10 sp=0xc024006cb8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c340, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024006f68 sp=0xc024006e10 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc0161633b8, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240070c0 sp=0xc024006f68 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c320, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024007218 sp=0xc0240070c0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163298, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024007370 sp=0xc024007218 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c300, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240074c8 sp=0xc024007370 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163178, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024007620 sp=0xc0240074c8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024007778 sp=0xc024007620 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0240079b8, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240078d0 sp=0xc024007778 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c2e0, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024007a28 sp=0xc0240078d0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016163068, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024007b80 sp=0xc024007a28 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c2b0, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024007cd8 sp=0xc024007b80 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016162f48, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024007e30 sp=0xc024007cd8 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x203005, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024007f88 sp=0xc024007e30 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016162e08, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc0240080e0 sp=0xc024007f88 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0x0, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc024008238 sp=0xc0240080e0 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc024008478, 0x0, 0x0, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024008390 sp=0xc024008238 pc=0x8593fc
main.OpenAPIExample(0x1, 0xc0002589c0, 0xc01615c270, 0x0, 0x203003, 0x203003)
	/Users/dan/Projects/apisprout/example.go:183 +0x729 fp=0xc0240084e8 sp=0xc024008390 pc=0x858f89
main.OpenAPIExample(0x1, 0xc000258ea0, 0xc0001a7c8c, 0x4, 0xc016162d08, 0x0)
	/Users/dan/Projects/apisprout/example.go:162 +0xb9c fp=0xc024008640 sp=0xc0240084e8 pc=0x8593fc
...additional frames elided...
created by net/http.(*Server).Serve
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:2884 +0x2f4

goroutine 1 [IO wait, 1 minutes]:
internal/poll.runtime_pollWait(0x7f2410d36f68, 0x72, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/netpoll.go:182 +0x56
internal/poll.(*pollDesc).wait(0xc0000fab98, 0x72, 0x0, 0x0, 0x95a68a)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x9b
internal/poll.(*pollDesc).waitRead(...)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc0000fab80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_unix.go:384 +0x1ba
net.(*netFD).accept(0xc0000fab80, 0xc00003ca70, 0xc00003ca00, 0x40b5e9)
	/usr/local/Cellar/go/1.12/libexec/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc00000f2c0, 0xc00018f9b8, 0xd9f26ffe, 0x86e62ea640e41d19)
	/usr/local/Cellar/go/1.12/libexec/src/net/tcpsock_posix.go:139 +0x32
net.(*TCPListener).AcceptTCP(0xc00000f2c0, 0xc00018f9e0, 0x4ad316, 0x5d34094e)
	/usr/local/Cellar/go/1.12/libexec/src/net/tcpsock.go:247 +0x48
net/http.tcpKeepAliveListener.Accept(0xc00000f2c0, 0xc00018fa30, 0x18, 0xc000000180, 0x6bfc94)
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:3264 +0x2f
net/http.(*Server).Serve(0xc0001f56c0, 0xa13dc0, 0xc00000f2c0, 0x0, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:2859 +0x22d
net/http.(*Server).ListenAndServe(0xc0001f56c0, 0xc0001f56c0, 0xc00018fc78)
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:2797 +0xe4
net/http.ListenAndServe(...)
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:3037
main.server(0xc000124280, 0xc000097cb0, 0x1, 0x3)
	/Users/dan/Projects/apisprout/apisprout.go:601 +0x855
github.com/spf13/cobra.(*Command).execute(0xc000124280, 0xc00001e0d0, 0x3, 0x3, 0xc000124280, 0xc00001e0d0)
	/Users/dan/Projects/pkg/mod/github.com/spf13/[email protected]/command.go:766 +0x2ae
github.com/spf13/cobra.(*Command).ExecuteC(0xc000124280, 0x95b8c2, 0xa, 0x0)
	/Users/dan/Projects/pkg/mod/github.com/spf13/[email protected]/command.go:852 +0x2c0
github.com/spf13/cobra.(*Command).Execute(...)
	/Users/dan/Projects/pkg/mod/github.com/spf13/[email protected]/command.go:800
main.main()
	/Users/dan/Projects/apisprout/apisprout.go:120 +0x822

goroutine 19 [IO wait, 1 minutes]:
internal/poll.runtime_pollWait(0x7f2410d36e98, 0x72, 0xffffffffffffffff)
	/usr/local/Cellar/go/1.12/libexec/src/runtime/netpoll.go:182 +0x56
internal/poll.(*pollDesc).wait(0xc00045c298, 0x72, 0x0, 0x1, 0xffffffffffffffff)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x9b
internal/poll.(*pollDesc).waitRead(...)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc00045c280, 0xc00025e671, 0x1, 0x1, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/internal/poll/fd_unix.go:169 +0x19b
net.(*netFD).Read(0xc00045c280, 0xc00025e671, 0x1, 0x1, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc000548020, 0xc00025e671, 0x1, 0x1, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.12/libexec/src/net/net.go:177 +0x69
net/http.(*connReader).backgroundRead(0xc00025e660)
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:677 +0x58
created by net/http.(*connReader).startBackgroundRead
	/usr/local/Cellar/go/1.12/libexec/src/net/http/server.go:673 +0xca

invalid character 'o' looking for beginning of value

when

docker run --rm -p 8000:8000 danielgtaylor/apisprout http://api.36node.com/petstore/v0/spec

got

invalid character 'o' looking for beginning of value

Any idea?

I've tried with url

https://github.com/OAI/OpenAPI-Specification/raw/master/examples/v3.0/petstore.yaml

it do work

Catch invalid JSON errors in schemas when watching

Summary
When mocking in watch mode, if the schema is not a valid JSON, the whole process exits with code 1 because of an uncaught error: unexpected end of JSON input

Steps to reproduce
Mock an invalid JSON schema. For example:

{"openapi": "3.0.0"

Actual result
The whole process (and the docker container) exit with an error code 1.

Expected result
The process should catch the error, show a controlled error message and keep watching changes until schema is a valid JSON.

More info
This happens if you edit the schema manually while watching, and save the file before you're done editing (this happens a lot when you have a continuoues-save-addiction in you).
Algo happens to me when syncing schemas from AWS S3 to my local machine (I guess it reads the file in the middle of the write operation).

Improve default example based on format property

Summary
When mocking a request that does not provide an example, it auto-generates one based on properties data type. But it doesn't use format prop.

Steps to reproduce
Mock the following request, and call it.

/foo:
  get:
    operationId: getFoo
    responses:
      '200':
        content:
          application/json:
            schema:
              type: object
              properties:
                dateProp:
                  type: string
                  format: "date-time"

Actual result
The API response is
{"dateProp": "string"}

Expected result
{"dateProp": "2019-02-28T18:27:44-03:00"}

More info
It should also check for minLength, maxLength to provide strings; minimum, maximum, exclusiveMinimum and exclusiveMaximum to provide numbers.

Suggested string formats to be supported:

  • date
  • date-time
  • email
  • uuid

Use defined 400 response object when request validation fails

Hi,

When setting up the requestBody validation, is there any way to return the defined 400 response object instead of the text/plain with the json validation info?
In the following example:

---
openapi: 3.0.0
info:
  version: 1.0.0
  title: Mock API
servers:
  - url: http://localhost:19999
paths:
  "/api/3.1/login/":
    post:
      description: Request access token
      operationId: login using client id & secret
      produces:
        - "application/json"
      requestBody:
        description: Client id and secret
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  description: The ID of the client
                  type: string
                  enum:
                    - my_client_id
                client_secret:
                  description: Client secret
                  type: string
                  enum:
                    - very_secret_secret
              required:
                - client_id
                - client_secret
              additionalProperties: false
      responses:
        200:
          description: "/login response"
          content:
            application/json:
              example:
                access_token: '1234567890'
                token_type: doggie
                expires_in: 1000
        400:
          description: "Bad Request. Invalid client ID/secret"
          content:
            application/json:
              example:
                message: "Blablabla, bad request"
                documentation_url: "http://blabla.com"

I get the expected 200 OK with:

curl -X POST -H 'Content-Type:application/json' -H 'Accept-Type:application/json' -i http://localhost:19999/api/3.1/login/ \
-d '{"client_id":"my_client_id", "client_secret": "very_secret_secret"}'

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Sun, 22 Dec 2019 21:58:25 GMT
Content-Length: 82

{
  "access_token": "1234567890",
  "expires_in": 1000,
  "token_type": "doggie"
}%  

But with a different client_secret other than the one defined in the schema enum I get:

curl -X POST -H 'Content-Type:application/json' -H 'Accept-Type:application/json' -i http://localhost:19999/api/3.1/login/ \ 
-d '{"client_id":"my_client_id", "client_secret": "invalid_secret"}'

HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Date: Sun, 22 Dec 2019 21:58:47 GMT
Content-Length: 271
Content-Type: text/plain; charset=utf-8

Request body has an error: doesn't input the schema: Error at "/client_secret":JSON value is not one of the allowed values
Schema:
  {
    "description": "Client secret",
    "enum": [
      "very_secret_secret"
    ],
    "type": "string"
  }

Value:
  "invalid_secret"

while what I would really like was the object I defined, i.e.:

{
  "message": "Blablabla, bad request",
  "documentation_url": "http://blabla.com"
}

Do you have any idea how I could achieve this? Thank you.

apisprout is rejecting perfecly valid json references

I have in my main spec document something like this:

components:
  ListOfWidgets:
    $ref: 'parts/widget/model.yaml#/ListOfWidgets`
  Widget:
    $ref: 'parts/widget/model.yaml#/Widget`

And parts/widget/model.yaml looks something like this:

ListOfWidgets:
  type: array
  items:
    $ref: '#/Widget'

Widget:
  properties:
    id:
      type: string
    description:
      type: string

apisprout rejects this because:

2019/05/31 14:37:49 expected prefix '#/components/schemas/' in URI '#/ListOfWidgets'

That seems unreasonable. apisprout should not be enforcing restrictions on the organization of documents. These are not schemas because the path includes #/components/schemas; they are schemas because they are included by reference in the schemas section of the specification.

openapi3.SwaggerLoader has no field or method LoadSwaggerFromYAMLData

Env

go version go1.11.5 darwin/amd64

Issue

when i run

go get github.com/danielgtaylor/apisprout

I got Errors:

danielgtaylor/apisprout/apisprout.go:280:24: loader.LoadSwaggerFromYAMLData undefined (type *openapi3.SwaggerLoader has no field or method LoadSwaggerFromYAMLData)

/__reload route does not use custom headers

When starting apisprout --header "CustomerHeader: value" uri, apisprout will as expected load the swagger definition at uri provided using the custom header provided. We use it to provide a security access token to access the protected uri resource.

When asking apisprout to reload the definition via a /__reload call:

  • custom header won't be used
  • download will fail (our server reports a 404 if our security heaser isn't sent)
  • apisprout will display 'Reloaded from uri" message and no error is reported
  • apisprout won't fail and will keep on working assuming an empty definition has been provided (all calls to apisprout will result in 404)

Will try to provide a fix via a PR.

Missing "motivation" section in readme

Hello

First of all, thank you open-sourcing your code, I understand it is not easy to maintain in wild public. I am deciding which mock server generator from OpenAPI v3 specification to use and "motivation" section in readme would really help people like me to choose.
I am expecting form such docs section to get insight why you created new library instead of using already existing solutions https://openapi.tools/#mock. What was the motivation, what are/were you missing in existing solutions.
Could you please create one?

Thanks
Good luck!
Ctibor

Enforce security scheme

Preface

For me, it'd be a really neat feature if my OpenAPI spec defined a security scheme for endpoints, and that apisprout could enforce these to some extent.

Authentication

From https://swagger.io/docs/specification/authentication/.

Basic Authentication

Per the documentation, we can validate the Authorization header is of the Basic type, along with ensuring a base64 encoded value is passed, that when decoded, matches the regexp: ^\w+:.[^:]+$

API Keys

API Keys could be passed in either the query parameter, the header, or a cookie.

Depending on what is defined the spec, I think we can just ensure the defined value is present.

Bearer Authentication

Similarly to authentication, we could just validate that a value is provided under the Authorization: Bearer %s header.

OAuth 2.0

I think this one could be missed.

OpenID Connect Discovery

Unsure how to implement.

Cookie Authentication

Unsure how to implement.

Additional Considerations

401

Some paths will specify a 401 response, we'd want to ensure we serve this matching response along with any example given

Strictness

Ideally it should be strongly define how strict we match and enforce the security schemes. Whether we just check a value exists, or we additionally check the correct format.

Need

Does anyone else actually need this? Is this a useful feature for anyone?

Unsupported format value uriref

$ apisprout https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/uspto.yaml

2019/10/06 12:18:18 Caught panic while trying to load: Validating Swagger failed: Unsupported 'format' value 'uriref'

Add response headers to mock

Currently, responses don't include the headers defined in the schema.

For example:

paths:
  /hello:
    get:
      summary: Hello world
      responses:
        '200':
          description: OK
          headers:
            x-foo:
              schema:
                type: string
                example: bar
          content:
            application/json:
              schema:
                type: object
                properties:
                  foo:
                    type: string

Should return x-foo: bar as a response header.

Add optional suppoort for headers while getting yaml file

I need to start a mock server using an api.yaml file on my gitlab repo, but it requires an http header to be added such as "PRIVATE-TOKEN: <your_access_token>", but the code here is not reading optional headers/parameters:
(apisprout.go line 315) resp, err := http.Get(uri)

I tried to add req.Header.Add but my Go programming skills are horrible.
Thanks!

Gopkg.lock have a issue about openapi3filter

Thank you for developing apisprout!!! It's really helpful :)

I found Gopkg.toml setting doesn't catch up with kin-openapi update
update contents is like getkin/kin-openapi@fa639d0

when I load openapi.json, apisprout cause panic like blow

panic: Validating Swagger failed: Security scheme of type 'apiKey' should have 'in'. It can be 'query' or 'header', not 'cookie'

kin-openapi have already handle https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject, but latest apisprout image still give above messeage...

So I clone this repository and remove Gopkg.lock and build docker on the local machen then it works
I think I might have not hanlde this issue by removing lock file. I'm not tottaly familier with go and go dependency though.

Sorry for just repoting but I post it because I feel it helps someone If they have encounted same problem.

By the way I really appliciate apisprout!!

json: cannot unmarshal bool into Go value of type string

So this might be a problem in the OpenAPI, but the error is quite long. Perhaps someone has some insight.

Reproducer:

git clone https://github.com/jdegre/5GC_APIs
# commit da92f21c0e6b2b112f79670eb61cf9f7617bba22 as of right now
cd 5GC_APIs
apisprout TS32291_Nchf_ConvergedCharging.yaml

gives the attached long error, ending with:

Error while unmarshalling property 'required' (*[]string): json: cannot unmarshal bool into Go value of type string

apisprout.log

Media Types with charset not accepted

Having a media type containing the optional charset part lets the mock server fail.

2020/02/10 14:46:31 GET /health (checkHealth) => 200 (application/json;charset=UTF-8)
2020/02/10 14:46:31 Cannot marshal as 'application/json;charset=UTF-8'!

With the following spec for example

/pet/findByStatus:
    get:
      tags:
      - "pet"
      summary: "Finds Pets by status"
      description: "Multiple status values can be provided with comma separated strings"
      operationId: "findPetsByStatus"
      produces:
      - "application/json; charset=utf-8"

Circular reference causes memory leak / crashes

Take this scenario

file1.yaml

field:
  $ref: './file2.yaml#/components/schemas/Something'

file2.yaml

AnotherThing:
  $ref: './file1.yaml#/components/schemas/SomethingElse'

Currently apisprout will spike in memory usage or crash in such a scenario, even though references are resolvable.

Cannot generate example with allOf

First of all, I'd like to thank you for this awesome tool. Keep up the good work!

Now, straight to the point. While tinkering with apisprout, I noticed that it cannot generate examples to respond with if the response model inherits from another schema.

Steps to Reproduce

Given the following specification:

openapi: '3.0.0'

info:
  title: Test API
  version: '0.1.0'

paths:
  /test:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ExtendedType'

components:
  schemas:
    BaseType:
      type: object
      properties:
        xx:
          type: string
          example: aaa
        yy:
          type: string
          example: bbb
    ExtendedType:
      allOf:
        - $ref: '#/components/schemas/BaseType'
        - type: object
          properties:
            zz:
              type: string
              example: ccc

When I start the mock server and issue a GET /test request:

apisprout test.yml
curl localhost:8000

I expect an HTTP/1.1 200 OK response with the following payload:

{
  "data": [
    {
      "xx": "aaa",
      "yy": "bbb",
      "zz": "ccc"
    }
  ]
}

Instead, the mock server responds with

HTTP/1.1 418 I'm a teapot
No example available.

Cannot generate &ref examples (examples defined in components)

When an example is defined in "components>examples"
components: examples: ResponseObjectExample: value: we gonna STOP now
and then referenced(&ref) in the path>responses>content>example
... responses: 200: description: We gonna STOP now content: application/json: schema: $ref: "#/components/schemas/ResponseObject" example: $ref: "#/components/examples/ResponseObjectExample"
the mock response will not contain the actual example but the reference as string
#/components/examples/ResponseObjectExample'

BUT
when one defines the example in the path>responses>content>example
responses: 200: description: We gonna STOP now content: application/json: schema: $ref: "#/components/schemas/ResponseObject" example: value: "This is an example"
then all works fine:
{ "value": "This is an example" }

Running on local file

I try to run the command in the README

docker run -p 8000:8000 -v $(pwd)/open_api.json:/api.json danielgtaylor/apisprout /api.json

but I get:

open /api.json: permission denied

I don't know much about docker usage, is there a quick way to get around that issue?

Request/Response Mocks Defined As OpenAPI Examples

Issue
A present Open API 3.0 Examples are returned randomly, the only differentiator is setting a Preferred HTTP response code:

         // Choose a random example to return.
	keys := make([]string, 0, len(mt.Examples))
	for k := range mt.Examples {
		keys = append(keys, k)
	}
	selected := keys[rand.Intn(len(keys))]
	return mt.Examples[selected].Value.Value, nil

Request
It would be great if we could define which mocks to return also using path params, query strings, and even request/response payloads. See how Microcks uses this ability: http://microcks.github.io/using/openapi/

Pet Store is serving up teapots

Hey Daniel! Trying out this awesome thing and getting teapot responses instead of valid mocks:

docker run -p 8000:8000 danielgtaylor/apisprout https://raw.githubusercontent.com/OAI/OpenAPI-Specification/OpenAPI.next/examples/v3.0/petstore.yaml

Responses:

http --json GET http://localhost:8000/pets
HTTP/1.1 418 I'm a teapot
Content-Length: 21
Content-Type: text/plain; charset=utf-8
Date: Fri, 27 Jul 2018 14:23:04 GMT

No example available.

Any ideas? The --json switch sets Accept: application/json which I assume is how you determine the responses. Had the same problem in Postman.

Add option to set a basepath for every path

Summary
If servers url contain a base path (for example: https://example.com/api), when you mock it you loose that base path.

Steps to reproduce
Mock the following schema:

openapi: 3.0.0
info:
  description: Example API
  title: Example API
  version: 1.0.0

servers:
  - url: 'https://example.com/api'
    description: The Example API server

paths:
  /foo:
    get:
      operationId: getFoo
      responses:
        '200':
          content:
            application/json:
              schema:
                type: object
                properties:
                  bar:
                    type: string

Actual result
The API endpoint is mocked as http://localhost/foo

Expected result
The API endpoint should be mocked as http://localhost/api/foo

More info
Suggested solutions
a) Add an optional argument to include server.url basepath in every endpoint (eg: --include-base-path for cli)
b) Add an optional argument to define a basepath for every endpoint (eg: --basepath=/api for cli)

Support version flag when getting with `go get github.com/danielgtaylor/apisprout`

Thank you for creating this great tool.

I would like to see version of apisprout when I get it with go get github.com/danielgtaylor/apisprout .

Currently, I got Error: unknown flag: --version since a binary from go get isn't generated from govvv build in release.sh

Step to encounter the unkown flag error.

$ go get github.com/danielgtaylor/apisprout
$ which apisprout
/my-GOPATH/go/bin/apisprout
$ apisprout --version
Error: unknown flag: --version
Usage:
.
.
.

Support reading $ref: #/paths/*

Currently APISprout has strict behavior where it expects $ref to be pointing to components/schemas only. However standard resolver tools like Speccy resolves paths to something like these:

field:
  $ref: '#/paths/inventory~get~blahblah/get/responses/200/content/application~1json/schema/items/**'

As per OpenAPI standards as well above behavior is allowed, although not ideal.

So instead of failing, $refs should be read/crawled regardless of where they point.

Add support for displaying the Swagger UI

It would be really helpful if the server could also display the Swagger UI for the OpenAPI Spec so that people could easily testing things out without having to resort to CURL or Postman or the like.

CORS configuration

Hi, I'm using this apisprout in web development project.

I'm happy if it has configuration to add Access-Control-Allow-Origin HTTP Header.
Currently, I have to add some proxy.

Improve default example based on enum property

Summary
When mocking a request that does not provide an example, it auto-generates one based on properties data type. But it doesn't use enum prop.

Steps to reproduce
Mock the following request, and call it.

/foo:
  get:
    operationId: getFoo
    responses:
      '200':
        content:
          application/json:
            schema:
              type: object
              properties:
                enumProp:
                  type: string
                  enum: ["foo", "bar"]

Actual result
The API response is
{"enumProp": "string"}

Expected result
{"enumProp": "foo"}
or
{"enumProp": "bar"}

It could respond always the first one, or a random element containen in the enum.

APISprout in Container can't download from untrusted SSL Web server

APISprout in Docker Image can't download an OpenAPI file from a SSL Web server that is signed with a private authority.

$ ./apisprout https://localhost:8080/api.yml
2020/02/05 23:08:28 Get https://localhost:8080/api.yml: x509: certificate signed by unknown authority

However update-ca-certificates is present into the image (see Dockerfile).

I suggest you to modify the Dockerfile to run update-ca-certificates at APISprout startup by replacing

ENTRYPOINT ["/usr/local/bin/apisprout"]

with

COPY startup.sh /startup.sh
RUN chmod +x /startup.sh
ENTRYPOINT  [ "/startup.sh" ]

and adding this new startup.sh file:

#!/bin/sh
update-ca-certificates
/startup.sh

Support ETag and Last-Modified in Response

Docker Image used: 6c07143937e57095d8478efc8ab7eab52b44e67c7673285f8c0a2bf4a7b137ad

openapi: 3.0.3
info:
  title: test
  version: '1.0'
servers:
  - url: 'http://localhost:8000'
paths:
  /test:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    default: 'true'
              examples:
                a:
                  value:
                    ok: true
          headers:
            ETag:
              schema:
                type: string
              example: '"c561c68d0ba92bbeb8b0f612a9199f722e3a621a"'
            Last-Modified:
              schema:
                type: string
              example: Mon, 18 Jul 2016 02:36:04 GMT

Will return:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Etag: string
Last-Modified: string
Date: Thu, 23 Apr 2020 22:38:43 GMT
Content-Length: 16

Either the example values should be provided or (better) real values should be generated.

Unsupported 'format' value 'uuid'

When I have a string with a format of "uuid" I get the above error.

An example is as follows:

     requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sourceSystemId:
                  type: string
                  format: uuid
                  example: dd7d8481-81a3-407f-95f0-a2f1cb382a4b

Add support for readOnly and writeOnly properties

Summary
Apisprout does not support readOnly and writeOnly attributes of properties.

Steps to reproduce
Mock this schema:

paths:
  /foo:
    get:
      operationId: getFoo
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/fooSchema"
    post:
      operationId: postFoo
      requestBody:
        description: The state to set to the alarm
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/fooSchema"

components:
  schemas:
    fooSchema:
      type: object
      properties:
        normalProp:
          type: string
        readOnlyProp:
          readOnly: true
        writeOnlyProp:
          writeOnly: true
      required:
        - normalProp
        - readOnlyProp
        - writeOnlyProp

Actual result
In GET operation, the example includes writeOnlyProp. In POST operation it requires readOnlyProp.

Expected result

  1. It shouldn't include writeOnly properties in auto-generated examples. The response should be:
{
  "normalProp": "string",
  "readOnlyProp": "string"
}
  1. It shouldn't require readOnly properties in the request body. This request body should be valid:
{
  "normalProp": "foo",
  "writeOnlyProp": "bar"
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.