Coder Social home page Coder Social logo

wellrested's Introduction

WellRESTed

WellRESTed provides classes to help you create RESTful APIs and work with HTTP requests and responses.

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": "1.*"
    }
}

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 autoload.php file generated by Composer. vendor/autoload.php

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 URI pattern to a class name. The class name represents the Handler class which the router will dispatch at the time it receives a request for the given URI. The handlers are never loaded unless they are needed.

Here's an example of a Router that will handle two URIs:

// Build the router.
$myRouter = new Router();
$myRouter->addRoute(Route::newFromUriTemplate('/things/', 'ThingCollectionHandler'));
$myRouter->addRoute(Route::newFromUriTemplate('/things/{id}', 'ThingItemHandler'));

// Determine and output the response.
$response = $myRouter->getResponse();
$response->respond();

When you create your Handler subclass, you will provide a method for each HTTP verb you would like the endpoint to support. For example, if /things/ 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.

Here's a simple Handler that matches the first endpoint, /things/.

class ThingCollectionHandler extends \pjdietz\WellRESTed\Handler
{
    protected function get()
    {
        // Read some things from the database, cache, whatever.
        // ...read this into the variable $data

        // Set the values for the instance's response member. This is what the
        // Router will eventually use to output a response to the client.
        $this->response->setStatusCode(200);
        $this->response->setHeader('Content-Type', 'application/json');
        $this->response->setBody(json_encode($data));
    }

    protected function post()
    {
        // Read from the instance's request member and store a new Thing.
        // ...

        // Build a response to send to the client.
        $this->response->setStatusCode(201);
        $this->response->setBody('You added a thing!');
    }
}

This Handler works with the second endpoint, /things/{id}. The pattern for this endpoint has the variable {id} in it. The Handler can access path variables through its args member, which is an associative array of variables from the URI.

class ThingItemHandler extends \pjdietz\WellRESTed\Handler
{
    protected function get()
    {
        // Lookup a Thing ($thing) based on $this->args['id']
        // ...

        if ($thing) {
            // The Thing exists! Let's output a representation.
            $this->response->setStatusCode(200);
            $this->response->setHeader('Content-Type', 'application/json');
            $this->response->setBody(json_encode($thing));
        } else {
            // The ID did not match anything.
            $this->response->setStatusCode(404);
            $this->response->setHeader('Content-Type', 'text/plain');
            $this->response->setBody('No thing with id ' . $this->args['id']);
        }
    }
}

As of version 1.3.0, you can have a Router dispatch other Routers. This is useful for breaking your endpoints into smaller route tables. Here's an example:

/**
 * Top-level router that dispatches all traffic to /cat/... to CatRouter and all
 * traffic to /dog/... to DogRouter.
 */
class TopRouter extends \pjdietz\WellRESTed\Router
{
    public function __construct()
    {
        $this->addRoute(new Route('/^\/cat\//', 'CatRouter'));
        $this->addRoute(new Route('/^\/dog\//', 'DogRouter'));
    }
}

Requests and Responses

You've already seen a Response in use in the examples above. You can also use Responses outside of Handlers. 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;

The Request class goes hand-in-hand with the Response class. Again, this is used in the Handler class to read the information from the request being handled. From outside the context of a Handler, you can also use the Request class to read info for the request sent to the server.

// Call the static method getRequest() to get a reference to the Request
// singleton that represents 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.
    // ...
}

The Request class can also make a request to another server and provide the response as a Response object. (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));

// Make the request.
$resp = $rqst->request();

// Read the response.
if ($resp->getStatusCode() === 201) {
    // The new resource was created.
    $createdResource = json_decode($resp->getBody());
}

Routing from a Handler

One more fun thing you can do with WellRESTed is use your API from inside your API. WellRESTed makes this easy because each dispatched Handler or Router keeps a reference to the top-level Router.

Suppose you have an endpoint that needs to look up information using another endpoint. Now that you've seen that you can create and work with your own requests and responses, we'll look at how to use them in the context of a handler.

class NestedHandler extends \pjdietz\WellRESTed\Handler
{
    protected function get()
    {
        // To build this response, we need some of the info from the /things/ representation.
        // Create a Request instance to query this API.
        $rqst = new Request();
        $rqst->setPath('/things/');

        // Use this handler's reference to the router that dispatched it.
        $router = $this->getRouter();

        // Pass the request for /things/ to the router to get a response.
        $resp = $router->getResponse($rqst);

        // Read the status code, headers, body, etc. on the response.
        // ...
    }
}

More Examples

For more examples, see the project pjdietz/wellrested-samples.

Copyright and License

Copyright © 2013 by PJ Dietz Licensed under the MIT license

wellrested's People

Contributors

pjdietz avatar nthdesign avatar

Watchers

JT5D avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.