- Guidelines
- RESTful URLs
- HTTP Verbs
- Responses
- HTTP Status Codes
- Error handling
- Versions
- Record limits
- Request & Response Examples
- Rate Limiting
- Idempotent
- Modeling Actions
- Security
- Documentation
- Amazing Rest Apis
This document provides guidelines and examples for Kudobuzz APIs, encouraging consistency, maintainability, and best practices across services. Our APIs aim to balance a truly RESTful API interface with a positive developer experience (DX).
This document borrows heavily from:
- Designing HTTP Interfaces and RESTful Web Services
- API Facade Pattern, by Brian Mulloy, Apigee
- Web API Design - Missing Link, by Apigee
- Web API Design, by Apigee
- Fielding's Dissertation on REST
- Resource Modeling
- Best Practices for Designing a Pragmatic RESTful API by Vinay
- White House Api Standards
- 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 https://api.kudobuzz.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}
- Design resource representations. Don’t simply represent database tables.
- Support field projections on resources. Allow clients to reduce the number of fields that come back in the response.
- For non-resource requests, url should identify the action being taken. E.g. if the endpoint converts 100 euros to chinese yen, is should look like
/convert?from=EURO&to=YEN&amount=100
- Make it clear in your API documentation that the "non-resource" scenarios are different. You can do this by simply separating out a section of your documentation that makes it clear that you use verbs in cases like this.
- List of magazines:
- Filtering and Sorting:
- A single magazine in JSON format:
- All articles in (or belonging to) this magazine:
- Specify optional fields in a comma separated list:
- Add bulk magazines
- Add a new article to a particular magazine:
- Search for articles
- Download brochure
- Non-plural noun:
- Verb in URL:
- Filter outside of query string
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.)
- No values in keys
No values in keys:
"tags": [
{"id": "125", "name": "Environment"},
{"id": "834", "name": "Water Quality"}
],
Values in keys:
"tags": [
{"125": "Environment"},
{"834": "Water Quality"}
],
There are currently over 70 status codes, it is difficult for developers to memorize all of these codes. Use only a small subset of common status codes.
Status Code | Description |
---|---|
200 OK | The request was successfully processed |
201 Created | The request has been fulfilled and the new resource has been created |
400 Bad Request | The request was not understood by server due bad syntax, request contains invalid and missing request details. |
404 Not Found | The resource was not found |
401 UnAuthorised | The request is missing the necessary authentication details |
403 Forbidden | The request credentials does not have the permission to perform that action on the resource |
422 UnProcessable Entity | The request body is well formed but contains semantical errors. The error response body will contain more details |
429 Too Many Requests | The request was not accepted because the application has exceeded the rate limit. |
Error responses can include message for the developer,an optional internal error code (corresponding to some specific internally determined ID), details for validation errors. For example:
{
"error": {
"message" : "Verbose, plain language description of the problem. Provide developers
suggestions about how to solve their problems here",required
"code" : "444444", // this is not the same statusCodes, optional
"details": [{param, messeage, value}] // Validation Error details, optional
}
}
- Never release an Public API Gateway 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.
- If no limit is specified, return results with a default limit.
- To get records 51 through 75 do this:
- https://api.kudobuzz.com/v1/magazines?limit=25&cursor=383884834
- cursor=383884834 means, ‘everything greater than 383884834’
- limit=25 means, ‘return a maximum of 25 records’
Information about record limits and total available count should also be included in the response. Example:
{
"metadata": {
"count": 227
},
"data": []
}
Example: https://example.gov/api/v1/magazines
Response body:
{
"metadata": {
"count": 123
},
"data": [
{
"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"
}
]
}
Example 1: https://example.gov/api/v1/magazines?type=magazine
Returns response with an array with multiple objects
Response body:
{
"metadata": {
"count": 123
},
"data": [
{
"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"
}
]
}
Example 2: https://example.gov/api/v1/magazines?special_code=code-1234
Returns response with a single object
{
"data": {
"id": "1234",
"type": "magazine",
"title": "Public Water Systems",
"tags": [
{"id": "125", "name": "Environment"},
{"id": "834", "name": "Water Quality"}
],
"created_at": "1231621302",
"updated_at": "12321621302"
}
}
Response body
Example: http:/api.kudouzz.com/v1/api/magazines/[id]
Response body:
{
"data": {
"id": "1234",
"type": "magazine",
"title": "Public Water Systems",
"tags": [
{"id": "125", "name": "Environment"},
{"id": "834", "name": "Water Quality"}
],
"created_at": "1231621302",
"updated_at": "12321621302"
}
}
Example: Create – POST https://api.kudobuzz.com/v1/magazines/bulk
Request body:
[
{
"title": "Water Quality",
"year": "2012",
"month": "August",
"description": "Your one-stop information source on how to preserve water"
},
{
"title": "Global warming"
"year": "2020",
"month": "July",
"description": "Tips for slowing down the inevitable"
}
]
Response body:
{
"data": [
{
"id": "1235",
"title": "Water Quality",
"description": "Your one-stop information source on how to preserve water",
"year": "2012",
"month": "August",
"created_at": "1231621302",
"updated_at": "12321621302"
},
{
"id": "1236",
"title": "Global warming"
"description": "Tips for slowing down the inevitable",
"year": "2020",
"month": "July",
"created_at": "1231621302",
"updated_at": "12321621302"
}
]
}
Example: Create – POST https://api.kudobuzz.com/v1/magazines/[id]/articles
Request body:
{
"data": {
"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... "
}
}
Ensure that your apis' are protected against sudden increase in request. Use the following headers to notify consumers if they exceeded the number request in a specif interval.
X-Rate-Limit-Limit
- the number of request allowed in a given interval
X-Rate-Limit-Remaining
- the number of request remaining
X-Rate-Limit-Reset
- the next time for reset
Ensure that your GET, PUT, and DELETE operations are all idempotent. There should be no adverse side affects from operations.
Use OAuth2 to secure your API.
- Use a Bearer token for authentication.
- Require HTTPS / TLS / SSL to access your APIs. OAuth2 Bearer tokens demand it. Unencrypted communication over HTTP allows for simple eavesdroppping and impersonation.
You write APIs so others can use them, benefit from them. Providing an API documentation for your REST APIs are crucial. Use Api Blueprint