Saturday, January 16, 2016

HTTP API Design Guide



https://geemus.gitbooks.io/http-api-design/content/
HTTP API Design
Separate Concerns
Keep things simple while designing by separating the concerns between the different parts of the request and response cycle. Keeping simple rules here allows for greater focus on larger and harder problems.
Requests and responses will be made to address a particular resource or collection. Use the path to indicate identity, the body to transfer the contents and headers to communicate metadata. Query params may be used as a means to pass header information also in edge cases, but headers are preferred as they are more flexible and can convey more diverse information.

Require Secure Connections
Redirects are discouraged since they allow sloppy/bad client behaviour without providing any clear gain. Clients that rely on redirects double up on server traffic and render TLS useless since sensitive data will already have been exposed during the first call.+

Require Versioning in the Accepts Header
Versioning and the transition between versions can be one of the more challenging aspects of designing and operating an API. As such, it is best to start with some mechanisms in place to mitigate this from the start.
To prevent surprise, breaking changes to users, it is best to require a version be specified with all requests. Default versions should be avoided as they are very difficult, at best, to change in the future.
It is best to provide version specification in the headers, with other metadata, using the Accept header with a custom content type, e.g.:
Accept: application/vnd.heroku+json; version=3

Support ETags for Caching
Include an ETag header in all responses, identifying the specific version of the returned resource. This allows users to cache resources and use requests with this value in the If-None-Match header to determine if the cache should be updated.+

Provide Request-Ids for Introspection
Include a Request-Id header in each API response, populated with a UUID value. By logging these values on the client, server and any backing services, it provides a mechanism to trace, diagnose and debug requests.

Divide Large Responses Across Requests with Ranges
Large responses should be broken across multiple requests using Range headers to specify when more data is available and how to retrieve it. See the Heroku Platform API discussion of Ranges for the details of request and response headers, status codes, limits, ordering, and iteration.
Resource names

Use the plural version of a resource name unless the resource in question is a singleton within the system (for example, in most systems a given user would only ever have one account). This keeps it consistent in the way you refer to particular resources.+

Actions
Prefer endpoint layouts that don’t need any special actions for individual resources. In cases where special actions are needed, place them under a standard actions prefix, to clearly delineate them:
/resources/:resource/actions/:action
e.g.
/runs/{run_id}/actions/stop

Use consistent path formats
Downcase paths and attributes
Use downcased and dash-separated path names, for alignment with hostnames, e.g:
service-api.com/users
service-api.com/app-setups
Downcase attributes as well, but use underscore separators so that attribute names can be typed without quotes in JavaScript, e.g.:
service_class: "first"

Support non-id dereferencing for convenience
In some cases it may be inconvenient for end-users to provide IDs to identify a resource. For example, a user may think in terms of a Heroku app name, but that app may be identified by a UUID. In these cases you may want to accept both an id or name, e.g.:
$ curl https://service.com/apps/{app_id_or_name}
$ curl https://service.com/apps/97addcf0-c182
$ curl https://service.com/apps/www-prod
Do not accept only names to the exclusion of IDs.+

Minimize path nesting
In data models with nested parent/child resource relationships, paths may become deeply nested, e.g.:
/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}
Limit nesting depth by preferring to locate resources at the root path. Use nesting to indicate scoped collections. 
For example, for the case above where a dyno belongs to an app belongs to an org:
/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}

Return appropriate status codes
  • 206: Request succeeded on GET, but only a partial response returned: see above on ranges
Provide full resources where available
Provide the full resource representation (i.e. the object with all attributes) whenever possible in the response. Always provide the full resource on 200 and 201 responses, including PUT/PATCH and DELETE requests, e.g.:
$ curl -X DELETE \
  https://service.com/apps/1f9b/domains/0fd4

HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
...
{
  "created_at": "2012-01-01T12:00:00Z",
  "hostname": "subdomain.example.com",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "updated_at": "2012-01-01T12:00:00Z"
}
Provide resource (UU)IDs
Give each resource an id attribute by default. Use UUIDs unless you have a very good reason not to. Don’t use IDs that won’t be globally unique across instances of the service or other resources in the service, especially auto-incrementing IDs.+

Provide standard timestamps
Provide created_at and updated_at timestamps for resources by default, e.g:
{
  // ...
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T13:00:00Z",
  // ...
}
These timestamps may not make sense for some resources, in which case they can be omitted.+

Use UTC times formatted in ISO8601
Accept and return times in UTC only. 
Render times in ISO8601 format, e.g.:
"finished_at": "2012-01-01T12:00:00Z"

Nest foreign key relations
Serialize foreign key references with a nested object, e.g.:
{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0..."
  },
  // ...
}
Instead of e.g.:
{
  "name": "service-production",
  "owner_id": "5d8201b0...",
  // ...
}
This approach makes it possible to inline more information about the related resource without having to change the structure of the response or introduce more top-level response fields, e.g.:
{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0...",
    "name": "Alice",
    "email": "alice@heroku.com"
  },
  // ...
}

Generate structured errors
Generate consistent, structured response bodies on errors. Include a machine-readable error id, a human-readable error message, and optionally a url pointing the client to further information about the error and how to resolve it, e.g.:
HTTP/1.1 429 Too Many Requests
{
  "id":      "rate_limit",
  "message": "Account reached its API rate limit.",
  "url":     "https://docs.service.com/rate-limits"
}
Document your error format and the possible error ids that clients may encounter.+

Show rate limit status
Rate limit requests from clients to protect the health of the service and maintain high service quality for other clients. You can use a token bucket algorithm to quantify request limits.

Return the remaining number of request tokens with each request in the RateLimit-Remaining response header.

Keep JSON minified in all responses
You may consider optionally providing a way for clients to retrieve more verbose response, either via a query parameter (e.g. ?pretty=true) or via an Accept header param (e.g. Accept: application/vnd.heroku+json; version=3; indent=4;).+

Provide machine-readable JSON schema
Provide a machine-readable schema to exactly specify your API. Use prmd to manage your schema, and ensure it validates with prmd verify.

Provide human-readable docs

Provide human-readable documentation that client developers can use to understand your API.
If you create a schema with prmd as described above, you can easily generate Markdown docs for all endpoints with prmd doc.
In addition to endpoint details, provide an API overview with information about:
Authentication, including acquiring and using authentication tokens.
API stability and versioning, including how to select the desired API version.
Common request and response headers.
Error serialization format.
Examples of using the API with clients in different languages.

Provide executable examples
Provide executable examples that users can type directly into their terminals to see working API calls. To the greatest extent possible, these examples should be usable verbatim, to minimize the amount of work a user needs to do to try the API, e.g.:
$ export TOKEN=... # acquire from dashboard
$ curl -is https://$TOKEN@service.com/users
If you use prmd to generate Markdown docs, you will get examples for each endpoint for free.

Describe stability
Describe the stability of your API or its various endpoints according to its maturity and stability, e.g. with prototype/development/production flags.
See the Heroku API compatibility policy for a possible stability and change management approach.
Once your API is declared production-ready and stable, do not make backwards incompatible changes within that API version. If you need to make backwards-incompatible changes, create a new API with an incremented version number.

https://github.com/ZhangBohan/http-api-design-ZH_CN

http://venkateshcm.com/2014/04/Guidelines-Restful-Web-Services/
Uniform Resource handling
  • Allow discoverability of new resources. Similar to adding new link to existing page (resource) to allow access to new page (new resource).
  • Take advantage of intermediary components between client and server. ( Caches, Proxies, Firewalls etc)
  • Follow consistent approach to view/modify/create operations on any resource.
  • Make conscious trade-offs between cache-ability, discoverability, performance and convenience
Safe Methods
  • Client requests are readonly.
  • Client can make duplicate requests without causing unintended side-effects. Similar to loading the page again in browser.
  • Does not mean server will respond with same response to the new requests. Similar to reloading(F5) a page in browser may get different/modified response (new data) on dynamic web page.
Idempotent Methods
  • Client can replay the request if client is not certain server has processed the request due network failure or other errors.
Follow HTTP standards
  • Use Request Methods as defined by HTTP
    • Get, Head, Options methods
      • should be safe (readonly) i.e. should not cause side effects on resource representation.
    • Get, Head, Options, Put, Delete
      • should be idempotent i.e. replay of request (due to network failure or uncertainty) should not cause issues
    • Post
      • Can cause side-effects and does not guarantee safety or idempotent
    • Use Request MIME Types to encode representation
    • Use HTTP status code for responses status
    • Keep Restful Services Stateless — maintain state in client.
  • URL of the resource
    • Url of the resource represents the hierarchy.
    • For example : www.school.com/class/<1>/subject//
      • In the above example school has classes
      • classes has subjects
Frequently Asked Questions :
  • Is PUT Request for Creation and POST for updating ?
    • Both PUT and POST can be used for Creating new resource or Updating an existing resource.
  • Deference between PUT and POST ?
    • PUT is idempotent and client can be replay the request if network failure or system error without causing issues on server. Use PUT to completely replace existing resource representation or create new resource representation.
    • POST is not idempotent and general purpose method without restrictions and corresponding benefits. Use POST when other verbs don’t fit.
  • When to use POST ?
    • POST is general purpose method which can be used when other HTTP verbs don’t fit well.

[Using] POST only becomes an issue when it is used in a situation for which some other method is ideally suited:
e.g., retrieval of information that should be a representation of some resource (GET), complete replacement of 
a representation (PUT), or any of the other standardized methods that tell intermediaries something more valuable
than “this may change something.” The other methods are more valuable to intermediaries because they say something
about how failures can be automatically handled and how intermediate caches can optimize their behavior. POST does
not have those characteristics, but that doesn’t mean we can live without it. POST serves many useful purposes in
HTTP, including the general purpose of “this action isn’t worth standardizing.”
                    --- Roy T. Fielding (http://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post)
  • How does HTTP Safety and Idempotent work during concurrent requests?
    • Safety and Idempotent are defined in non concurrent condition.
      • Good analogy to understand is load a web page in browser and on reloading the page browser can get new version of the page. Server could also deny GET request if agreed number of requests has been reached. User should not worry about making duplicate requests.
    • For example,
      • A replay GET request can return new representation if resource is modified by another request.
      • A replay GET request can return modified representation like updated hit/access count.
      • A failed GET request after allotted number of calls are made to a given resource, does not violate Safety rule.
      • Get request with authentication token can fail on second request. Safety does not grantee same response every time.
  • Can a single GET request return two or more different resources? Can a resource contain other resources?
    • Yes, they can but it comes at the cost of cache-ability.

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts