File: README.md
[![CircleCI][circle_ci_image]][circle_ci]
Prism Overview
Prism is a set of packages for API mocking and contract testing with OpenAPI v2 (formerly known as Swagger) and OpenAPI v3.x.
Prism provides:
- Mock Servers: Life-like mock servers from any API specification document.
- Validation Proxy: Contract Testing for API consumers and developers.
- Comprehensive API Specification Support: OpenAPI v3.1, OpenAPI v3.0, OpenAPI v2.0 (formerly Swagger) and Postman Collections.
Ways to Use Prism
Hosted Prism
Stoplight provides hosted mock servers for convenience so that API consumers can experiment with an API without the need for backend code.
Use one of these options for instant, hosted mock servers:
- Stoplight Platform: Collaborative API Design Platform for designing, developing and documenting APIs with hosted mocking powered by Prism.
- Stoplight Studio: Free visual OpenAPI designer that comes integrated with mocking powered by Prism.
Learn more in the hosted Prism documentation.
Self-hosted Prism
Prism is an open-source HTTP server run from the command-line. It provides mocking, request validation, and content negotiation. Use it standalone tool or in continuous integration.
Installation and Usage
This information refers to Open Source Prism 3.x, which is the current version most likely you will use. If you're looking for the 2.x version, look at the 2.x branch
Install Self-hosted Prism
Prism requires
- NodeJS >= 18.20.1
- for NodeJS 18.x, >= 18.16 is required
npm install @stoplight/prism-cliFor more installation options, see our installation documentation.
Mocking
Prism can help you create a fake "mock" based off an OpenAPI document, which helps people see how your API will work before you even have it built. Run it locally with the prism mock command to run your API on a HTTP server you can interact with.
prism mock https://raw.githack.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yamlLearn more about how the mock server works.
Validation Proxy
Prism can help you check for discrepencies between your API implementation and the OpenAPI document that describes, letting you funnel HTTP traffic through it with the prism proxy command.
prism proxy examples/petstore.oas2.yaml https://petstore.swagger.io/v2Learn more about how the validation proxy works.
๐ Documentation and Community
โ FAQs
Cannot access mock server when using Docker?
Prism uses localhost by default, which usually means 127.0.0.1. When using docker the mock server will
be unreachable outside of the container unless you run the mock command with -h 0.0.0.0.
Why am I getting 404 errors when I include my basePath?
OpenAPI v2.0 had a concept called "basePath", which was essentially part of the HTTP path the stuff
after host name and protocol, and before query string. Unlike the paths in your paths object, this
basePath was applied to every single URL, so Prism v2.x used to do the same. In OpenAPI v3.0 they
merged the basePath concept in with the server.url, and Prism v3 has done the same.
We treat OAS2 host + basePath the same as OAS3 server.url, so we do not require them to go in
the URL. If you have a base path of api/v1 and your path is defined as hello, then a request tohttp://localhost:4010/hello would work, but http://localhost:4010/api/v1/hello will fail. This
confuses some, but the other way was confusing to others. Check the default output of Prism CLI to
see what URLs you have available.
๐ง Roadmap
- Content Negotiation
- Security Validation
- Validation Proxy
- Recording/Learning Mode (create OpenAPI from HTTP traffic)
- Data Persistence (allow Prism act like a sandbox)
Submit your ideas for new functionality on the Stoplight Roadmap.
๐ Help Others Utilize Prism
If you're using Prism for an interesting use case, contact us for a case study. We'll add it to a list here. Spread the goodness ๐
๐ Contributing
If you are interested in contributing to Prism itself, check out our contributing docs โ and code of conduct โ to get started.
๐ Thanks
Prism is built on top of lots of excellent packages, and here are a few we'd like to say a special thanks to.
Check these projects out!
๐ฒ Sponsor Prism by Planting a Tree
If you would like to thank us for creating Prism, we ask that you buy the world a tree.
File: docs/guides/01-mocking.md
HTTP Mocking
Prism's HTTP mock server simulates a real web API by providing endpoints and validation rules described in your API description document. This allows client developers to begin writing code for frontend services like web, mobile, or other backend applications, while API developers are still writing code. This can help find and solve problems early on, before the API is built, because changing all that code can be expensive.
- Does the API contain the information the client needs?
- Is that data in the format the client needs?
- Are the resources too "normalized" and data-centric (instead of being use-case centric) that the client has to make 3292375 calls to get all the data they need?
- Is there enough time left for feedback to be implemented?
- If the feedback spawns large enough work, will the client have time to implement this API once it's done?
You can avoid these problems by getting a free API to play with without spending a month building it all.
Catching problems early on while you're still just tweaking the API descriptions (maybe using Stoplight Studio), means you can avoid making costly changes to the production API, deprecating old things, or creating whole new global versions which add a huge workload to every single client.
Just like HTTP messages, there are two halves to mocking: requests and responses.
Response Generation
Prism will try to return meaningful responses based on whatever information it has available, like response examples, and use various fallback mechanisms in case no examples were provided. This means any OpenAPI description document can be used with no extra work, but better documents provide better results.
The first thing to understand is that the Prism HTTP Server respects Content Negotiation. If your API is a mixture of JSON, XML and form data, you can use Accept
and Content-Type just like with a real API, and it should work as expected, or fail if you request non-existent types.
Prism Decision Engine
Prism responses are based on the following decision diagram.
/* Detailed source-code truncated for AI context efficiency. */Response Examples
If a response has an example, it will be used for that response. If there are multiple examples, then they can be selected by name. In the following OpenAPI description, the operation has a 200 OK response and multiple examples:
responses:
'200':
content:
application/json:
schema:
'$ref': '#/components/schemas/Pet'
examples:
cat:
summary: An example of a cat
value:
id: 2
name: Fluffy
photoUrls: []
dog:
summary: An example of a dog
value:
id: 1
name: Spot
photoUrls:
- https://images.dog.ceo/breeds/kelpie/n02105412_893.jpgCalling curl http://127.0.0.1:4010/pets/123 on this will give:
{
"id": 2,
"name": "Fluffy",
"photoUrls": []
}Calling the same URL with the Prefer header example=dog http://127.0.0.1:4010/pets/123 will yield to:
{
"id": 1,
"name": "Spot",
"photoUrls": ["https://images.dog.ceo/breeds/kelpie/n02105412_893.jpg"]
}Remember to provide an expected response code
It's always worth indicating the HTTP response code from which
exampleshould be taken. If Prism decides to change the response code due to validation or security violations, yourexamplemight be ignored.
Static or Dynamic Generation
By default, Prism uses a static generation strategy, which is outlined below. You can enable the dynamic examples generation by using the -d flag in the command line.
prism mock api.oas3.yaml # Static examples
prism mock -d api.oas3.yaml # Dynamic examplesIf the HTTP server has been started in static mode, specific calls can be made in dynamic mode by specifying the Prefer header with the dynamic key set to true.
Static Response Generation
If the provided OpenAPI Schema Object has a response body example, it's used to provide a response.
If not, a response body will be created by looking through the whole schema object (following any $ref's it finds along the way) to create a full fake response.
- If the property has a default value, then it will return the specified value.
- If the property has an
examplesvalue, then it will return the first element in the array. - If the property has neither an example nor a default value and is nullable, it will return null.
- If the property has neither an example nor a default value and isn't nullable, but has a
formatspecified, then it will return a meaningful static value according to the format. - If the property has neither an example nor a default value, isn't nullable, and has no
formatspecified, then it will return'string'in case of a string and0in case of a number.
For example, this is a schema component found in an OpenAPI description document:
Pet:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
example: doggie
photoUrls:
type: array
items:
type: stringWhen you call curl http://127.0.0.1:4010/pets/123, the operation references this component and a doggie is returned:
{
"id": 0,
"name": "doggie",
"photoUrls": ["string"]
}Notice that name had an example with a value so Prism used it, but photoUrls didn't, so it just returned "string".
Users also have the option to use the command-line flag --ignoreExamples. When present, and in static mode, the flag tells Prism to treat the spec as if it doesn't have any response examples defined. In this case, Prism continues to do what it already does in static mode when no response example are present, which is to return an example that has not been generated using json-schema-faker, but was created by Prism (it replicates the behavior of the situation just above where no response examples are given in the schema). However, when the --ignoreExamples flag is present, and in dynamic mode, the flag is essentially ignored, since in dynamic mode, examples are not consulted and json-schema-faker is used to generate a response based on the schema defined in the spec.
Dynamic Response Generation
Testing against the exact same piece of data over and over again isn't the best way to build a robust integration. What happens when a name is longer than you expected, or the value happens to be 0 instead of 6?
Dynamic mode solves this by generating a random value for all the properties according to their type, and other information like format or even by using the Faker library.
Read more about how to use Faker in Dynamic Response with Faker.
Request Validation
Having a mock server that only gives responses would not be useful, which is why Prism imitates request validation too. An OpenAPI description document is full of validation rules like type, format, max length, etc. Prism can validate incoming messages and provide validation feedback if it receives invalid requests.
Read more about this in the Prism Request Validation guide.
Deprecating operations
If an operation is marked as deprecated: true then Prism adds Deprecation: true header to the response.
File: docs/guides/02-request-validation.md
Request Validation
Based on the API description document, Prism can take educated guesses at all sorts of validation rules for the request body, headers, query parameters, using keywords like type, format, maxLength, etc.
It can also fail with 401 if security information is missing, and do a bunch of other things the API description document says the real API will do.
Prism evaluates paths in the order they are listed in the API specification.
Parameter Validation
Requests which expect a request body, query parameter, or a path parameter, will be validated.
For example, make a POST with a JSON body that's missing the required name parameter.
curl -X POST -s -D "/dev/stderr" -H "content-type: application/json" -d '{"tag":"Stowford"}' http://127.0.0.1:4010/petsIn this case, Prism will:
- Look for a response with status code
422on the operation you were trying to execute. - If there's not a
422defined, it will look for a response with status code400on the operation you were trying to execute. - In case there's neither a
422nor a400defined, Prism will create a422response code for you indicating the validation errors it found along the way. Such response will have a payload conforming to the application/problem+json specification.
Since the operation hasn't any error response defined, Prism will generate a 422 response:
HTTP/1.1 422 Unprocessable Entity
content-type: application/problem+json
content-length: 380
Date: Fri, 05 Jul 2019 07:56:18 GMT
Connection: keep-alive
{
"type" : "https://stoplight.io/prism/errors#UNPROCESSABLE_ENTITY",
"title" : "Invalid request.",
"detail" : "Your request is not valid and no HTTP validation response was found in the spec, so Prism is generating this error for you.",
"status" : 422,
"validation" : [
{
"message" : "should have required property 'name'",
"severity" : "Error",
"code" : "required",
"location" : [
"body"
]
}
]
}This error shows effectively that the request is missing a required property name from the HTTP request body.
Pairing a GET with a request body is another example of a 422 response you may receive.
Server Validation
OpenAPI allows the entire API, or certain operations, to be associated with specific servers.
To make sure the server URL you plan to use is a valid server for the API, or for the particular operation you are attempting, provide it as a __server query parameter.
Take this minimalist OpenAPI example:
openapi: 3.0.2
paths:
'/pet':
get:
responses:
'200':
content:
'*/*':
schema:
type: string
example: hello world
servers:
- url: https://stoplight.io/api
name: Production
- url: https://stag.stoplight.io/api
name: StagingYou can make a request enforcing server validation by providing the __server query string parameter:
curl http://localhost:4010/pet?__server=https://stoplight.io/api
hello worldOn the other hand, putting a server which isn't defined in the specification:
curl http://localhost:4010/pet?__server=https://nonsense.com/apiWill give you the following error:
{
"type": "https://stoplight.io/prism/errors#NO_SERVER_MATCHED_ERROR",
"title": "Route not resolved, no server matched.",
"status": 404,
"detail": "The server url http://nonsense.com/api hasn't been matched with any of the provided servers"
}File: docs/guides/03-validation-proxy.md
Validation Proxy
Unlike mocking, the validation proxy expects there to be a real API running somewhere. This could be a localhost environment, docker container, hosted sandbox environment, or a production environment.
The proxy feature will help you identify discrepancies between the OpenAPI document and any other server you designate as the target. This can help frontend developers integrating with your API, or other backend developers, who might want to channel their requests through Prism to see if they're making valid requests. The proxy can also be enabled in staging or any other pre-production environment, like a dress rehearsal before the opening night of a play.
Use Cases
Assisting API Consumer Integration
In the design-first workflow, mocking gives your team something to use before the API exists. Then, when enough feedback has come in and the API developers have decided to start coding the API, the hope is that the real API matches the mock API. If it matches, the existing development work done by the API consumers during the feedback stage means that integrating the real API should involve little to no work. Sadly, subtle differences often go unnoticed, with properties changing slightly, or being removed completely.
API consumers can funnel their development traffic through Prism running as proxy, and then relay that traffic to the API-in-progress. It reports any mistakes it notices along the way, either with the requests you're sending or the responses coming back from the server.
In this use case, the OpenAPI documents are provided by the API team, distributed to the API consumers, and the proxy server points to the development environment. Also, enable --errors so Prism alerts you if a mismatch is noticed.
prism proxy reference/backend/openapi.yaml http://localhost:3000 --errorsThe proxy URL must begin with the protocol (
http,https).
End-to-End Contract Testing
Before the design-first workflow, folks would often slap together their own API descriptions, often by hand, and often just eyeball it for correctness. Various tools came and went for trying to test the correctness of their API description documents, but they were often awkward flaky test-suites that people ended just turning off. Adding contract testing to existing test-suites is now easy with Prism.
Teams with existing end-to-end test suites can drop Prism into this testing environment, and change some environment variables (or service catalog) to point to Prism Proxy. Each time API A talks to API B, or B to C, it will be going via C, so if any of the APIs make an invalid request the whole test suite can fail.
prism proxy reference/api-a/openapi.yaml api-a-test.example.com --errors -p 5000
prism proxy reference/api-b/openapi.yaml api-b-test.example.com --errors -p 5001
prism proxy reference/api-c/openapi.yaml api-c-test.example.com --errors -p 5002This adds contract testing to an existing test suite, regardless of the language your APIs are written in, without any changes required to the codebases.
Unimplemented Operations will be Mocked
In case the upstream server responds with the 501 status code, Prism will try to mock the call using the provided OpenAPI document.
Live Contract Testing
Now you can use Prism to test traffic against the API description. This could be done in development, but it could also be placed in staging, QA, or some sort of pre-production environment. Probably keep it out of production, because even though Prism is quick like a fox, introducing anything to the critical path of your API is probably not what you want.
Deprecating operations
If an operation is marked as deprecated: true, Prism adds Deprecation: true header to the response if the response from remote server doesn't already contains that header.
Future versions of Prism will include ways to sniff existing traffic, without requests being made directly to it, such as sniffing NGINX logs, or piping other forms of traffic through. Get in touch with ideas.
File: docs/guides/04-callbacks.md
Mocking Callbacks with Prism
Callback in OpenPI 3.x defines an outgoing, asynchronous request that your service will make to some other service. Typical real-life example is a code repository. You can subscribe to certain events on a repo (like commit or tag) and your API will start receiving notifications for those events. Another example is one-time notifications. You can subscribe to a invoice paid event and a callback will be invoked when such payment is processed.
Sources:
Callback Example
This example shows how Prism mocks callbacks. There are two services defined: payment-service and client-service. payment-service exposes a subscribe-to-invoice-events method. Client service defines a notification reception endpoint. The goal is to programmatically subscribe to events about certain invoice.
Environment setup
Start payment-service exposing /subscribe callback.
prism mock -p 4010 examples/callbacks/payment-service.oas3.yamlStart client-service exposing /notify operation used for receiving callback requests.
prism mock -p 4011 examples/callbacks/client-service.oas3.yamlRun
Subscribe to callback
curl -v -H'Content-type: application/json' -d'{ "url": "http://localhost:4011/notify", "token": "ssecurre" }' http://127.0.0.1:4010/invoices/123/subscribeNow, the console for payment-service should contain:
[HTTP SERVER] post /invoices/123/subscribe โน info Request received
[NEGOTIATOR] โน info Request contains an accept header: */*
[VALIDATOR] โ success The request passed the validation rules. Looking for the best response
[NEGOTIATOR] โ success Found a compatible content for */*
[NEGOTIATOR] โ success Responding with the requested status code 202
[CALLBACK] โน info actions: Making request to http://localhost:4011/notify?token=ssecurre...
[CALLBACK] โน info actions: Request finishedThe console of client-service:
[HTTP SERVER] post /notify โน info Request received
[NEGOTIATOR] โน info Request contains an accept header: */*
[VALIDATOR] โ success The request passed the validation rules. Looking for the best response
[NEGOTIATOR] โ success Found a compatible content for */*
[NEGOTIATOR] โ success Responding with the requested status code 200After subscribing via /subscribe, Prism successfully invoked /notify callback with mocked payload.
Limitations
- no support for
serversandsecuritydefinitions inside callback operation - no support for
$urland$request.path.*runtime expressions
File: docs/guides/05-cors.md
CORS
By default, Prism will handle all the preflight requests responding with a 204 and with headers that will allow all the methods and all the origins.
This is done automatically, even when your OpenAPI description doesn't include CORS response headers. A request to OPTIONS /api/todo will receive a 204 as a response even though your description document doesn't specify the OPTIONS verb for that endpoint, and even if your description document doesn't have an /api/todo path at all. However, if your OpenAPI description includes CORS headers, Prism won't override them, and you must ensure they enable requests from a browser on your own.
In case your OpenAPI Document specifies an OPTIONS handler (returning a custom status code or different headers) it will still be called when the subsequent OPTIONS request will be made. This is because Prism is able to differentiate between a preflight request and a regular OPTIONS request.
You can disable the default CORS handler with a command line flag (prism mock document.yml --cors=false). In that case, you are in complete control of the response for all the preflight request, and you can decide which header you want to return.
File: docs/guides/06-errors.md
Errors
All the errors that Prism returns conform to RFC7807 - Problem Details for HTTP APIs, which means you'll always get a JSON object with the following properties:
type(string)title(string)status(number)detail(string)
This document enumerates all the possible errors returned by Prism and provides some further information on how to solve them.
Routing Errors
This class of errors is returned when Prism is trying to identify the right resource to use to respond to the provided HTTP Request.
NO_BASE_URL_ERROR
Message: Attempted to make a request to a server but neither baseUrl param were provided nor servers were defined in the spec
Returned Status Code: 400
Explanation: This error occurs when Prism is being used as a proxy and the current document is missing at least a server in the dedicated array (both globally and locally). The proxy functionality is currently disabled in Prism, so this error should never happen.
NO_RESOURCE_PROVIDED_ERROR
Message: Route not resolved, no resource provided
Returned Status Code: 404
Explanation: This error occurs when the current document doesn't have any endpoint.
Example
openapi: 3.0.1
paths:curl -X POST http://localhost:4010/pets
NO_PATH_MATCHED_ERROR
Message: Route not resolved, no path matched
Returned Status Code: 404
Explanation: This error occurs when the current document doesn't have any endpoint matching the requested URL.
Example
openapi: 3.0.1
paths:
/pets:
get:
responses:
200:curl -X POST http://localhost:4010/hello
NO_SERVER_MATCHED_ERROR
Message: Route not resolved, no server matched
Returned Status Code: 404
Explanation: This error occurs when the server validation is enabled, and the current request hasn't sent the current server or the provided one isn't among the defined in the relative array in the file.
Example
openapi: 3.0.0
paths:
'/pet':
get:
responses:
'200': {}
servers:
- url: '{schema}://{host}/{basePath}'
variables:
schema:
default: http
enum:
- http
- https
host:
default: stoplight.io
enum:
- stoplight.io
- dev.stoplight.io
basePath:
default: apicurl "http://localhost:4010/pet?__server=http%3A%2F%2Finvalidserver.com"
NO_METHOD_MATCHED_ERROR
Message: Route resolved, but no path matched
Returned Status Code: 405
Explanation: This error occurs when the current document has an endpoint with the requested URL, but the specified Verb isn't listed.
Example
openapi: 3.0.1
paths:
/pets:
get:
responses:
200:curl -X POST http://localhost:4010/pets
NO_SERVER_CONFIGURATION_PROVIDED_ERROR
Message: Route not resolved, no server configuration provided
Returned Status Code: 404
Explanation: This error occurs when a base URL has been provided in the current request (enabling the server validation feature) but the current document doesn't have any servers field/entry.
Validation Errors
This class of errors is returned when Prism is validating the request/response against the provided OpenAPI file.
UNPROCESSABLE_ENTITY
Message: Invalid request
Returned Status Code: 422
Explanation: This error occurs when the current request hasn't passed the validation rules specified in the current OpenAPI file and the current resource is missing an error message (422, 400, default). Note that this is an error generated by Prism.
The detail field contains further information on the error (whether it's on the body, the headers or the query string).
NOT_ACCEPTABLE
Message: The server can't produce a representation for your accept header
Returned Status Code: 406
Explanation: This error occurs when the current request has asked the response in a format that the current document isn't able to produce.
Example
openapi: 3.0.2
paths:
/todos:
get:
responses:
200:
examples:
text/plain: hellocurl http://localhost:4010/todos -H "accept: application/json"`NOT_FOUND
Message: The server can't find the requested content
Returned Status Code: 404
Explanation: This error occurs when the current request is asking for a specific status code that the document isn't listing or it's asking for a specific example that doesn't exist in the current document.
VIOLATIONS
Message #1: Request/Response not valid
Returned Status Code: 500
Explanation: This error occurs when you're run Prism with the --errors flag and the request or the response has at least one violation marked as an error.
Message #2: response.body Request body must match exactly one schema in oneOf
Returned Status Code: N/A
Explanation: This error can occur if the current document contains a discriminator. Prism does not support discriminators.
Security Errors
This class of errors is returned when the current request isn't satisfying the security requirements specified in the current resource
UNAUTHORIZED
Message: Invalid security scheme used
Returned Status Code: 401
Explanation: This error occurs when the security scheme for the current resource doesn't match the one that the one that the request being processed has provided.
Negotiation Errors
This class of errors is returned when anything goes wrong between your valid request and returning a suitable response
NO_COMPLEX_OBJECT_TEXT
Message: Can't serialise complex objects as text
Returned Status Code: 500
Explanation: This error occurs when the current request accepts the text/* as the response content type and Prism decided to respond with that, but the schema associated with the selected response of the operation generated a non-primitive payload and Prism can't serialise it.
Example
openapi: '3.0.1'
paths:
/:
get:
responses:
200:
content:
text/plain:
schema:
type: object
properties:
name:
type: string
example: Clark
surname:
type: string
example: Kentcurl -X POST http://localhost:4010/ -A 'Accept: text/plain'
NO_RESPONSE_DEFINED
Message: No response defined for the selected operation
Returned Status Code: 500
Explanation: This error occurs when the current request has matched a corresponding HTTP Operation and has passed all the validations, but there's no response that could be returned.
INVALID_CONTENT_TYPE
Message: Supported content types: list
Returned Status Code: 415
Explanation: This error occurs when the current request specifies a Content-Type that isn't supported by corresponding HTTP Operation. In the case there is no request body or Content-Length is 0, the Content-Type header is ignored.
SCHEMA_TOO_COMPLEX
Message: Unable to generate [body|header] for response. The schema is too complex to generate.
Returned Status Code: 500
Explanation: This error occurs when part of the response can't be generated using JSON Schema Sampler. JSON Schema Sampler has been configured to use a limit of 2500 "ticks". A "tick" is loosely defined as any instance of a JSON Schema schema or subschema. This includes a/an single:
- Property
- Object
- Array item (each in an array between
minItemsandmaxItems, defaulting to 1) - Combiner item (members of
allOf,oneOf,anyOf)
...all recursively, unless a $ref has already been visited (in which case, the subschema is skipped). As a workaround, consider using dynamic response mocking.
Unknown Error
In case you get an UNKNOWN error, it likely means this particular edge case isn't handled. If you encounter one of these, open an issue.
File: docs/guides/07-http-client.md
Prism Client
Prism includes a HTTP Client that you can use to request data to both a real server or a mocked document. The client is modeled after Axios so it may feel familiar.
Create Client from File
Use the getHttpOperationsFromSpec method defined in the @stoplight/prism-cli package to create the required operations array from an OpenAPI spec:
const { getHttpOperationsFromSpec } = require('@stoplight/prism-cli/dist/operations');
const { createClientFromOperations } = require('@stoplight/prism-http/dist/client');
const { URL } = require('url');
const operations = await getHttpOperationsFromSpec('examples/petstore.oas2.yaml');
const client = createClientFromOperations(operations, {
mock: { dynamic: false },
validateRequest: true,
validateResponse: true,
checkSecurity: false,
errors: true,
upstream: new URL('https://api.example.com'),
upstreamProxy: undefined,
isProxy: true,
});The getHttpOperationsFromSpec method also receives the spec as a string:
const descriptionDoc = `
openapi: 3.0.2
paths:
/hello:
get:
responses:
200:
`;
const operations = await getHttpOperationsFromSpec(descriptionDoc);
...Create Client from Manual HTTP Operations
const { createClientFromOperations } = require('@stoplight/prism-http/dist/client');
const { URL } = require('url');
const client = createClientFromOperations(
[
{
method: 'get',
path: '/hello',
id: 'n1',
responses: [{ code: '200' }],
},
],
{
mock: { dynamic: false },
validateRequest: true,
validateResponse: true,
checkSecurity: false,
errors: true,
upstream: new URL('https://api.example.com'),
upstreamProxy: undefined,
isProxy: true,
}
);Example usages
Once you've got a client instance:
Request using the generic method:
client.request('https://google.it', { method: 'get' }).then(console.log);The response object has all the information you need, including the used configuration object.
Override the configuration object on the request level
const config = { validateResponse: false };
client.request('https://google.it', { method: 'get' }, config).then(console.log);This disables response validation only for the current request
You can do the same thing using the shortcut methods
client.get('https://google.it', { mock: { dynamic: false } }).then(console.log);For the shortcut methods (since the only mandatory option is intrinsic in the function name) the option parameter can be omitted
client.get('https://google.it', { validateRequest: false }).then(console.log);You can also use relative links when doing requests. In such case you won't be able to use the proxy and the server validation will be disabled:
client.get('/users/10', { validateRequest: false }).then(console.log);โฆor you can also set the base path in the options object:
client.get('/users/10', { baseUrl: 'https://api.stoplight.io/' }).then(console.log);Set mocking options
client.request('https://google.it', { method: 'get' }, { mock: { dynamic: true } }).then(console.log);
client
.request('https://google.it', { method: 'get' }, { isProxy: true, upstream: new URL('https://api.example.com') })
.then(console.log);File: docs/guides/08-multiple-documents.md
Serving Multiple OpenAPI Documents
A single Prism instance serves one OpenAPI document, but serving multiple documents is possible by running multiple Prism instances on different documents, then serving their content using a reverse Proxy.
You can use any HTTP proxy along with a process management tool to achieve this. The following example explains how to serve multiple OpenAPI documents using Docker Compose.
Preparing configuration files
Depending on your needs, you might have a docker-compose.yaml file like this:
version: '3'
services:
proxy:
image: caddy
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
ports:
- '8080:80'
depends_on:
- prism_1
- prism_2
prism_1:
image: stoplight/prism:4
command: >
mock -p 4010 --host 0.0.0.0
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/yaml/petstore.yaml
prism_2:
image: stoplight/prism:4
command: >
mock -p 4010 --host 0.0.0.0
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yamlAnd the corresponding Caddyfile file:
http://localhost
route /app_1/* {
uri strip_prefix /app_1
reverse_proxy prism_1:4010
}
route /app_2/* {
uri strip_prefix /app_2
reverse_proxy prism_2:4010
}This configuration will allow access to the first Prism instance on localhost:8080/app_1 and the second instance on localhost:8080/app_2 endpoint.
Also, the provided Caddyfile only serves illustrative purposes and hence shouldn't be considered complete nor production-ready.
Running the cluster
First, place the aforementioned files under the same directory - here prism-multi-example.
prism-multi-example
โโโ docker-compose.yaml
โโโ CaddyfileWith the files in place, you can run (from under prism-multi-example/): docker-compose up.
After a second, you should be set up with two Prism instances serving different OAS documents.
Testing the cluster
If you used Caddyfile configuration provided in this document, you should now have two endpoints available:
http://localhost:8080/app_1http://localhost:8080/app_2
You can now try these out by issuing:
curl http://localhost:8080/app_1/pets
curl http://localhost:8080/app_2/petsAt this point, the responses should be given back without issues.
Adding more documents
You can extend the cluster by adding more nodes to docker-compose.yaml.
Under services, you can add:
prism_3:
image: stoplight/prism:4
command: >
mock -p 4010 --host 0.0.0.0
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore.yamlTo make the new node accessible from the proxy, please also adjust Caddyfile:
route /app_3/* {
uri strip_prefix /app_3
reverse_proxy prism_3:4010
}File: docs/guides/09-postman-collection.md
Postman Collections Support
Prism offers a limited support for Postman Collection. The basic workflow of using Prism (both from the CLI and deployed in a Docker container) are fundamentally the same:
prism mock https://raw.githubusercontent.com/postmanlabs/postman-collection/develop/examples/collection-v2.json
info GET http://127.0.0.1:4010/status/200
info POST http://127.0.0.1:4010/post
info PUT http://127.0.0.1:4010/status/201
info GET http://127.0.0.1:4010/post
info GET http://127.0.0.1:4010/status/400/
info GET http://127.0.0.1:4010/path/to/document
start Prism is listening on http://127.0.0.1:4010โฆand then use the trusty curl to try out the server:
curl -s -D "/dev/stderr" http://127.0.0.1:4010/status/200
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Content-type: application/json
authorization: Hawk id="dh37fgj492je", ts="1448549987", nonce="eOJZCd", mac="O2TFlvAlMvKVSKOzc6XkfU6+5285k5p3m5dAjxumo2k="
set-cookie: null
Content-Length: 15
Date: Mon, 09 Mar 2020 19:19:31 GMT
Connection: keep-alive
"response body"%For a complete CLI overview, please see the CLI page
Known limitations
There are some known limitations that it's important to keep in mind:
Authentication
Postman supports a few authentication schemes that OpenAPI doesn't, such as Hawk and AWS. In this case, Prism will do a simplified version of security validation and verify that you've got the right headers populated.
Events
Events are linked to the Postman hosted platform, so Prism will skip this section entirely.
For this reason, if some event handlers have scripts that modify a local variable used in a request/response pair, Prism won't be aware of these changes. Global variables are not supported by Prism.
JSON Schema Generation
OpenAPI 2 and 3 are schema driven, while Postman Collections are examples driven.
Essentially, while in OpenAPI 2/3 you can either define an example request/response body OR define a JSON Schema to describe how the payload will look like, in a Postman Collections you can only define examples.
Prism will try to infer a JSON Schema from an example, and use such one to perform request/response validation as well as examples generation in case the it's running in dynamic mode.
Infer a JSON Schema from a payload is an operation usually complicated and there's no way a perfect result will be achieved. Keep in mind you might get legitimate validation errors.
To give an example, this JSON object:
{
"name": "Bugatti Veyron",
"type": "Sport Car",
"speed": 3000
}will likely generate this schema:
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string"
},
"speed": {
"type": "number"
}
}
}Although the result seems good:
- There is no way to understand whether all or some properties are required or not, so they'll all be marked as optional.
- There is no way to understand whether a type is indeed an
enuminstead of a regularstring. In this specific example, maybe the author's intention is that type is eitherSport CarorSUV - There is no way to understand whether a type can be something stricter; for example, maybe the author's intention was to mark the
speedproperty asintegerinstead ofnumber.
Operations Merging
Postman Collections allows to define the same response multiple times, as long they differ for the returned response type, payload, examples. Prism will try to merge all these definitions in a single operation and then selecting the appropriate example based on its internal negotiator.