WellRESTed ========== [![Build Status](https://travis-ci.org/pjdietz/wellrested.svg?branch=master)](https://travis-ci.org/pjdietz/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. Requirements ------------ - PHP 5.3 - [PHP cURL](http://php.net/manual/en/book.curl.php) for making requests with the [`Client`](src/pjdietz/WellRESTed/Client.php) class (Optional) 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: ```json { "require": { "pjdietz/wellrested": "2.*" } } ``` Use Composer to download and install WellRESTed. Run these commands from the directory containing the **composer.json** file. ```bash $ 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. Overview -------- ### Routing and Routes WellRESTed's primary goal is to facilitate mapping of URIs to classes that will provide or accept representations. To do this, create a [`Router`](src/pjdietz/WellRESTed/Router.php) instance and load it up with some routes. ```php // Build the router. $myRouter = new Router(); $myRouter->add( ["/exact/", $exactHandler], ["/prefix/*", $prefixHandler], ["/template/{id}/", $templateHandler], ["~/regex/([0-9+])~", $regexHandler], ); $myRouter->respond(); ``` Each route maps a path to a handler. The path may be: - An exact match to a path (fastest, least powerful) - A prefix (ending with `*`) - A URI template with variables indicated with curly braces (ex: `{variable}`) - A regular expression (slowest, most powerful) Template and Regex routes will forward variables or captures to their handlers. Template routes can also be customized to restrict variables to match specific patterns. (TODO LINK) The handler may be any of the following: - An instance that implements [`HandlerInterface`](src/pjdietz/WellRESTed/Interfaces/HandlerInterface.php) - A string containing the fully qualified name of a `HandlerInterface` concrete class - A callable that returns a `HandlerInterface` concrete class The best choices are strings and callables because they delay instantiation until the last instant. If your class is autoloaded, the class never needs to be loaded or instantiated until it is needed. To illustrate, image you have a namespace `\MyApi` with several classes inside that implement `HandlerInterface`. ```php // Build the router. $myRouter = new Router(); $myRouter->add( ["/instance/", new \MyApi\InstanceHandler()], ["/string/", '\MyApi\StringHandler'], ["/callable/", function () { return new \MyApi\CallableHandler(); }] ); $myRouter->respond(); ``` While the callable approach may look a bit weird, it's very powerful, and makes dependency injection very easy. (TODO LINK) ### Handlers Any class that implements [`HandlerInterface`](src/pjdietz/WellRESTed/Interfaces/HandlerInterface.php) may be the handler for a route. This could be a class that builds the actual response, or it could be another [`Router`](src/pjdietz/WellRESTed/Router.php). When a router dispatches a request to a handler, it calls the handler's `getResponse()` method, passing along the request and an array of extra arguments. These extra arguments may be captures from a regular expression route, variables from a URI template route, or any other arbitrary pieces of information you want to pass to the handler. The handler builds and returns a [`ResponseInterface`](src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php). Or, the handler may return `null` to indicate that it won't be handling the request after all. #### Handler Class WellRESTed provides the abstract class [`Handler`](src/pjdietz/WellRESTed/Handler.php) which you may subclass for your handlers. This class provides methods for responding based on HTTP method. When you create your [`Handler`](src/pjdietz/WellRESTed/Handler.php) 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`. ```php 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](https://github.com/pjdietz/wellrested/wiki/Handlers) to learn about the subclassing the [`Handler`](src/pjdietz/WellRESTed/Handler.php) class. See [HandlerInteface](https://github.com/pjdietz/wellrested/wiki/HandlerInterface) to learn about more ways build completely custom classes. ### Responses You've already seen a [`Response`](src/pjdietz/WellRESTed/Response.php) used inside a [`Handler`](src/pjdietz/WellRESTed/Handler.php) in the examples above. You can also create a [`Response`](src/pjdietz/WellRESTed/Response.php) outside of [`Handler`](src/pjdietz/WellRESTed/Handler.php). Let's take a look at creating a new [`Response`](src/pjdietz/WellRESTed/Response.php), setting a header, supplying the body, and outputting. ```php $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`](src/pjdietz/WellRESTed/Handler.php), you can also use the [`Request`](src/pjdietz/WellRESTed/Request.php) class to read info for the request sent to the server by using the static method `Request::getRequest()`. ```php // 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`](src/pjdietz/WellRESTed/Client.php) class allows you to make an HTTP request using cURL. (This feature requires [PHP cURL](http://php.net/manual/en/book.curl.php).) ```php // 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()); } ``` Copyright and License --------------------- Copyright © 2015 by PJ Dietz Licensed under the [MIT license](http://opensource.org/licenses/MIT)