Introduction

What Is It?

Aphiria is a suite of decoupled libraries that help you write expressive REST APIs without bleeding into your code base. Let's look at an example controller.

final class UserController extends Controller
{
    public function __construct(private IUserService $users) {}

    #[Post('/users')]
    public function createUser(Credentials $creds): IResponse
    {
        $user = $this->users->create($creds->email, $creds->password);

        return $this->created("/users/{$user->id}", $user);
    }

    #[Get('/users/:id')]
    public function getUserById(int $id): User
    {
        return $this->users->getById($id);
    }
}

In createUser(), Aphiria uses content negotiation to deserialize the request body to a Credentials object. Likewise, Aphiria determines how to serialize the User from getUserById() to whatever format the client wants (eg JSON or XML). This is all done with zero configuration of your plain-old PHP objects (POPOs).

Let's configure our DI container to inject an instance of IUserService into our controller via a binder.

final class UserServiceBinder extends Binder
{
    public function bind(IContainer $container): void
    {
        $container->bindInstance(IUserService::class, new UserService());
    }
}

Next, let's use a module to register the binder. We'll also configure our app to map an exception that IUserService might throw to an HTTP response. Modules give you a place to configure each piece of your business domain, allowing you to easily plug-and-play code into your app.

final class UserModule extends AphiriaModule
{
    public function configure(IApplicationBuilder $appBuilder): void
    {
        $this->withBinders($appBuilder, new UserServiceBinder())
            ->withProblemDetails(
                $appBuilder,
                UserNotFoundException::class,
                status: HttpStatusCode::NotFound
            );
    }
}

Finally, let's register the module with our app, which is itself a module.

final class GlobalModule extends AphiriaModule
{
    public function configure(IApplicationBuilder $appBuilder): void
    {
        $this->withModules($appBuilder, new UserModule());
    }
}

That's all it takes to build a fully functional API with Aphiria.

Getting Started

To get up and running, follow our installation guide to create a skeleton app that uses Aphiria. Then, learn how to define some routes, create some controllers, and configure your dependencies. From there, you can browse the docs in any order you choose, although the order they're listed in might be the best way to read them.

Aphiria uses a GitHub project for keeping track of new features, bug fixes, and roadmapping. To learn more about the direction of the framework, check out the project.

Another PHP Framework?

Great question. The idea for Aphiria was conceived after using ASP.NET Core. Its expressive syntax, intuitive models, and simple configuration inspired us to see if we could find these things in a PHP framework. We looked at frameworks, and usually found at least one major problem with them all:

There is a general trend towards having separate API and front end codebases. Full stack frameworks have their place, but we felt like this was becoming a less and less common way to write websites - most are JavaScript-powered UIs calling APIs. So, we focused on what we know best - building REST APIs. We spent months sketching out the ideal syntax, laboring over how to provide the best developer experience possible. Once we had the syntax down, we worked backwards and started implementing it over the course of a few years. It wasn't easy, but we can honestly say we are very proud of it. We hope you enjoy it, too.