A fluent PHP library for generating fake API response data. Perfect for testing and creating mock API responses.
Inspired by Laravel's Eloquent Factories.
composer require --dev cbaconnier/php-api-factoryCreate a factory by extending ApiFactory and defining your data structure:
use Cbaconnier\PhpApiFactory\ApiFactory;
class UserApiFactory extends ApiFactory
{
// optional
protected ?string $wrapper = 'users';
protected function definition(): array
{
return [
'id' => $this->faker->unique()->randomNumber(8),
'name' => $this->faker->name(),
'email' => $this->faker->unique()->email(),
'role' => $this->faker->randomElement(['admin', 'member', 'viewer']),
'created_at' => $this->faker->dateTime()->format('Y-m-d H:i:s'),
];
}
}Generate data:
// Single item
$user = UserApiFactory::new()->make();
// ['id' => 12345678, 'name' => 'John Doe', ...]
// Multiple items
$users = UserApiFactory::new()->count(5)->make();
// [['id' => 1, ...], ['id' => 2, ...], ...]
// Wrapped response
$response = UserApiFactory::new()->count(5)->wrap()->make();
// ['users' => [['id' => 1, ...], ['id' => 2, ...]]]$user = UserApiFactory::new()->make(['name' => 'Jane Doe', 'role' => 'admin']);Define reusable modifications:
class UserApiFactory extends ApiFactory
{
public function admin(): static
{
return $this->state(['role' => 'admin']);
}
public function suspended(): static
{
return $this->state([
'status' => 'suspended',
'suspended_at' => $this->faker->dateTime()->format('Y-m-d H:i:s'),
]);
}
}
$admin = UserApiFactory::new()->admin()->make();
$suspendedAdmin = UserApiFactory::new()->admin()->suspended()->make();Generate unique values for each item:
$users = UserApiFactory::new()
->count(3)
->sequence(fn($index) => ['name' => "User {$index}"])
->make();
// [['name' => 'User 0', ...], ['name' => 'User 1', ...], ...]
// Cycle through values
$users = UserApiFactory::new()
->count(4)
->sequence([
['role' => 'admin'],
['role' => 'member'],
['role' => 'viewer'],
])
->make();
// Roles: admin, member, viewer, admin// Only specific fields
$user = UserApiFactory::new()->only(['id', 'name'])->make();
// Exclude specific fields
$user = UserApiFactory::new()->except(['email', 'created_at'])->make();Reuse data from existing collections:
$projects = [['id' => 1], ['id' => 2]];
$tasks = TaskFactory::new()
->count(10)
->recycle($projects, 'project_id')
->make();
// Each task gets a random project_id (1 or 2)
// With custom source key
$users = [['user_id' => 100], ['user_id' => 200]];
TaskFactory::new()
->recycle($users, 'assigned_to', 'user_id')
->make();
// With callable for complex relationships
TaskFactory::new()
->recycle($projects, fn($project) => [
'project' => [
'id' => $project['id'],
'name' => $project['name']
]
])
->make();Create complex nested structures:
$project = ProjectFactory::new()
->has('owner', UserApiFactory::new())
->has('tasks', TaskFactory::new()->count(5))
->make();
// {
// 'id': 1,
// 'name': 'Project Alpha',
// 'owner': {'id': 1, 'name': 'John Doe', ...},
// 'tasks': [{'id': 1, ...}, {'id': 2, ...}, ...]
// }
// Deep nesting
ProjectFactory::new()
->has('tasks',
TaskFactory::new()
->count(3)
->has('assignee', UserApiFactory::new())
)
->make();Add pagination or other metadata:
ApiFactory::register('default', [
'metadata' => fn($items) => [
'pagination' => [
'total' => count($items),
'per_page' => 15,
'current_page' => 1,
],
'meta' => [
'version' => '1.0',
],
],
]);
ApiFactory::default('default');
$response = UserApiFactory::new()
->count(25)
->wrap()
->withMetadata()
->make();
// {
// 'users': [...],
// 'pagination': {...},
// 'meta': {...},
// }Configure global settings:
use Cbaconnier\PhpApiFactory\ApiFactory;
ApiFactory::register('default', [
'faker' => [
'locale' => 'fr_FR',
'providers' => [CustomProvider::class],
],
'wrapper' => 'data',
'metadata' => [
'meta' => ['version' => '1.0'],
],
]);
ApiFactory::default('default');All features work together:
$response = UserApiFactory::new()
->count(10)
->sequence(fn($i) => ['name' => "User {$i}"])
->admin()
->only(['id', 'name', 'role'])
->wrap()
->make();composer install
composer testMIT