Migrate from Prism
This guide moves a repository that mocks its API with prism mock and checks it with
prism proxy to apigenie-server: the addresses, the Prefer header, request validation, the
validation proxy, the CI step, and what has no counterpart. It starts from Prism 5.x and an
OpenAPI file, openapi.yaml.
You need the CLI installed; the Quickstart shows how. Keep Prism installed until the last step, so you can send the same requests to both.
What changes and what stays
| Prism | API Genie | |
|---|---|---|
| Mock | prism mock openapi.yaml |
apigenie-server openapi.yaml |
| Validation proxy | prism proxy openapi.yaml http://localhost:8080 |
apigenie-server openapi.yaml --proxy-to http://localhost:8080 |
| Address | http://127.0.0.1:4010, CORS on |
the same; --host, --port, --cors off |
| Documents | OpenAPI 2.0 and 3.x, Postman collections | OpenAPI 3.0 to 3.2, Swagger 2.0, AsyncAPI 3, .proto, GraphQL |
| Picking an answer | Prefer: code=404, example=cat, dynamic=true; __code, __example, __dynamic |
the same, plus delay=, drop= and scenario= |
| Static and dynamic | examples by default, -d generates |
the same; --dynamic or -d, --seed N in both |
| An invalid request | 422 with problem details | the same, with 400, 401, 415 for what they name |
| An invalid answer of the mock | logged; a 500 with --errors |
logged and counted in X-Apigenie-Mock-Violations; a 500 with --strict |
| Violations of the proxy | sl-violations header; errors with --errors |
X-Apigenie-Mock-Violations headers; errors with --strict; a report, and exit status 5 |
| Reload on change | always | --watch |
| Configuration | the command line | the command line, or apigenie-server.yaml (Configuration) |
| Docker | stoplight/prism:5 |
mykulyak/apigenie-server |
| npm | @stoplight/prism-cli |
@mykulyak/api-genie |
Run both on the same document
prism mock openapi.yaml
apigenie-server openapi.yaml
Listening on http://127.0.0.1:4010/v1 (spec: openapi.yaml, 12 operations)
Admin API: http://127.0.0.1:4010/__apigenie
Dashboard: http://127.0.0.1:4010/__apigenie/ui
Both listen on 127.0.0.1:4010 with CORS headers on, so a client keeps its base URL. Prism
ignores the document’s servers and serves /pets; apigenie-server serves the paths under the
path of the first server, /v1/pets, and as they are, /pets, so both addresses answer. The
dashboard shows every request, what answered it and what was wrong with it, which Prism prints to
the terminal; --log-level debug and --log-bodies print it too.
curl http://127.0.0.1:4010/pets
Both answer with the first example of the lowest 2xx response. Where a response has no example,
Prism’s static mode fills the schema with "string" and 0; apigenie-server generates a value
that fits the schema, its formats, patterns, ranges and enums, in static mode too
(Responses). Prism’s --ignoreExamples has --dynamic as
its closest counterpart.
Pick the answer of a request
The Prefer header and the __ query parameters keep their names:
curl http://127.0.0.1:4010/pets -H 'Prefer: code=404'
curl http://127.0.0.1:4010/pets -H 'Prefer: example=empty'
curl 'http://127.0.0.1:4010/pets?__dynamic=true'
apigenie-server adds delay=1500 (answer after 1.5 seconds), drop=reset (reset the
connection; close, timeout and truncate too) and scenario=outage
(choosing a response per request).
For an answer that should hold for a while, such as an outage of one backend, a
scenario in the document or in the configuration is switched
on with --scenario or in the dashboard, instead of a Prefer header on every request.
Prism’s __server query parameter has no counterpart: the mock does not check which server a
request is meant for.
Request validation and security
Both answer a request that does not match its operation with 422 and problem details. Prism
answers with the operation’s own 422 or 400 response when it declares one; apigenie-server
answers with the problems it found: 422 for a parameter or a body that does not match its schema,
400 for a body it cannot parse, 415 for a media type the operation does not declare
(Validation and security).
Both answer 401 when a request carries no credentials for the operation’s security requirements.
Prism stops there; apigenie-server can check the credentials themselves:
# apigenie-server.yaml
version: "1.0"
security:
mode: enforce
credentials: {api_keys: {apiKey: [secret]}, bearer_tokens: [token]}
Prism’s --errors on the mock, which turns an invalid answer of the mock into a 500, is
--strict. Without it, the problems of an answer are logged and counted in the
X-Apigenie-Mock-Violations header of that answer.
Dynamic data and x-faker
-d and --seed keep their names. x-faker on a property carries over, with one change: the
providers are named like those of today’s faker.js, person.firstName and internet.email, not
name.firstName of the Faker 6 that Prism uses; the Faker page
lists them with their arguments:
Pet:
type: object
properties:
name: {type: string, x-faker: person.firstName}
owner: {type: string, x-faker: internet.email}
A property can get its provider from the configuration instead, without touching the document
(User.email: {faker: internet.email} under generation), and string properties called like
email, first_name or city get fitting values without any of this. Prism’s
--json-schema-faker-fillProperties, which adds properties the schema does not declare, has no
counterpart.
The validation proxy
prism proxy openapi.yaml http://localhost:8080
apigenie-server openapi.yaml --proxy-to http://localhost:8080
Every request goes to the real server, and the request and the server’s answer are checked
against the document. The violations of an exchange come back in headers, sl-violations in
Prism, X-Apigenie-Mock-Violations and X-Apigenie-Mock-Violations-Detail here, and in the
dashboard’s Contract screen with the coverage of the document
(Contract testing).
--errorsis--strict: a request that does not match the document is answered with 422 without reaching the server, and a server answer that does not match is replaced by a 502.--validate-request falseisvalidation: {request: off}in the configuration.- Prism mocks an operation the server answers with 501.
--proxy-mode fallbackdoes the same, and also when the server answers 404, does not answer in time or cannot be reached. - Both add
Deprecation: trueto the answers of a deprecated operation. --upstream-proxyhas no counterpart: the server reaches the upstream directly.
The report in CI
With Prism, CI learns about a contract violation from a test that fails behind --errors.
apigenie-server writes a report when it stops, and exits with status 5 when the contract failed:
apigenie-server openapi.yaml --proxy-to http://localhost:8080 \
--report contract.json --report-junit contract.xml --fail-on errors --min-coverage 80 &
API_URL=http://localhost:4010 npm test
curl -X POST http://localhost:4010/__apigenie/shutdown
wait $!
--fail-on errors fails the job on an error-level violation even when every test passed, and
--min-coverage 80 when the tests leave more than a fifth of the document untested. The JUnit
report has one test case per operation, so the CI system shows it next to the test results.
Mock and contract-test an API has the whole flow,
with --record and --replay for tests that run without the real services.
Several APIs
Prism runs one document per process, on a port each:
prism mock -p 5000 pets.yaml
prism mock -p 5001 orders.yaml
One apigenie-server serves them as services, each at its own
mount, with a proxy or a scenario of its own:
apigenie-server pets.yaml orders.yaml
Listening on http://127.0.0.1:4010 (2 services)
pets http://127.0.0.1:4010/pets/v1 (spec: pets.yaml, 12 operations)
orders http://127.0.0.1:4010/orders (spec: orders.yaml, 5 operations)
What has no counterpart
- Callbacks. Prism sends the callback requests an operation declares;
apigenie-serverdoes not mock callbacks, webhooks or links. - Postman collections as the document. The mock serves OpenAPI, Swagger 2.0, AsyncAPI,
Protobuf and GraphQL documents.
apigenie test importturns a Postman collection into.httpfiles for apigenie test. -m, the second process for the log. The server is one native process.__server,--upstream-proxyand--json-schema-faker-fillProperties, as noted above.
Remove Prism
When the same requests get the answers you expect from both: replace prism mock and
prism proxy in the scripts, the Compose file and the CI pipeline, remove @stoplight/prism-cli
from the development dependencies, and swap the Docker image:
docker run --rm -p 4010:4010 -v "$PWD:/mnt/data" mykulyak/apigenie-server openapi.yaml
The image listens on every interface of the container, as prism mock -h 0.0.0.0 did.