Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/phprest/phprest
REST-like PHP micro-framework.
https://github.com/phprest/phprest
Last synced: about 1 month ago
JSON representation
REST-like PHP micro-framework.
- Host: GitHub
- URL: https://github.com/phprest/phprest
- Owner: phprest
- License: mit
- Created: 2014-11-05T18:07:21.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2020-07-28T12:07:38.000Z (over 4 years ago)
- Last Synced: 2024-01-25T07:10:17.330Z (11 months ago)
- Language: PHP
- Homepage:
- Size: 274 KB
- Stars: 310
- Watchers: 15
- Forks: 17
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: changelog.md
- License: LICENSE
Awesome Lists containing this project
- awesome-rest - phprest - Specialized REST microframework for PHP. (Servers / PHP)
README
# Phprest
[![Build Status](https://travis-ci.com/ayanozturk/phprest.svg?branch=master)](https://travis-ci.com/ayanozturk/phprest)
[![Code Coverage](https://scrutinizer-ci.com/g/ayanozturk/phprest/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/ayanozturk/phprest/?branch=master)
[![Quality Score](https://scrutinizer-ci.com/g/ayanozturk/phprest/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ayanozturk/phprest/?branch=master)
[![Software License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)# Description
REST-like PHP micro-framework.
It's based on the [Proton](https://github.com/alexbilbie/Proton) ([StackPhp](http://stackphp.com/) compatible) micro-framework.
Phprest gives you only the very basics to build your own architecture within your own framework and assemble any folder structure you like. It is just a thin layer around your application with the help of some great libraries.
# Components
* [League\Container](https://github.com/thephpleague/container)
* [League\Route](https://github.com/thephpleague/route)
* [League\Event](https://github.com/thephpleague/event)
* [League\BooBoo](https://github.com/thephpleague/booboo)
* [Willdurand\Negotiation](https://github.com/willdurand/Negotiation)
* [Willdurand\Hateoas](https://github.com/willdurand/Hateoas)
* [Monolog\Monolog](https://github.com/Seldaek/monolog)
* [Stack\Builder](https://github.com/stackphp/builder)# Skills
* Dependency injection
* Routing
* Error handling
* Serialization
* Deserialization
* HATEOAS
* API versioning
* Pagination
* Logging# ToC
* [Installation](https://github.com/phprest/phprest#installation)
* [Usage](https://github.com/phprest/phprest#usage)
* [Services](https://github.com/phprest/phprest#services)
* [Setup](https://github.com/phprest/phprest#setup)
* [Configuration](https://github.com/phprest/phprest#configuration)
* [Logging](https://github.com/phprest/phprest#logging)
* [Usage with Stack](https://github.com/phprest/phprest#usage-with-stack)
* [API versioning](https://github.com/phprest/phprest#api-versioning)
* [Routing](https://github.com/phprest/phprest#routing)
* [Simple routing](https://github.com/phprest/phprest#simple-routing)
* [Routing with arguments](https://github.com/phprest/phprest#routing-with-arguments)
* [Routing through a controller](https://github.com/phprest/phprest#routing-through-a-controller)
* [Routing through a service controller](https://github.com/phprest/phprest#routing-through-a-service-controller)
* [Routing with annotations](https://github.com/phprest/phprest#routing-with-annotations)
* [Controller](https://github.com/phprest/phprest#controller)
* [Serialization, Deserialization, HATEOAS](https://github.com/phprest/phprest#serialization-deserialization-hateoas)
* [Serialization example](https://github.com/phprest/phprest#serialization-example)
* [Deserialization example](https://github.com/phprest/phprest#deserialization-example)
* [Pagination](https://github.com/phprest/phprest#pagination)
* [Responses](https://github.com/phprest/phprest#responses)
* [1xx, 2xx, 3xx status codes](https://github.com/phprest/phprest#1xx-2xx-3xx-status-codes)
* [Example](https://github.com/phprest/phprest#example)
* [Types](https://github.com/phprest/phprest#types)
* [4xx, 5xx status codes](https://github.com/phprest/phprest#4xx-5xx-status-codes)
* [Example](https://github.com/phprest/phprest#example-1)
* [Types](https://github.com/phprest/phprest#types-1)
* [Dependency Injection Container](https://github.com/phprest/phprest#dependency-injection-container)
* [CLI](https://github.com/phprest/phprest#cli)
* [Error handler](https://github.com/phprest/phprest#error-handler)
* [On a single exception](https://github.com/phprest/phprest#on-a-single-exception)
* [Authentication](https://github.com/phprest/phprest#authentication)
* [Basic Authentication](https://github.com/phprest/phprest#basic-authentication)
* [JWT Authentication](https://github.com/phprest/phprest#jwt-authentication)
* [API testing](https://github.com/phprest/phprest#api-testing)
* [API documentation](https://github.com/phprest/phprest#api-documentation)# Installation
Install it through composer.
```json
{
"require": {
"phprest/phprest": "@stable"
}
}
```**tip:** you should browse the [`phprest/phprest`](https://packagist.org/packages/phprest/phprest)
page to choose a stable version to use, avoid the `@stable` meta constraint.# Usage
## Services
There are a couple of services which can help you to solve some general problems:
* [Validator](https://github.com/phprest/phprest-service-validator)
* [Request Filter](https://github.com/phprest/phprest-service-request-filter)
* [Orm](https://github.com/phprest/phprest-service-orm)*These are separate repositories.*
## Setup
```php
get('/{version:\d\.\d}/', function (Request $request) {
return new Response\Ok('Hello World!');
});$app->run();
```### Configuration
You should check the [Config](src/Config.php) class.
### Logging
```php
setLoggerConfig(new LoggerConfig('phprest', $loggerHandlers));
$config->setLoggerService(new LoggerService());
```### Usage with Stack
You can register middlewares trough the ```registerMiddleware```function.
```php
$app->registerMiddleware('Jsor\Stack\JWT', [
[
'firewall' => [
['path' => '/', 'anonymous' => false],
['path' => '/tokens', 'anonymous' => true]
],
'key_provider' => function() {
return 'secret-key';
},
'realm' => 'The Glowing Territories'
]
]);
```## API Versioning
Phprest works with API versions by default. This means that the [ApiVersion Middleware](src/Middleware/ApiVersion.php) manipulates the incoming request. The version (based on the current Accept header) is added to the path.
What does it mean?
|Accept header|Route|Result route*|
|-------------|-----|-------------|
|application/vnd.phprest-v1+json|/temperatures|/1.0/temperatures|
|application/vnd.phprest-v3.5+json|/temperatures|/3.5/temperatures|
|\*/\*|/temperatures|/*the version which you set in your [Config](src/Config.php#L70)*/temperatures|\* *It is not a redirect or a forward method, it is just an inner application routing through a middleware.*
---
|Accept/Content-Type header can be|Transfers to|
|---------------------------------|------------|
|application/vnd.**Vendor**-v**Version**+json|itself|
|application/vnd.**Vendor**+json; version=**Version**|itself|
|application/vnd.**Vendor**-v**Version**+xml|itself|
|application/vnd.**Vendor**+xml; version=**Version**|itself|
|application/json|application/vnd.**Vendor**-v**Version**+json|
|application/xml|application/vnd.**Vendor**-v**Version**+xml|
|\*/\*|application/vnd.**Vendor**-v**Version**+json|
API **Version** only can be one of the following ranges:
* 0 - 9
* 0.0 - 9.9---
* If Accept header is not parsable
* then Phprest throws a Not Acceptable exception
* If you do a deserialization and Content-Type header is not parsable
* then Phprest throws an Unsupported Media Type exception## Routing
For more information please visit [League/Route](https://github.com/thephpleague/route).
### Simple routing
```php
get('/{version:\d\.\d}/hello', function (Request $request, $version) {
# You can leave the $request and the $version variable
return new Response\Ok('Hello World!');
});
```* The [ApiVersion Middleware](src/Middleware/ApiVersion.php) manipulates the inner routing every time, so you have to care about the first part of your route as a version number.
* This route is available in all API versions (see the ```\d\.\d``` regular expression)
* You can set a fix API version number too e.g. ```'/3.6/hello'```### Routing with arguments
```php
get('/2.4/hello/{name:word}', function (Request $request, $name) {
return new Response\Ok('Hello ' . $name);
});
```* This route is available only in API version 2.4
### Routing through a controller
```php
get('/{version:\d\.\d}/', '\Foo\Bar\HomeController::index');
``````php
get('/{version:\d\.\d}/', 'HomeController::index');
```### Routing with annotations
You have to register your controller.
```php
registerController('\Foo\Bar\Controller\Home');
``````php
id = $id;
$this->value = $value;
$this->created = $created;
}
}
```The router:
```php
post('/{version:\d\.\d}/temperatures', function () use ($app, $version) {
$temperature = new \Foo\Entity\Temperature(1, 32, new \DateTime());
return new Response\Created('/temperatures/1', $temperature);
});
```Json response (Accept: application/vnd.vendor+json; version=1):
```json
{
"id": 1,
"value": 32,
"_links": {
"self": {
"href": "\/temperatures\/1"
}
}
}
```Xml response (Accept: application/vnd.vendor+xml; version=1):
```xml
1
32
```
Properties will be translated from camel-case to a lower-cased underscored name, e.g. camelCase -> camel_case by default. If you want to use a custom serialized name you have to use the **@SerializedName** option on your attribute.
### Deserialization example
You have to use the [HATEOAS Util](src/Service/Hateoas/Util.php) trait in your controller to do deserialization.
```php
# ...
use JMS\Serializer\Exception\RuntimeException;
# ...
public function post(Request $request)
{
try {
/** @var \Foo\Entity\Temperature $temperature */
$temperature = $this->deserialize('\Foo\Entity\Temperature', $request);
} catch (RuntimeException $e) {
throw new Exception\UnprocessableEntity(0, [new Service\Validator\Entity\Error('', $e->getMessage())]);
}
}
# ...
```## Pagination
```php
query->all()
1, # page, should be (int)$request->query->get('page')
10, # limit, should be (int)$request->query->get('limit')
5, # total pages
'page', # page route parameter name, optional, defaults to 'page'
'limit', # limit route parameter name, optional, defaults to 'limit'
true, # absolute URIs
47 # total number of rows
);
# ...
return new Response\Ok($paginatedCollection);
```For more informations please visit the [HATEOAS docs](https://github.com/willdurand/Hateoas#dealing-with-collections)
## Responses
There are several responses you can use by default, one of them is the Ok response.
### 1xx, 2xx, 3xx status codes
These are simple Response objects.
#### Example
```php
get('/', function (Request $request) {
return new Response\Ok('Hello World!');
});
# ...
```#### Types
|Responses|
|-------------|
|Accepted|
|Created|
|NoContent|
|NotModified|
|Ok|### 4xx, 5xx status codes
These are Exceptions.
#### Example
```php
get('/', function (Request $request) {
# ...
throw new \Phprest\Exception\BadRequest();
# ...
});
# ...
```#### Types
|Exceptions|
|----------|
|BadRequest|
|Conflict|
|Forbidden|
|Gone|
|InternalServerError|
|MethodNotAllowed|
|NotAcceptable|
|NotFound|
|TooManyRequests|
|PreconditionFailed|
|TooManyRequests|
|Unauthorized|
|UnprocessableEntity|
|UnsupportedMediaType|## Dependency Injection Container
See [Proton's doc](https://github.com/alexbilbie/Proton#dependency-injection-container) and for more information please visit [League/Container](https://github.com/thephpleague/container).
## CLI
You can use a helper script if you want after a composer install (```vendor/bin/phprest```).
You have to provide the (bootstrapped) app instance for the script. You have two options for this:
* Put your app instance to a specific file: ```app/app.php```
* You have to return with the bootstrapped app instance in the proper file
* Put the path of the app instance in the ```paths.php``` file
* You have to return with an array from the ```paths.php``` file with the app file path under the ```app``` array key## Error handler
Phprest handles error with [League\BooBoo](https://github.com/thephpleague/booboo). The default formatter is [Json and Xml Formatter](src/ErrorHandler/Formatter/JsonXml.php).
### On a single exception
```php
get('/{version:\d\.\d}/', function (Request $request, $version) {
throw new \Phprest\Exception\Exception('Code Red!', 9, 503);
});
# ...
```The response is content negotiationed (xml/json), the status code is 503.
```json
{
"code": 9,
"message": "Code Red!",
"details": []
}
``````xml
9
```
# Authentication
### Basic Authentication
You'll need this package:
* [Dflydev\Dflydev-stack-basic-authentication](https://github.com/dflydev/dflydev-stack-basic-authentication)```php
$app->registerMiddleware('Dflydev\Stack\BasicAuthentication', [
[
'firewall' => [
['path' => '/', 'anonymous' => false],
['path' => '/temperatures', 'method' => 'GET', 'anonymous' => true]
],
'authenticator' => function ($username, $password) {
if ('admin' === $username && 'admin' === $password) {
# Basic YWRtaW46YWRtaW4=
return 'success';
}
},
'realm' => 'The Glowing Territories'
]
]);
```### JWT Authentication
You'll need this package:
* [Jsor\Stack-jwt](https://github.com/jsor/stack-jwt)```php
$app->registerMiddleware('Jsor\Stack\JWT', [
[
'firewall' => [
['path' => '/', 'anonymous' => false],
['path' => '/tokens', 'anonymous' => true]
],
'key_provider' => function() {
return 'secret-key';
},
'realm' => 'The Glowing Territories'
]
]);
```# API testing
There are a couple of great tools out there for testing your API.
* [Postman](http://www.getpostman.com/) and [Newman](https://github.com/a85/Newman)
* Tip: Create collections in Postman and then run these in Newman
* [Frisby](https://github.com/vlucas/frisby)
* Frisby is a REST API testing framework built on node.js and Jasmine that makes testing API endpoints easy, fast, and fun.
* [Runscope](https://www.runscope.com/)
* For Api Monitoring and Testing# API documentation
Just a few recommendations:
* [API Blueprint](https://apiblueprint.org/)
* API Blueprint is a documentation-oriented API description language. A couple of semantic assumptions over the plain Markdown.
* [Swagger](http://swagger.io/)
* With a Swagger-enabled API, you get interactive documentation, client SDK generation and discoverability.