7.5 KiB
WellRESTed
WellRESTed is a micro-framework for creating RESTful APIs in PHP. It provides a lightweight yet powerful routing system and classes to make working with HTTP requests and responses clean and easy.
Version 2
It's more RESTed than ever!
Version 2 brings a lot improvements over 1.x, but it is not backwards compatible. See Changes from Version 1 if you are migrating from a previous 1.x version of WellRESTed.
Requirements
Install
Add an entry for "pjdietz/wellrested" to your composer.json file's require property. If you are not already using Composer, create a file in your project called "composer.json" with the following content:
{
"require": {
"pjdietz/wellrested": "2.*"
}
}
Use Composer to download and install WellRESTed. Run these commands from the directory containing the composer.json file.
$ curl -s https://getcomposer.org/installer | php
$ php composer.phar install
You can now use WellRESTed by including the vendor/autoload.php file generated by Composer.
Examples
Routing
WellRESTed's primary goal is to facilitate mapping of URIs to classes that will provide or accept representations. To do this, create a Router instance and load it up with some routes. Each route is simply a mapping of a path or path pattern to a class name. The class name represents the "handler" (any class implementing HandlerInterface ) which the router will dispatch when it receives a request for the given URI. The handlers are never instantiated or loaded unless they are needed.
// Build the router.
$myRouter = new Router();
$myRouter->addRoutes(array(
new StaticRoute("/", "\\myapi\\Handlers\\RootHandler"),
new StaticRoute("/cats/", "\\myapi\\Handlers\\CatCollectionHandler"),
new TemplateRoute("/cats/{id}/", "\\myapi\\Handlers\\CatItemHandler")
));
$myRouter->respond();
See Routes to learn about the various route classes.
Optimized Route Lookup
StaticRoute and PrefixRoute routes are optimized by providing a direct lookup from path to handler. This is different from convential lookups because a match must be found by iterating through the entire list of routes in the router. This reduces the lookup complexity from O(n)—linear—to O(1)—constant.
Handlers
Any class that implements HandlerInterface may be the handler for a route. This could be a class that builds the actual response, or it could be another Router.
For most cases, you'll want to use a subclass of the Handler class, which provides methods for responding based on HTTP method. When you create your Handler subclass, you will implement a method for each HTTP verb you would like the endpoint to support. For example, if /cats/ should support GET, you would override the get() method. For POST, post(), etc.
Here's a simple Handler that allows GET and POST.
class CatsCollectionHandler extends \pjdietz\WellRESTed\Handler
{
protected function get()
{
// Read some cats from the database, cache, whatever.
// ...read these an array as the variable $cats.
// Set the values for the instance's response member. This is what the
// Router will eventually output to the client.
$this->response->setStatusCode(200);
$this->response->setHeader("Content-Type", "application/json");
$this->response->setBody(json_encode($cats));
}
protected function post()
{
// Read from the instance's request member and store a new cat.
$cat = json_decode($this->request->getBody());
// ...store $cat to the database...
// Build a response to send to the client.
$this->response->setStatusCode(201);
$this->response->setBody(json_encode($cat));
}
}
See Handlers to learn about the subclassing the Handler class.
See HandlerInteface to learn about more ways build completely custom classes.
Responses
You've already seen a Response used inside a Handler in the examples above. You can also create a Response outside of Handler. Let's take a look at creating a new Response, setting a header, supplying the body, and outputting.
$resp = new \pjdietz\WellRESTed\Response();
$resp->setStatusCode(200);
$resp->setHeader("Content-type", "text/plain");
$resp->setBody("Hello world!");
$resp->respond();
exit;
This will output nice response, complete with status code, headers, body.
Requests
From outside the context of a Handler, you can also use the Request class to read info for the request sent to the server by using the static method Request::getRequest().
// Call the static method Request::getRequest() to get the request made to the server.
$rqst = \pjdietz\WellRESTed\Request::getRequest();
if ($rqst->getMethod() === 'PUT') {
$obj = json_decode($rqst->getBody());
// Do something with the JSON sent as the message body.
// ...
}
HTTP Client
The Client class allows you to make an HTTP request using cURL.
(This feature requires PHP cURL.)
// Prepare a request.
$rqst = new \pjdietz\WellRESTed\Request();
$rqst->setUri('http://my.api.local/resources/');
$rqst->setMethod('POST');
$rqst->setBody(json_encode($newResource));
// Use a Client to get a Response.
$client = new Client();
$resp = $client->request($rqst);
// Read the response.
if ($resp->getStatusCode() === 201) {
// The new resource was created.
$createdResource = json_decode($resp->getBody());
}
Building Routes with JSON
WellRESTed also provides a class to construct routes for you based on a JSON description. Here's an example:
$json = <<<'JSON'
{
"handlerNamespace": "\\myapi\\Handlers",
"routes": [
{
"path": "/",
"handler": "RootHandler"
},
{
"path": "/cats/",
"handler": "CatCollectionHandler"
},
{
"tempalte": "/cats/{id}",
"handler": "CatItemHandler"
}
]
}
JSON;
$builder = new RouteBuilder();
$routes = $builder->buildRoutes($json);
$router = new Router();
$router->addRoutes($routes);
$router->respond();
When you build routes through JSON, you can provide a handlerNamespace to be affixed to the front of every handler.
Copyright and License
Copyright © 2015 by PJ Dietz Licensed under the MIT license