Automatic content negotiation. No magic. No bleeding into your code.
// Define a controller endpointclassUserControllerextendsController{publicfunction__construct(privateIUserService$users){}#[Post('/users')]publicfunctioncreateUser(User$user):IResponse{$this->users->create($user);return$this->created("/users/{$user->id}",$user);}#[Get('/users/:id')]#[AuthorizeRoles('admin')]publicfunctiongetUserById(int$id):User{return$this->users->getById($id);}}// Bind your dependency$container->bindInstance(IUserService::class,newUserService());// Run an integration test$postResponse=$this->post('/users',newUser('Dave'));$user=$this->readResponseBodyAs(User::class,$postResponse);$admin=newPrincipalBuilder('example.com')->withRoles('admin')->build();$getResponse=$this->actingAs($admin,fn()=>$this->get("/users/$user->id"));$this->assertParsedBodyEquals($user,$getResponse);
Install Aphiria
composer create-project aphiria/app --prefer-dist --stability dev