Update documentation and README
This commit is contained in:
parent
2398fc6b77
commit
e77c85f71b
54
README.md
54
README.md
|
|
@ -9,7 +9,7 @@ Requirements
|
|||
------------
|
||||
|
||||
- PHP 5.3
|
||||
- [PHP cURL](http://php.net/manual/en/book.curl.php) for making requests with the `Client` class (Optional)
|
||||
- [PHP cURL](http://php.net/manual/en/book.curl.php) for making requests with the [`Client`](src/pjdietz/WellRESTed/Client.php) class (Optional)
|
||||
|
||||
|
||||
Install
|
||||
|
|
@ -40,7 +40,7 @@ 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 `Route`s. Each `Route` is simply a mapping of a URI 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.**
|
||||
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. Each route is simply a mapping of a URI 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.**
|
||||
|
||||
```php
|
||||
// Build the router.
|
||||
|
|
@ -58,7 +58,7 @@ See [Routes](documentation/routes.md) to learn about the various route classes.
|
|||
|
||||
### Building Routes with JSON
|
||||
|
||||
WellRESTed also provides a class to construct routes for you based on a JSON description. Here's an example.
|
||||
WellRESTed also provides a class to construct routes for you based on a JSON description. Here's an example:
|
||||
|
||||
```php
|
||||
$json = <<<'JSON'
|
||||
|
|
@ -89,15 +89,13 @@ $router->addRoutes($routes);
|
|||
$router->respond();
|
||||
```
|
||||
|
||||
Notice that when you build routes through JSON, you can provide a `handlerNamespace` to be affixed to the front of every `handler`.
|
||||
Notice that when you build routes through JSON, you can provide a `handlerNamespace` to be affixed to the front of every handler.
|
||||
|
||||
### 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 another `Router`.
|
||||
Any class that implements [`HandlerInterface`](src/pjdietz/WellRESTed/Interface/HandlerInterface.php) may be the handler for a route. This could be a class that builds the actual response, or it could another [`Router`](src/pjdietz/WellRESTed/Router.php).
|
||||
|
||||
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.
|
||||
|
||||
If your endpoint should reject particular verbs, no worries. The Handler base class defines the default verb-handling methods to respond with a **405 Method Not Allowed** status.
|
||||
For most cases, you'll want to use a subclass of the [`Handler`](src/pjdietz/WellRESTed/Handler.php) class, which 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`.
|
||||
|
||||
|
|
@ -129,43 +127,11 @@ class CatsCollectionHandler extends \pjdietz\WellRESTed\Handler
|
|||
}
|
||||
```
|
||||
|
||||
#### Path Variables
|
||||
|
||||
When you use a `TemplateRoute` with variables (or a `RegexRoute` with capture groups), you can access the variables (or captures) through the `Handler` member variable `$args`.
|
||||
|
||||
Create this route...
|
||||
```php
|
||||
$route = TemplateRoute("/cats/{id}", "CatItemHandler");
|
||||
```
|
||||
|
||||
...which dispatches a `CatItemHandler` instance.
|
||||
```php
|
||||
class CatItemHandler extends \pjdietz\WellRESTed\Handler
|
||||
{
|
||||
protected function get()
|
||||
{
|
||||
// Find a cat ($cat) based on $this->args["id"]
|
||||
$id = $this->args["id"]
|
||||
// ...do lookup here...
|
||||
|
||||
if ($cat) {
|
||||
// The cat exists! Let's output a representation.
|
||||
$this->response->setStatusCode(200);
|
||||
$this->response->setHeader("Content-Type", "application/json");
|
||||
$this->response->setBody(json_encode($cat));
|
||||
} else {
|
||||
// The ID did not match anything.
|
||||
$this->response->setStatusCode(404);
|
||||
$this->response->setHeader("Content-Type", "text/plain");
|
||||
$this->response->setBody("No cat with id " . $this->args["id"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
See [Handlers](documentation/handler.md) to learn about the various route classes.
|
||||
|
||||
### Responses
|
||||
|
||||
You've already seen a `Response` in use in the examples above. You can also a `Response` outside of `Handler`. Let's take a look at creating a new `Response`, setting a header, supplying the body, and outputting.
|
||||
You've already seen a [`Response`](src/pjdietz/WellRESTed/Response.php) in use in the examples above. You can also 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();
|
||||
|
|
@ -178,7 +144,7 @@ exit;
|
|||
|
||||
### 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()`.
|
||||
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 a reference to the Request
|
||||
|
|
@ -194,7 +160,7 @@ if ($rqst->getMethod() === 'PUT') {
|
|||
|
||||
### HTTP Client
|
||||
|
||||
The `Client` class allows you to make an HTTP request using cURL.
|
||||
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).)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
# Handlers
|
||||
|
||||
|
||||
[`Handler`](../src/pjdietz/WellRESTed/Handler.php) is an abstract base class for you to subclass to create controllers for generating responses given requests.
|
||||
|
||||
## Instance Members
|
||||
|
||||
Your [`Handler`](../src/pjdietz/WellRESTed/Handler.php) subclass has access to three protected members:
|
||||
|
||||
Member | Type | Description
|
||||
---------- | ---- | -----------
|
||||
`args` | `array` | Map of variables to supplement the request, usually path variables.
|
||||
`request` | [`RequestInterface`](../src/pjdietz/WellRESTed/Interfaces/RequestInterface.php) | The HTTP request to respond to.
|
||||
`response` | [`RequestInterface`](../src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php) | The HTTP response to send based on the request.
|
||||
|
||||
|
||||
## HTTP Verbs
|
||||
|
||||
Most of the action takes place inside the methods called in response to specific HTTP verbs. For example, to handle a `GET` request, implement the `get` method.
|
||||
|
||||
```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));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Implement the methods that you want to support. If you don't want to support `POST`, don't implement it. The default behavior is to respond with `405 Method Not Allowed` for most verbs.
|
||||
|
||||
The methods available to implement are:
|
||||
|
||||
HTTP Verb | Method | Default behavior
|
||||
--------- | --------- | ----------------------
|
||||
`GET` | `get` | 405 Method Not Allowed
|
||||
`HEAD` | `head` | Call `get`, then clean the response body
|
||||
`POST` | `post` | 405 Method Not Allowed
|
||||
`PUT` | `put` | 405 Method Not Allowed
|
||||
`DELETE` | `delete` | 405 Method Not Allowed
|
||||
`PATCH` | `patch` | 405 Method Not Allowed
|
||||
`OPTIONS` | `options` | Add `Allow` header, if able
|
||||
|
||||
### `OPTIONS` requests and `Allowed` headers
|
||||
|
||||
An `OPTIONS` request to your endpoint should result in the API responding with an `Allow` header listing the verbs the endpoint supports. For example:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Allow: GET, HEAD, POST, OPTIONS
|
||||
Content-Length: 0
|
||||
```
|
||||
|
||||
To support `OPTIONS` requests, implement `getAllowedMethods` and return an array of the methods you support. For a handler that supports the methods in the example response, do this:
|
||||
|
||||
```php
|
||||
protected function getAllowedMethods()
|
||||
{
|
||||
return array("GET", "HEAD", "POST", "OPTIONS");
|
||||
}
|
||||
```
|
||||
|
||||
You do not need to implement `options`. `options` by default calls `getAllowedMethods`. If it gets a return value, it sets the status code to `200 OK` and adds the `Allow` header. Otherwise, it responds `405 Method Not Allowed`.
|
||||
|
||||
### Custom Verbs
|
||||
|
||||
To support custom verbs, redefine the `buildResponse`. To respond to the custom verb `SNIFF`, to this:
|
||||
|
||||
```php
|
||||
protected function buildResponse()
|
||||
{
|
||||
switch ($this->request->getMethod()) {
|
||||
case 'SNIFF':
|
||||
// Assuming you also made a sniff() method...
|
||||
$this->sniff();
|
||||
break;
|
||||
default:
|
||||
// Let the parent's method do the rest.
|
||||
self::buildResponse();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## HttpExceptions
|
||||
|
||||
Another useful feature of the [`Handler`](../src/pjdietz/WellRESTed/Handler.php) class is that it catches exceptions deriving from [`HttpException`](../src/pjdietz/WellRESTed/Exceptions/HttpExceptions) and turns them into responses.
|
||||
|
||||
[`HttpException`](../src/pjdietz/WellRESTed/Exceptions/HttpExceptions) and its subclasses provide the status code and description for simple error responses.
|
||||
|
||||
For example, you can throw a `NotFountException` if the resource the request indicates does not exist.
|
||||
|
||||
|
||||
```php
|
||||
use \pjdietz\WellRESTed\Handler;
|
||||
use \pjdietz\WellRESTed\Exceptions\HttpExceptions\NotFoundException;
|
||||
|
||||
class CatsCollectionHandler extends Handler
|
||||
{
|
||||
protected function get()
|
||||
{
|
||||
// Lookup a cat by ID.
|
||||
$cat = Cat::getById($this->args["id"]);
|
||||
if (!$cat) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$this->response->setStatusCode(200);
|
||||
$this->response->setHeader("Content-Type", "application/json");
|
||||
$this->response->setBody(json_encode($cat));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Your [`Handler`](../src/pjdietz/WellRESTed/Handler.php) will automatically turn this into a `404 Not Found` response.
|
||||
|
||||
Here are the available `HttpException` classes:
|
||||
|
||||
Response Code | Class
|
||||
--------------------------- | -----------------------
|
||||
`400 Bad Request` | `BadRequestException`
|
||||
`401 Unauthorized` | `UnauthorizedException`
|
||||
`403 Forbidden` | `ForbiddenException`
|
||||
`404 Not Found` | `NotFoundException`
|
||||
`409 Conflict` | `ConflictException`
|
||||
`500 Internal Server Error` | `HttpException`
|
||||
|
||||
You can also create your own by subclass `HttpException` and setting the exception's `$code` to the status code and `$messge` to a default message.
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
# Routes
|
||||
|
||||
WellRESTed comes with a few Route classes:
|
||||
WellRESTed comes with a few route classes:
|
||||
|
||||
- `StaticRoute`: Matches request paths exactly
|
||||
- `TemplateRoute`: Matches URI templates
|
||||
- `RegexRoute`: Matches a custom regular expression
|
||||
- [`StaticRoute`](../src/pjdietz/WellRESTed/Routes/StaticRoute.php): Matches request paths exactly
|
||||
- [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php): Matches URI templates
|
||||
- [`RegexRoute`](../src/pjdietz/WellRESTed/Routes/RegexRoute.php): Matches a custom regular expression
|
||||
|
||||
Each works basically the same way: It first checks to see if it is a match for the request. If it's a match, it instantiates a specific class implementing the `HandlerInterface` (autoloading the class, if needed). Finally, it uses the handler class to provide a response.
|
||||
Each works basically the same way: It first checks to see if it is a match for the request. If it's a match, it instantiates a specific class implementing the [`HandlerInterface`](../src/pjdietz/WellRESTed/Interfaces/HandlerInterface.php) (autoloading the class, if needed). Finally, it uses the handler class to provide a response.
|
||||
|
||||
## StaticRoute
|
||||
|
||||
Use a `StaticRoute` when you know the exact path you want to handle. This route will match only requests to `/cats/`.
|
||||
Use a [`StaticRoute`](../src/pjdietz/WellRESTed/Routes/StaticRoute.php) when you know the exact path you want to handle. This route will match only requests to `/cats/`.
|
||||
|
||||
```php
|
||||
$route = new StaticRoute("/cats/", "CatHandler");
|
||||
```
|
||||
|
||||
You can also make a `StaticRoute` that matches multiple exact paths. For example, suppose you have a multi-use `AnimalHandler` that you want to invoke to handle requests to `/cats/`, `/dogs/`, and `/birds/`. You can make this by passing an array instead of a string as the first parameter.
|
||||
You can also make a [`StaticRoute`](../src/pjdietz/WellRESTed/Routes/StaticRoute.php) that matches multiple exact paths. For example, suppose you have a multi-use `AnimalHandler` that you want to invoke to handle requests to `/cats/`, `/dogs/`, and `/birds/`. You can make this by passing an array instead of a string as the first parameter.
|
||||
|
||||
```php
|
||||
$route = new StaticRoute(array("/cats/", "/dogs/", "/birds/"), "AnimalHandler");
|
||||
|
|
@ -24,7 +24,7 @@ $route = new StaticRoute(array("/cats/", "/dogs/", "/birds/"), "AnimalHandler");
|
|||
|
||||
## TemplateRoute
|
||||
|
||||
`StaticRoutes` are the best choice if you know the exact path up front. But, what if you want to handle a path that includes a variable? That's where the `TemplateRoute` comes in.
|
||||
[`StaticRoute`](../src/pjdietz/WellRESTed/Routes/StaticRoute.php) is the best choice if you know the exact path up front. But, what if you want to handle a path that includes a variable? That's where the [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) comes in.
|
||||
|
||||
Here's a route that will match a request to a specific cat by ID and send it to a `CatItemHandler`.
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ Here's a route that will match a request to a specific cat by ID and send it to
|
|||
$route = new TemplateRoute("/cats/{id}", "CatItemHandler");
|
||||
```
|
||||
|
||||
A `TemplateRoute` use a URI template to match a request. To include a variable in your template, enclose it in `{}`. The variable will be extracted and made available for the handler in the handler's `args` member.
|
||||
A [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) use a URI template to match a request. To include a variable in your template, enclose it in `{}`. The variable will be extracted and made available for the handler in the handler's `args` member.
|
||||
|
||||
```php
|
||||
class CatItemHandlder extends \pjdietz\WellRESTed\Handler
|
||||
|
|
@ -48,7 +48,7 @@ class CatItemHandlder extends \pjdietz\WellRESTed\Handler
|
|||
|
||||
Your template may have multiple variables. Be sure to give each a unique name.
|
||||
|
||||
With this `TemplateRoute`...
|
||||
With this [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php)...
|
||||
|
||||
```php
|
||||
$route = new TemplateRoute("/cats/{catId}/{dogId}", "CatItemHandler");
|
||||
|
|
@ -59,13 +59,13 @@ $route = new TemplateRoute("/cats/{catId}/{dogId}", "CatItemHandler");
|
|||
|
||||
### Default Variable Pattern
|
||||
|
||||
By default, the `TemplateRoute` will accept for a variable any value consisting of numbers, letters, underscores, and hyphens. You can change this behavior by passing a pattern to use as the third parameter of the constructor. Here we'll restrict the template to match only numeric values.
|
||||
By default, the [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) will accept for a variable any value consisting of numbers, letters, underscores, and hyphens. You can change this behavior by passing a pattern to use as the third parameter of the constructor. Here we'll restrict the template to match only numeric values.
|
||||
|
||||
```php
|
||||
$route = new TemplateRoute("/cats/{id}", "CatItemHandler", TemplateRoute::RE_NUM);
|
||||
```
|
||||
|
||||
The `TemplateRoute` includes constants for some common situations. The value of each constant is a partial regular expression. You can use one of the constants, or provide your own partial regular expression.
|
||||
The [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) includes constants for some common situations. The value of each constant is a partial regular expression. You can use one of the constants, or provide your own partial regular expression.
|
||||
|
||||
### Pattern Constants
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ The `TemplateRoute` includes constants for some common situations. The value of
|
|||
|
||||
### Variable Patterns Array
|
||||
|
||||
You can also set a different pattern for each variable. To do this, pass an array to the `TemplateRoute` constructor as the fourth paramter. The array must have variable names as keys and patterns as values.
|
||||
You can also set a different pattern for each variable. To do this, pass an array to the [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) constructor as the fourth parameter. The array must have variable names as keys and patterns as values.
|
||||
|
||||
```php
|
||||
$patterns = array(
|
||||
|
|
@ -96,13 +96,13 @@ Here, `{id}` will need to match digits and `{name}` must be all letters. Since `
|
|||
|
||||
### RegexRoute
|
||||
|
||||
If `TemplateRoute` doesn't give you enough control, you can make a route that matches a regular expression.
|
||||
If [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php) doesn't give you enough control, you can make a route that matches a regular expression using a [`RegexRoute`](../src/pjdietz/WellRESTed/Routes/RegexRoute.php).
|
||||
|
||||
```php
|
||||
$route = new RegexRoute("~/cat/[0-9]+~", "CatHandler")
|
||||
```
|
||||
|
||||
This will match `/cat/102` or `/cat/999` or what have you. To make this more useful, we can add a capture group. The captures are made available to the `Handler` as the `$args` member, as with the URI template variables for the `TemplateRoute`
|
||||
This will match `/cat/102` or `/cat/999` or what have you. To make this more useful, we can add a capture group. The captures are made available to the handler as the `$args` member, as with the URI template variables for the [`TemplateRoute`](../src/pjdietz/WellRESTed/Routes/TemplateRoute.php)
|
||||
|
||||
Note that the entire matched path will always be the `0` item, and captured groups will begin at `1`.
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use pjdietz\WellRESTed\Interfaces\RequestInterface;
|
|||
*/
|
||||
abstract class Handler implements HandlerInterface
|
||||
{
|
||||
/** @var array Map of variables to suppliement the request, usually path variables. */
|
||||
/** @var array Map of variables to supplement the request, usually path variables. */
|
||||
protected $args;
|
||||
/** @var RequestInterface The HTTP request to respond to. */
|
||||
protected $request;
|
||||
|
|
|
|||
Loading…
Reference in New Issue