Skip to content
This repository has been archived by the owner on May 18, 2021. It is now read-only.

Latest commit

 

History

History
312 lines (217 loc) · 8.49 KB

REST.md

File metadata and controls

312 lines (217 loc) · 8.49 KB

REST Service

REST service (will be named "service" in the text) provides the possibility to operate on resources from any kind of application. To use it one must authenticate first. Service supports two types of authentication: basic and token.

When user is authenticated, he is able to perform CRUD operations on resources by using the following methods: GET, POST, PUT, PATCH, DELETE.

Also, the service supports other HTTP methods: OPTIONS, TRACE, HEAD.

The service understands the several input and output data formats. Input: standard HTTP url-encoded, XML and JSON bodies. Output: XML and JSON.

Authorization

Basic

To use basic authorization just use base64-encoded username:password string in Authorization header like this:

Authorization: Basic dGVzdF91c2VyOjEyMzQ1Ng==

End of story.

Token

Token authorization is a little more complicated than basic. First, you have to make a usual Basic-Authorization request, and in response you will receive the token. Then just send this token in every request in Authorization header or as a request parameter _token. The former is better, because it will not be cached (in GET requests).

Step 1: Authorization: Basic dGVzdF91c2VyOjEyMzQ1Ng== On every basic authorization request without _token parameter new token will be generated. You can have only one token, so if you use it in several places, do not call basic authorization requests, do it only once, and then use received token.

Step 2 (and consequent): Authorization: Token 1af538baa9045a84c0e889f672baf83ff24 or http://hackazon.dev/api/?_token=1af538baa9045a84c0e889f672baf83ff24&other_params...

Content Type

Request

Content type in request can be standard HTTP url-encoded, XML and JSON bodies. Important: Content-Type header in request and actual content type of the request body must be equal. Otherwise parsing error occur.

Response

The Service reads Accept header in request to determine output format. But this value can be overridden by using url parameter _format (accepts xml and json).

Accept header supports application/json, application\xml and application/x-www-form-urlencoded formats. There may be more complicated Accept strings, but they are canonicalised to these forms.

If no correct Accept or _format values provided, json is used.

URL format

URLs have the following format:


    /api(/resource(/id(/property)))

Each consequent parameter is optional, the mandatory is only /api part, as an entry point to the Service

property value is used to access certain sub-collections (prepared beforehand):


    GET http://hackazon.dev/api/order/1/addresses HTTP/1.1

Methods

Some of methods are forbidden by default in many http servers, o you must enable them in order to fully use the service.

In Apache you should make the following changes:


    <Directory "....">
        # ....
        <LimitExcept GET POST HEAD PUT OPTIONS DELETE PATCH>
            Order deny,allow
            Deny from all
        </LimitExcept>
        # ....
    </Directory>

And in Nginx the next ones (if this constraint is used in your config):


    if ($request_method !~* ^(GET|HEAD|POST|DELETE|OPTIONS|PUT|PATCH)$ ){return 403;}

TRACE

Research has shown that in PHP (and even in other languages) we don't have a control over TRACE method. Apache uses its own logic and sends the request content back. And Nginx just sends 405 Method Not Allowed status.

OPTIONS

This method just allows to fetch allowed methods for a given resource in Allow header.

GET

Incorrect response just raises an error message (with corresponding status):

Request:

    http://hackazon.dev/api/incorrect_path/10

Response:

    {"message":"Not Found","code":404}

Fetches the collection or a resource(sub-resources):

Request:

    http://hackazon.dev/api/order?_format=xml

Response:

    <?xml version="1.0"?>
    <order_address>
        <item0>
            <id>1</id>
            <full_name>asc</full_name>
            <address_line_1>asdasd</address_line_1>
            <address_line_2>asdasdasd</address_line_2>
            <city>asdasd</city>
            <region>asdasdasd</region>
            <zip>215325235</zip>
            <country_id>RU</country_id>
            <phone>1016186</phone>
            <customer_id>1</customer_id>
            <address_type>shipping</address_type>
            <order_id>1</order_id>
        </item0>
        <item1>
            ....
            ....
        </item1>
        ....
        ....
    </order_address>

Collections are fetched in controller action get_collection. Additional information is provided in response header Link (as on GitHub):


    Link: </api/category?page=1>; rel="current",</api/category?page=1>; rel="first",</api/category?page=4>; rel="last",</api/category?page=2>; rel="next"

Fetch single item:

Request:


    http://hackazon.dev/api/order/1

Response:

    {
        "id": "1",
        "created_at": "2014-08-22 09:57:52",
        "updated_at": "2014-08-22 12:57:52",
        "customer_firstname": "test_user",
        "customer_lastname": null,
        "....": "......",
        "....": "......",
        "orderAddress": [
            {
                 "id": "1",
                 "full_name": "asc",
                 "address_line_1": "asdasd",
                 "address_line_2": "asdasdasd",
                 "city": "asdasd",
                 "region": "asdasdasd",
                 "....": "......"
            },
            {
                 "id": "2",
                 "full_name": "asc",
                 "address_line_1": "asdasd",
                 "....": "......"
            }
        ]
    }

Fetch (predefined) collection of order addresses.


    http://hackazon.dev/api/order/1/addresses

All operations with addresses are possible if you are its owner (It's checked in Order controller).

HEAD request

Does the same as GET, but doesn't return the body of the response. So you can for example check whether you have an access to the resource, but without additional payload.

POST, PUT and PATCH methods

These methods are similar in the way they are processed. The difference is in their semantics. POST request must contain all fields of object being created. If some fields are missing, or there are excess fields, the exception will be thrown. If everything is OK, new resource is created and returned in the body of the response. POST method adds new object to the collection:


    POST http://hackazon.dev/api/order HTTP/1.1
    ... headers...
    Content-Type: application/xml
    Authorization: Token ...............

    <?xml version="1.0"?>
    <order>
        <created_at>2014-08-20 15:00:57</created_at>
        <updated_at>2014-08-20 18:00:57</updated_at>
        <customer_firstname>test_user</customer_firstname>
        <customer_lastname></customer_lastname>
        <customer_email>test_user@example.com</customer_email>
        <status>complete</status>
        <comment></comment>
        <customer_id>1</customer_id>
        <payment_method>wire transfer</payment_method>
        <shipping_method>mail</shipping_method>
    </order>

PUT method behaves similar to POST, but it updates existing object. It also must have ALL fields of the object.


    PUT http://hackazon.dev/api/order/1 HTTP/1.1

PATCH method also updates a resource like PUT, but its body do not have to hold all fields. It can send just one (or another needed count) field.


    PATCH http://hackazon.dev/api/order/1 HTTP/1.1

All these methods return modified or created resource in the response.

DELETE method

This method is very simple. It just deletes the resource and returns no content.


    DELETE http://hackazon.dev/api/order/1 HTTP/1.1

Config

    <?php
    return array(
       'excluded_models' => [     // Exclude models, that we do not want to expose
           'BaseModel',
           'Model',
           'OrderAddress'         // Or ones, which names we want to hide by using special REST Controller (e.g. OrderAddressesCollection)
       ],
       'auth' => [
           'type' => 'token',  // Type of authorization. default == 'basic'
       ]
    );