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).

  • --errors is --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 false is validation: {request: off} in the configuration.
  • Prism mocks an operation the server answers with 501. --proxy-mode fallback does the same, and also when the server answers 404, does not answer in time or cannot be reached.
  • Both add Deprecation: true to the answers of a deprecated operation.
  • --upstream-proxy has 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-server does 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 import turns a Postman collection into .http files for apigenie test.
  • -m, the second process for the log. The server is one native process.
  • __server, --upstream-proxy and --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.

Was this helpful?