Testing · APIs
Test against a mock API, not a placeholder
Develop and test against Prism, WireMock, MSW or json-server instead of an address that belongs to someone else.
Guide · APIs
Requests to addresses such as api.example-petstore.com come from code that still uses an example address as its base URL. This guide shows where that address usually lives, how to move it to configuration, and how to prevent it from happening again.
Base URL copied from an example
API_BASE_URL=https://api.example-petstore.comGET /v2/pet/42 Authorization: Bearer ••••api.example-petstore.com410 Gone The key reached a stranger: revoke itBase URL from configuration
API_BASE_URL=${API_BASE_URL}GET /v2/pet/42 Authorization: Bearer ••••200 OK The request and key reach the right serviceEvery request with a body, to an API-style path such as /v2/pet, or that asks for JSON, receives
410 Gone with a problem description (RFC 9457):
HTTP/1.1 410 Gone
Content-Type: application/problem+json; charset=utf-8
{"type":"https://example-petstore.com/#where","title":"Example domain, not a real service",
"status":410,"detail":"api.example-petstore.com is an example domain used in documentation. …"}
This domain is not the Swagger Petstore sample API, which lives at petstore.swagger.io.
BASE_URL = "https://api.example-petstore.com");.env file or environment variable copied from an example;host or servers field of an OpenAPI description used to generate a client;{{baseUrl}};Read the address from configuration and fail loudly when it is missing:
# Python: read the address from configuration, not from the code
import os
BASE_URL = os.environ["API_BASE_URL"]
// JavaScript / Node.js
const baseURL = process.env.API_BASE_URL;
// PHP 8
$baseUrl = getenv('API_BASE_URL') ?: throw new RuntimeException('API_BASE_URL is not set');
# Python, httpx
client = httpx.Client(base_url=os.environ["API_BASE_URL"])
// Node.js, axios
const api = axios.create({ baseURL: process.env.API_BASE_URL });
# Generated OpenAPI client (Python)
configuration = Configuration(host=os.environ["API_BASE_URL"])
// PHP, Guzzle
$client = new GuzzleHttp\Client(['base_uri' => getenv('API_BASE_URL')]);
// PHP, Symfony HttpClient
$client = Symfony\Component\HttpClient\HttpClient::createForBaseUri(getenv('API_BASE_URL'));
In Postman or Insomnia, set baseUrl per environment and select the right environment before sending.
Add a start-up or test check that rejects example addresses:
# Python
import os, re
base = os.environ["API_BASE_URL"]
if re.search(r"example-(petstore|commerce-host)\.com", base):
raise RuntimeError(f"API_BASE_URL still points at an example domain: {base}")
// PHP
$base = getenv('API_BASE_URL') ?: '';
if (preg_match('/example-(petstore|commerce-host)\.com/', $base)) {
throw new RuntimeException("API_BASE_URL still points at an example domain: $base");
}
In your own documentation and examples, use names reserved for that purpose, such as api.example.com.
See example domains.
If requests carried an API key, token, password or session cookie, they reached the wrong server. Revoke them at the service that issued them and issue new ones. Leaked credentials: what to do now.
Testing without the real service: Test against a mock API, not a placeholder