Skip to content

Instantly share code, notes, and snippets.

@syzspectroom
Last active April 3, 2018 13:32
Show Gist options
  • Save syzspectroom/42739715c5694be4b1f145e5dafc93cf to your computer and use it in GitHub Desktop.
Save syzspectroom/42739715c5694be4b1f145e5dafc93cf to your computer and use it in GitHub Desktop.
docs.md

RESTful URLs

General guidelines for RESTful URLs

  • A URL identifies a resource.
  • URLs should include nouns, not verbs.
  • Use plural nouns only for consistency (no singular nouns).
  • Use HTTP verbs (GET, POST, PUT, DELETE) to operate on the collections and elements.
  • You shouldn’t need to go deeper than resource/identifier/resource.
  • Put the version number at the base of your URL, for example http://example.com/v1/path/to/resource.
  • URL v. header:
    • If it changes the logic you write to handle the response, put it in the URL.
    • If it doesn’t change the logic for each response, like OAuth info, put it in the header.
  • Specify optional fields in a comma separated list.
  • Formats should be in the form of api/v2/resource/{id}.json

Good URL examples

Bad URL examples

HTTP Verbs

HTTP verbs, or methods, should be used in compliance with their definitions under the HTTP/1.1 standard. The action taken on the representation will be contextual to the media type being worked on and its current state. Here's an example of how HTTP verbs map to create, read, update, delete operations in a particular context:

HTTP METHOD POST GET PUT DELETE
CRUD OP CREATE READ UPDATE DELETE
/dogs Create new dogs List dogs Bulk update Delete all dogs
/dogs/1234 Error Show Bo If exists, update Bo; If not, error Delete Bo

(Example from Web API Design, by Brian Mulloy, Apigee.)

Responses

  • No values in keys
  • No internal-specific names (e.g. "node" and "taxonomy term")
  • Metadata should only contain direct properties of the response set, not properties of the members of the response set

Good examples

No values in keys:

"tags": [
  {"id": "125", "name": "Environment"},
  {"id": "834", "name": "Water Quality"}
],

Bad examples

Values in keys:

"tags": [
  {"125": "Environment"},
  {"834": "Water Quality"}
],

Error handling

Error responses should include a common HTTP status code, message for the end-user (when appropriate), internal error code (corresponding to some specific internally determined ID). For example:

{
  "status" : 400,
  "message" : "This is a message that can be passed along to end-users, if needed.",
  "code" : "444444"
}

Use three simple, common response codes indicating (1) success, (2) failure due to client-side problem, (3) failure due to server-side problem:

  • 200 All other successful
  • 201 POST
  • 204 DELETE
  • 400 Bad request
  • 401 Unauthorized/invalid token
  • 402 Payment required
  • 403 Forbidden
  • 404 Not found
  • 423 Locked
  • 498 Token expired

Versions

  • Never release an API without a version number.
  • Versions should be integers, not decimal numbers, prefixed with ‘v’. For example:
    • Good: v1, v2, v3
    • Bad: v-1.1, v1.2, 1.3
  • Maintain APIs at least one version back.

Record limits

Information about record limits and total available count should also be included in the response. Example:

{
    "total": {
        "count": 227,
        "offset": 25,
        "limit": 25
    },
    "results": [],
    "links": {}
}

Links

  • Where specified, a links member can be used to represent links. The value of each links member MUST be an object (a "links object").

  • Each member of a links object is a "link". A link MUST be represented as either:

    • a string containing the link’s URL.
    • an object ("link object") which can contain the following members:
    • href: a string containing the link’s URL.
    • meta: a meta object containing non-standard meta-information about the link.

Example:

{
  "links": {
    "first": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=0",
    "prev": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=25",
    "self": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=50",
    "next": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=75",
    "last": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=150"      
  }
}

API Resources

GET /magazines

Example: http://example.com/api/v1/magazines.json

Response body:

{
    "total": {
        "count": 227,
        "offset": 50,
        "limit": 25
    },
    "results": [
        {
            "id": "1234",
            "type": "magazine",
            "title": "Public Water Systems",
            "tags": [
                {"id": "125", "name": "Environment"},
                {"id": "834", "name": "Water Quality"}
            ],
            "created": "1231621302"
        },
        {
            "id": 2351,
            "type": "magazine",
            "title": "Public Schools",
            "tags": [
                {"id": "125", "name": "Elementary"},
                {"id": "834", "name": "Charter Schools"}
            ],
            "created": "126251302"
        },
        {
            "id": 2351,
            "type": "magazine",
            "title": "Public Schools",
            "tags": [
                {"id": "125", "name": "Pre-school"},
            ],
            "created": "126251302"
        }
    ],
    "links": {
        "first": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=0",
        "prev": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=25",
        "self": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=50",
        "next": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=75",
        "last": "http://example.com/api/v1/magazines?page[limit]=25&page[offset]=150"      
    }
}

GET /magazines/[id]

Example: http://example.com/api/v1/magazines/[id].json

Response body:

{
    "id": "1234",
    "type": "magazine",
    "title": "Public Water Systems",
    "tags": [
        {"id": "125", "name": "Environment"},
        {"id": "834", "name": "Water Quality"}
    ],
    "created": "1231621302"
}

POST /magazines/[id]/articles

Example: Create – POST http://example.com/api/v1/magazines/[id]/articles

Request body:

{
    "title": "Raising Revenue",
    "author_first_name": "Jane",
    "author_last_name": "Smith",
    "author_email": "[email protected]",
    "year": "2012",
    "month": "August",
    "day": "18",
    "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ante ut augue scelerisque ornare. Aliquam tempus rhoncus quam vel luctus. Sed scelerisque fermentum fringilla. Suspendisse tincidunt nisl a metus feugiat vitae vestibulum enim vulputate. Quisque vehicula dictum elit, vitae cursus libero auctor sed. Vestibulum fermentum elementum nunc. Proin aliquam erat in turpis vehicula sit amet tristique lorem blandit. Nam augue est, bibendum et ultrices non, interdum in est. Quisque gravida orci lobortis... "
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment