A simple, extensible REST API framework for PHP

Overview

Coverage Status

Note: This framework is not stable yet.

Introduction

Aphiria is a suite of small, decoupled PHP libraries that make up a REST API framework. It simplifies content negotiation without bleeding into your code, allowing you to write expressive code. Aphiria also provides the following functionality out of the box:

// Define a controller endpoint
class UserController extends Controller
{
    public function __construct(private IUserService $users) {}

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

// Bind your dependency
$container->bindInstance(IUserService::class, new UserService());

// Run an integration test
$this->assertParsedBodyEquals(new User(1, 'Dave'), $this->get('/users/1'));

Installation

Create an Aphiria app via Composer:

composer create-project aphiria/app --prefer-dist --stability dev

Refer to the documentation for more details.

Documentation

Full documentation is available at the Aphiria website.

Requirements

  • PHP 8.0

Contributing

We appreciate any and all contributions to Aphiria. Please read the documentation to learn how to contribute.

Community

If you have general questions or comments about Aphiria, join our GitHub Discussions.

Directory Structure

Aphiria is organized as a monorepo. Each library is contained in src/{library}, and contains src and tests directories.

License

This software is licensed under the MIT license. Please read the LICENSE for more information.

Author

Aphiria was created and primarily written by David Young.

Comments
  • Support for using higher ports for built-in webserver

    Support for using higher ports for built-in webserver

    Problem

    On OSX using port 80 is not available for users by default:

    > php aphiria app:serve
    Running at http://localhost:80
    [Mon Feb  1 08:55:10 2021] Failed to listen on localhost:80 (reason: Permission denied)
    

    Of course there are workarounds, but it's probably best to just avoid using port 80 as default, at least this is what most tools would do.

    Now it seems like providing a port is supported:

    > php aphiria app:serve --port 10080
    Running at http://localhost:10080
    [Mon Feb  1 08:57:01 2021] PHP 8.0.1 Development Server (http://localhost:10080) started
    

    Unfortunately however, this will cause some issues when the endpoint is hit:

    > curl http://localhost:10080/
    {"type":"https:\/\/tools.ietf.org\/html\/rfc7231#section-6.5.4","title":"No route found for http:\/\/localhost:10080\/","detail":null,"status":404,"instance":null}
    

    Expectation

    At least one, but perhaps all of the following:

    1. Use a higher port by default.
    2. When a higher port is used, the localhost router should still work properly.
    3. Documentation should make it obvious what to change when a different port is being used.
    opened by peteraba 3
  • Can we move bootstrappers included in skeleton app to modules?

    Can we move bootstrappers included in skeleton app to modules?

    Goal

    • Remove framework-specific bootstrappers from userland so that their apps' don't have too much framework-specific code/bootstrappers mixed in with app-specific code/bootstrappers
      • This makes it more similar to ASP.NET Core - you don't need to explicitly bootstrap it, but you do have entry points to customize the bootstrapping of the framework
    • Move app bootstrappers to Aphiria's source control

    Difficulties

    • How do we make it simple to configure things that are currently in those bootstrappers, eg paths to cache files, supported languages, etc?
    enhancement 
    opened by davidbyoung 3
  • Can not readLine from console input

    Can not readLine from console input

    Hi, I got this issue on Windows image

    I can not read any input from the console. I tried to use different consoles (git bash, cmd, power shell)

    It fails on the \Aphiria\Console\Output\StreamOutput::readLine

    feof return false here. The $input is present and have correct value inserted in the console

    public function readLine(): string
    {
        $input = \fgets($this->inputStream, 4096);
    
        if (!\feof($this->inputStream)) {
            throw new RuntimeException('Failed to read line');
        }
    
        return $input;
    }
    

    I've checked similar functionality on symfony console \Symfony\Component\Console\Helper\QuestionHelper::readInput They just return fgets result. Is there a reason to check for EOL while reading one line?

    if (!$question->isMultiline()) {
        return fgets($inputStream, 4096);
    }
    
    bug 
    opened by leprz 2
  • Default to using problem details for all 4xx and 5xx errors

    Default to using problem details for all 4xx and 5xx errors

    Problem details are currently returned for 400s created by IRequestBodyValidator. However, all our errors should be consistent and use problem details.

    enhancement 
    opened by davidbyoung 2
  • Support being able to override other middleware

    Support being able to override other middleware

    If we were to support a middleware for authenticating/authorizing a user, and wanted to protect our entire API with it except for a few select routes, the only way to do that would be to remember to add the auth middleware to each controller or route, which is cumbersome. A better DX might be to include the ability to remove previously-registered middleware via a new property in Aphiria\Routing\Middleware\MiddlewareBinding, eg:

    // In GlobalModule.php...
    $this->withGlobalMiddleware($appBuilder, new MiddlewareBinding(Authenticate::class));
    
    // Our controller with a route that overrides the Authenticate middleware...
    class LoginController extends Controller
    {
        #[Middleware(AllowGuests::class, override: [Authenticate::class])]
        public function logIn(Login $login): IResponse
        {
             // ...
        }
    }
    

    Then, the Aphiria\Api\Router middleware could filter out middleware that were overridden in other middleware.

    Things to figure out

    • Is there a security issue with allowing other middleware to remove select middleware?
    • Is the DX here really worth it?
    • Is there another way of accomplishing this?
    enhancement 
    opened by davidbyoung 1
  • Incorporate templates into content negotiation

    Incorporate templates into content negotiation

    In content negotiation, we are frequently incorporating a $type parameter, which we could use to help us know the return type of the method using @template annotations.

    enhancement wontfix 
    opened by davidbyoung 1
  • Support generics in collections

    Support generics in collections

    Pslam and PHPStorm both support generics using the @template PHPDoc. To provide a better type DX, we should support generics via this PHPDoc, and update any internal usages of the collections to be stronger typed.

    enhancement 
    opened by davidbyoung 1
  • Added support for C#-style extension methods

    Added support for C#-style extension methods

    Extension Methods

    Extension methods provide syntactic sugar for two things:

    1. Helper methods you frequently call on a class/interface
    2. Extending functionality on classes/interfaces you do not "own"

    Aphiria's extension method library helps you with the #⁠1. For example, you may have an IList interface that you frequently find yourself retrieving the first-or-default item from. Rather than have to extend the IList interface to add this helper method, you can use an extension method to add it to the interface.

    Note: Aphiria's implementation allows you to register extension methods on interfaces and/or parent classes, and "inherit" them in child classes.

    The Gotcha

    Unlike C#, PHP does not provide native functionality to dynamically add methods to a class without extending it. The closest thing we have is the magic method __call(), which lets you specify what to do when an unknown method is called on an object. Aphiria's extension method library has one huge catch - you must have control over the classes you're extending. That does negate some of the advantages to real extension methods for sure, but they can still be useful when you're looking to extend classes' functionality from within your own projects without polluting the interfaces with these helper methods.

    Basics

    Let's expand upon the first-or-default example from above. You could do this statically via

    class ListExtensions
    {
        public static function getFirstOrDefault(IList $list, mixed $default): mixed
        {
            return $list->count() === 0 ? $default : $list->get(0);
        }
    }
    

    and use it via

    $list = new ArrayList();
    // Add stuff to the list...
    $firstItem = ListExtensions::getFirstOrDefault($list, null);
    

    There's nothing inherently wrong with this code, but it would be nice if we could call it like:

    $list = new ArrayList();
    // Add stuff to the list...
    $firstItem = $list->getFirstOrDefault(null);
    

    To do this with Aphiria, you must:

    1. Implement Aphiria\ExtensionMethods\IExtendable in your class or interface (IList in this example)
    2. Use the Aphiria\ExtensionMethods\ExtensionMethods trait in your concrete class (ArrayList in this example)

    If you're using the full Aphiria framework, you can register the extension method in a module:

    // $this in the closure will be rebound to an instance of IList
    $this->withExtensionMethod(
        $appBuilder,
        IList::class,
        'getFirstOrDefault',
        fn (mixed $default): mixed => $this->count() === 0 ? $default : $this->get(0)
    );
    

    If you're not using the full framework and just wish to use the aphiria/extension-methods package, you can register an extension method via:

    ExtensionMethodRegistry::registerExtensionMethod(
        IList::class,
        'getFirstOrDefault',
        fn (mixed $default): mixed => $this->count() === 0 ? $default : $this->get(0)
    );
    

    Net Library Extension Methods

    Extension methods for the Net library can be enabled using a module:

    $this->withNetExtensionMethods($appBuilder);
    

    This will allow you to perform the logic within RequestParser and ResponseFormatter, but on IRequest and IResponse directly. The following extension methods are included:

    // Body extension methods
    IBody::getMimeType();
    IBody::readAsFormInput();
    IBody::readAsJson();
    IBody::readAsMultipart();
    
    // Header extension methods
    Headers::isJson();
    Headers::isMultipart();
    Headers::parseContentTypeHeader();
    Headers::parseParameters();
    
    // Request extension methods
    IRequest::getActualMimeType();
    IRequest::getClientIPAddress();
    IRequest::isJson();
    IRequest::isMultipart();
    IRequest::parseAcceptCharsetHeader();
    IRequest::parseAcceptHeader();
    IRequest::parseAcceptLanguageHeader();
    IRequest::parseContentTypeHeader();
    IRequest::parseCookies();
    IRequest::parseParameters();
    IRequest::parseQueryString();
    IRequest::readAsFormInput();
    IRequest::readAsJson();
    IRequest::readAsMultipart();
    
    // Response extension methods
    IResponse::deleteCookie();
    IResponse::setCookie();
    IResponse::setCookies();
    IResponse::redirectToUri();
    IResponse::writeJson();
    
    // URI extension methods
    Uri::parseQueryString();
    

    Closes #133

    opened by davidbyoung 1
  • Add support for C#-style extension methods

    Add support for C#-style extension methods

    We have a lot of decorator methods for things like HTTP requests and responses to make it easier to parse/format common data. However, this requires an ugly syntax like:

    use Aphiria\Net\Http\Formatting\RequestParser;
    
    $requestParser = new RequestParser();
    $ip = $requestParser->getClientIPAddress($request);
    

    It would be nice if we had the ability to dynamically register extension methods to give us a more fluent-looking syntax, eg

    $ip = $request->getClientIPAddress();
    

    This would use a combination of __call(), a new IExtendable interface, and a trait. We could then add some module components to let us set up these extension methods.

    PR

    Todo

    • [x] Determine if it's possible to add this functionality to classes you do not "own", which is really the whole selling point of extension methods in other languages
      • I could add this functionality to Aphiria classes, but that doesn't open up the ability to call extension methods on 3rd party classes without implementing some base interface
      • If you have to manually call ExtensionMethodRegistry::call() in case the class you're extending doesn't implement IExtendable, does this library even get us much?
      • Update: It is correct that you cannot add this functionality to classes you do not own - really nothing will let you hook into a third party class in PHP at the moment. So, this is really only valuable for code you own.
    • [x] Add the ability to register extension methods via module components
    • [x] Add baked-in extension methods for all parser/formatter Net library methods as well as any other decorator methods
    • [x] Add some way of getting intellisense for baked-in extension methods, eg through PhpStorm meta files or PHPDoc
    • [ ] Create the extension-methods GitHub repository prior to merging the PR
    • [ ] Add aphiria/extension-methods to Packagist
    enhancement spike 
    opened by davidbyoung 1
  • Set up a Psalm baseline file for issues that we do not plan on fixing

    Set up a Psalm baseline file for issues that we do not plan on fixing

    Psalm supports having a baseline file for all issues that are not suppressed either by annotations or in psalm.xml.dist. Once the issues in #80 are fixed and we've fixed as many level 1 issues as we plan to fix, we should create a baseline file via:

    php vendor/vimeo/psalm/psalm --set-baseline=psalm.baseline.xml.dist
    
    enhancement 
    opened by davidbyoung 1
  • Update documentation to prefer attributes over code configuration

    Update documentation to prefer attributes over code configuration

    Now that PHP 8 natively supports attributes, the documentation should prefer them over configuring things like routes, commands, and validation constraints via attributes over methods in modules. We should continue to document the code-based configuration, but that should be secondary to attributes.

    documentation 
    opened by davidbyoung 1
  • Drop

    Drop "PHP_CS_FIXER_IGNORE_ENV=1" from PHP-CS-Fixer Composer script

    Once PHP-CS-Fixer properly supports PHP 8.2, we should drop PHP_CS_FIXER_IGNORE_ENV=1 from the phpcs-fix Composer script.

    • [ ] Update Aphiria's main composer.json
    • [ ] Update Aphiria's libraries' composer.json
    • [ ] Update app's composer.json
    • [ ] Update aphiria.com's composer.json
    enhancement good first issue 
    opened by davidbyoung 0
  • Provide way of rendering HTML error responses when invoked from a browser

    Provide way of rendering HTML error responses when invoked from a browser

    If we invoke the skeleton app's API and hit a non-existent route, we get a JSON response showing the problem details. It would be nice if there was a way to instead return a nicely formatted HTML response in the case that the API was invoked from a browser.

    enhancement 
    opened by davidbyoung 0
  • Support Swagger Docs

    Support Swagger Docs

    REST APIs need to be documented. Swagger is one of the most common ways of auto-generating that documentation, and should be adopted by Aphiria for all controller methods.

    enhancement 
    opened by davidbyoung 0
  • Add support for preloading

    Add support for preloading

    PHP 7.4 added support for preloading. We should add a way of preloading files in Aphiria applications. This might require allowing users to "warm up" a cache of files by hitting multiple endpoints to determine what files are commonly used so that they can be preloaded. Maybe a console command like:

    php aphiria app:preload http://localhost/foo http://localhost/bar
    
    enhancement 
    opened by davidbyoung 0
Releases(v1.0.0-alpha8)
Owner
Aphiria
The Aphiria Framework
Aphiria
Simple, extensible and powerful enumeration implementation for Laravel.

About Laravel Enum Simple, extensible and powerful enumeration implementation for Laravel. Enum key value pairs as class constants Full featured suite

Ben Sampson 1.8k Dec 23, 2022
Simple PHP API client for tube-hosting.com rest API

Tube-Hosting API PHP client Explanation This PHP library is a simple api wrapper/client for the tube-hosting.com api. It is based on the provided docu

null 4 Sep 12, 2022
PHP REST API Framework

PSX Framework About PSX is a framework written in PHP dedicated to build REST APIs. It is based on multiple components which cover many aspects of the

Apioo 121 Dec 30, 2022
A lightweight REST API framework

php-microframework A minimal PHP 8 REST API built onto php-microframework. Features Automatic routing based on URL path, e.g. https://domain/controlle

John 1 Oct 16, 2021
GraphQL API to Studio Ghibli REST API

GhibliQL GhibliQL is a GraphQL wrapper to the Studio Ghibli REST API Usage First, you'll need a GraphQL client to query GhibliQL, like GraphQL IDE Con

Sebastien Bizet 8 Nov 5, 2022
Single file PHP script that adds a REST API to a SQL database

PHP-CRUD-API Single file PHP script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database. NB: This is the TreeQL referen

Maurits van der Schee 3.2k Jan 8, 2023
PHP REST API without using any frameworks. Contains all CRUD operations.

PHP REST API without any framework and CRUD operations ?? Hi there, this is a simple REST API built in PHP without using any frameworks. This is built

Hanoak 10 Sep 5, 2022
Phalcon PHP REST API Package, still in beta, please submit issues or pull requests

PhREST API A Phalcon REST API package, based on Apigees guidelines as found in http://apigee.com/about/content/web-api-design Please see the skeleton

PhREST 29 Dec 27, 2022
Quickly and easily expose Doctrine entities as REST resource endpoints with the use of simple configuration with annotations, yaml, json or a PHP array.

Drest Dress up doctrine entities and expose them as REST resources This library allows you to quickly annotate your doctrine entities into restful res

Lee Davis 88 Nov 5, 2022
example repository training REST API

adalah codebase REST-API dari tugas peserta yang mengikuti training membangun REST API dengan lumen selama 2 minggu. studi kasus nya adalah REST API website marketplace untuk agrobisniss.

Nuris Akbar 6 Sep 4, 2021
A REST API that should power the Agile Monkeys CRM Service

This is a simple REST API that purposes to power the Agile Monkeys CRM service

Dickens odera 3 Jul 31, 2021
Laravel Client REST Camunda API

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Uriel Reyes 1 Nov 5, 2021
Osclass REST API plugin.

Osclass API Osclass API plugin, with all the required endpoints and JWT auth. Osclass App (Native + PWA) You always wanted a mobile app for Osclass, d

Defected 4 Sep 10, 2022
Joy VoyagerApi module adds REST Api end points to Voyager with Passport and Swagger support.

Joy VoyagerApi This Laravel/Voyager module adds REST Api with Passport and Swagger support to Voyager. By ?? Ramakant Gangwar. Prerequisites Composer

Ramakant Gangwar 14 Dec 12, 2022
A rest api repository with laravel.

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

kyo 2 Jan 17, 2022
A rest api repository with laravel.

API Back End This is the repository for the TKJ 1 Class 12 Web Back End API system, for detailed info, you can go to the main link of the Front End ap

kyo 2 Jan 17, 2022
A chess REST API.

Chess API A chess REST API. Documentation Read the latest docs here. Installation Clone the chesslablab/chess-api repo into your projects folder as it

ChesslabLab 6 Jan 5, 2023
API-Rest para información sobre administración-politica de Cuba

API_CUBA API desarrollada con Laravel PHP para brindar servicios REST para multiples plataformas sobre información politico administrativa de API_CUBA

Iosvany Alvarez 6 Mar 31, 2022
Extended response classes for Rest API clients/SDKs

Rest Response Extended response classes for Rest API clients/SDKs. About This package is intended to be component of SDKs so the responses can be easi

Ilesanmi Olawale Adedotun 2 Mar 28, 2022