Installation:
composer require antwebes/guzzle-fake-server:dev-master
(Note: Use dev-master until a stable release is available.)
Basic Configuration: Create a Guzzle client with the fake server plugin:
use Ant\Bundle\GuzzleFakeServer\Guzzle\Plugin\FakeServer\FakeServer;
use Ant\Bundle\GuzzleFakeServer\Guzzle\Plugin\FakeServer\FileResourceLoader;
use Ant\Bundle\GuzzleFakeServer\Guzzle\Plugin\FakeServer\ArrayConfiguration;
use Guzzle\Client;
$client = new Client();
$fakeServer = new FakeServer(
new ArrayConfiguration("http://test-api.com/"),
new FileResourceLoader(__DIR__ . '/fixtures'),
200,
'""',
['Content-Type' => 'application/json']
);
$client->addSubscriber($fakeServer);
First Use Case: Define a mock response for a GET request:
$fakeServer->getConfiguration()->addGetResource(
'/users/1',
'user_1.json',
200
);
$response = $client->get('http://test-api.com/users/1');
// Returns content from `user_1.json` with status 200.
Define Fixtures:
Store JSON/XML files in a structured directory (e.g., tests/fixtures/api/).
Example: tests/fixtures/api/users/user_1.json:
{"id": 1, "name": "John Doe"}
Configure Mappings:
Use ArrayConfiguration for in-memory mappings or extend ResourceLoaderInterface for custom logic (e.g., database-backed responses).
$config = $fakeServer->getConfiguration();
$config->addPostResource(
'/api/login',
'auth/success.json',
200,
["email" => "user@example.com", "password" => "secret"]
);
Conditional Responses: Simulate different responses based on request data:
$config->addPostResource(
'/api/orders',
'orders/pending.json',
201,
["status" => "pending"]
);
$config->addPostResource(
'/api/orders',
'orders/completed.json',
201,
["status" => "completed"]
);
Integration with Laravel:
Bind the client to the container in AppServiceProvider:
public function register()
{
$this->app->singleton(GuzzleClient::class, function ($app) {
$client = new Client();
$client->addSubscriber(new FakeServer(
new ArrayConfiguration("http://api.example.com"),
new FileResourceLoader(__DIR__ . '/../tests/fixtures'),
200,
'""',
['Content-Type' => 'application/json']
));
return $client;
});
}
Testing: Use in unit tests to avoid external API calls:
public function testUserLogin()
{
$response = $this->app->make(GuzzleClient::class)->post('/api/login', [
'email' => 'user@example.com',
'password' => 'secret'
]);
$this->assertEquals(200, $response->getStatusCode());
$this->assertJson($response->getBody());
}
URL Matching:
ConfigurationInterface implementations if needed./users/{id} won’t work; use /users/1 explicitly.Case Sensitivity:
GET, POST) are case-sensitive in the configuration methods (e.g., addGetResource vs addgetResource).Resource Loading:
FileResourceLoader throws exceptions if files are missing. Validate paths early in tests:
if (!file_exists(__DIR__ . '/fixtures/user.json')) {
throw new \RuntimeException('Fixture file missing!');
}
Guzzle Version:
~3.7 in composer.json to avoid conflicts.Event Subscription:
Verify Mappings: Dump the configuration to debug:
var_dump($fakeServer->getConfiguration()->getResources());
Check Request Data: Log request payloads to ensure conditions match:
$fakeServer->setOnRequestCallback(function ($request) {
\Log::debug('Request:', $request->getBody());
});
Status Codes:
Default status is 200. Override per route:
$config->addGetResource('/error', 'error.json', 404);
Dynamic Fixtures:
Generate fixtures dynamically using ResourceLoaderInterface:
class DatabaseResourceLoader implements ResourceLoaderInterface
{
public function load($resource)
{
return json_encode(['data' => DB::table($resource)->get()]);
}
}
Headers and Body:
Set default headers/body in the FakeServer constructor:
$fakeServer = new FakeServer(
$config,
$loader,
200,
'{"default": "response"}', // Default body
['X-Custom-Header' => 'value'] // Default headers
);
Laravel Facades:
Access the client via Http::client() in tests:
$response = Http::client()->get('/api/users');
Performance: For large test suites, cache loaded resources to avoid disk I/O:
class CachingResourceLoader implements ResourceLoaderInterface
{
private $cache = [];
public function load($resource)
{
if (!isset($this->cache[$resource])) {
$this->cache[$resource] = file_get_contents($resource);
}
return $this->cache[$resource];
}
}
Extending Functionality:
ConfigurationInterface to support regex or partial matches.FakeServer to alter responses (e.g., add delays):
class DelayedFakeServer extends FakeServer
{
public function __construct(...$args)
{
parent::__construct(...$args);
$this->setOnResponseCallback(function ($response) {
sleep(1); // Simulate network delay
return $response;
});
}
}
How can I help you explore Laravel packages today?