k-kinzal/oas-fake-php

Intercept HTTP requests, validate against OpenAPI schemas, and generate fake responses for testing

Maintainers

Package info

github.com/k-kinzal/oas-fake-php

pkg:composer/k-kinzal/oas-fake-php

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-03-20 14:08 UTC

README

CI License: MIT PHP Version

OpenAPI schema-driven fake API server for PHP testing. Define your API contract once, and automatically get a working fake server that generates valid responses, validates requests, and catches schema violations in your tests.

Features

  • Automatic fake response generation from OpenAPI schema definitions
  • Request/response validation against the OpenAPI schema
  • Custom response stubs and callbacks per operation
  • Declarative server classes with handler methods mapped by operationId
  • Three operating modes: FAKE, RECORD, REPLAY
  • PSR-15 middleware support

Public API Surface

The primary user-facing entry points are OasFake, Server, Schema, FakeDataContext, FakeRequest, FakeResponse, Handler, Route, Mode, the documented exception types, and Validator for standalone validation. Pipeline and support classes such as Interceptor, ServerRegistry, Converter, OperationLookup, HandlerMap, and ParameterFaker are available under the same namespace for advanced use.

Requirements

  • PHP 8.0 - 8.5
  • ext-curl

Installation

composer require --dev k-kinzal/oas-fake-php

Usage

Basic

Define a server pointing to your OpenAPI schema and start intercepting:

use OasFake\OasFake;
use OasFake\Server;

final class PetStoreServer extends Server
{
    protected static string $SCHEMA = __DIR__ . '/openapi.yaml';
}

// Start intercepting HTTP requests
$server = OasFake::start(PetStoreServer::class);

// All HTTP requests now return responses generated from the schema
$client = new GuzzleHttp\Client(['base_uri' => 'https://petstore.example.com']);
$response = $client->get('/pets/1');

// Stop intercepting
OasFake::stop();

OasFake::stop() stops every running fake server. To stop only one server while leaving other registered servers active, pass the server instance: OasFake::stop($server) or $server->stop().

Custom Responses

Override responses for specific operations using the configure callback:

use OasFake\OasFake;
use OasFake\Handler;

$server = OasFake::start(PetStoreServer::class, fn ($s) => $s
    ->withResponse('listPets', 200, [['id' => 1, 'name' => 'Buddy']])
    ->withCallback('createPet', function ($request, $response) {
        $body = json_decode((string) $request->getBody(), true);
        return new \GuzzleHttp\Psr7\Response(201, [], json_encode([
            'id' => 42,
            'name' => $body['name'],
        ]));
    })
    ->withHandler('deletePet', Handler::status(204))
);

Declarative Server

Public handler methods on a Server subclass are automatically registered, matched by operationId:

use OasFake\Server;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class PetStoreServer extends Server
{
    protected static string $SCHEMA = __DIR__ . '/openapi.yaml';

    public function listPets(ServerRequestInterface $request, ?ResponseInterface $response): ResponseInterface
    {
        return new Response(200, ['Content-Type' => 'application/json'], json_encode([
            ['id' => 1, 'name' => 'Buddy'],
        ]));
    }

    #[\OasFake\Route(method: 'DELETE', path: '/pets/{petId}')]
    public function removePet(ServerRequestInterface $request, ?ResponseInterface $response): ResponseInterface
    {
        return new Response(204);
    }
}

Declarative handler methods should accept ServerRequestInterface as their first parameter and return a ResponseInterface. Public helper methods without that handler signature are ignored.

Configuration

use OasFake\OasFake;
use OasFake\Mode;

$server = OasFake::start(PetStoreServer::class, fn ($s) => $s
    ->withMode(Mode::RECORD)  // or ->withMode('record')
    ->withCassettePath('./fixtures/cassettes')
    ->withCassetteName('petstore')
    ->withRequestValidation(false)
    ->withResponseValidation(false)
    ->withFakerOptions(['alwaysFakeOptionals' => true, 'minItems' => 2, 'maxItems' => 5])
    ->withMiddleware(new MyMiddleware())
);

Mode::RECORD records OasFake's generated or custom responses to cassettes for deterministic replay. It does not proxy requests to a real upstream API.

All settings can also be overridden via environment variables:

OAS_FAKE_MODE=record OAS_FAKE_VALIDATE_REQUESTS=false composer test

License

MIT