# API Design and Use (with REST and JSON and JavaScript) # -------------------------------------------------- (2018) JSON (JavaScript Object Notation), like XML, is used as a data interchange format. It used the syntax of JavaScript object, making it easy to consume by web pages, for example. REST (Representational state transfer) is a manner of exchanging data. REST is stateless. REST services most run over HTTP (and HTTP is itself RESTful). With a RESTful web resource, requests made to a resource's URI return JSON (or XML or HTML or whatever). RESTful operations include the HTTP verbs GET, POST, PUT, DELETE and so on. API Design -------------------------------------------------- - Version the API, like https://example.com/api/v1/foo. - Anticipate the need for format flexibility. We might not always want to return JSON. E.g., https://example.com/api/v1/json/foo? (Not sure about this one.) - Resource names should be nouns, not verbs. (The HTTP method is the verb!) - The choice of nouns should make sense from the perspective of the API consumer/user. - Use plural in URL parts (e.g., "customers", "widgets", etc.). - Avoid collection names (i.e., use "customers" instead of "customer_list"). - Keep URL's as short as possible, while still making sense. - Make URL's developer-friendly and explorable via a browser address bar. - Use HTTP response codes to indicate status (200 OK, 404 not found, etc.). How do we put our request into the URL? What's part of the path, and what's added as query parameters? Generally, path parameters identify a specific resource or resources, while query parameters sort or filter those resources. Idempotence -------------------------------------------------- (Not strictly API-related, but since we're touching on HTTP methods, here's a refresher.) From the perspective of a RESTful service, an idempotent operation is one that clients can perform repeatedly with one result. That is, if a client repeatedly performs the same operation with the same parameters, idempotency guarantees that those multiple operation have same effect as a single operation. Since the GET, HEAD, OPTIONS and TRACE methods only read, they're naturally idempotent. DELETE is idempotent (but beware the first DELETE returning a 200 and subsequent DELETE's on the same record return 404). PUT is idempotent. (PUT generally updates an existing record.) POST is necessarily _not_ idempotent. (POST generally creates a new record.) E.g., clicking a "buy item" button ten times may get you ten instances of the thing, and that's not idempotent. PATCH is not idempotent. Example API's -------------------------------------------------- - https://developer.github.com/v3/ - https://developer.paypal.com/docs/api/ - https://www.twilio.com/docs/api/rest API Consumption with Browser JavaScript -------------------------------------------------- Among the several ways to use API data from a web page, choose the browser's JavaScript **fetch** API to consume JSON. CORS -------------------------------------------------- A web page freely embeds cross-origin images, stylesheets, and scripts, but by default the same-origin security policy forbids other cross-origin requests, like Ajax. What is an "origin"? An origin is defined as the combination of protocol (http), port (80), and host (www.example.com). Cross-Origin Resource Sharing (CORS) allows restricted resources to be requested from a different origin. CORS allows more than pure same-origin requests, but is more secure than allowing all cross-origin requests. CORS describes new HTTP headers that let browsers and servers request remote URLs only when they have permission. The browser must support these headers and honor the restrictions they impose. What is the point of CORS? Alice visits shady website X. Website X runs an ill-intentioned script that tries to exploit an API at Alice's bank. The banks sees that website X is not an acceptable origin, and blocks the abuse. CORS protects the user. For Ajax and HTTP methods that modify data (e.g., methods other than GET), the browser "preflights" the request by soliciting supported methods from the server with an HTTP OPTIONS request. Upon "approval" from the server, the browser sends the actual request with the actual HTTP request method. Servers also notify clients whether credentials, like cookies and HTTP auth, should accompany requests. The OPTIONS request sent by the browser includes the origin of the web pages (e.g., "Origin: www.example.com"). The server replies to the browser with an ACAO header to allow or deny the origin (e.g., "Access-Control-Allow-Origin: http://www.example.com"). The server might reply with a wildcard ACAO header ("Access-Control-Allow-Origin: *"), but that's only appropriate for completely public API's. Authorization and API Keys -------------------------------------------------- How do we restrict access to a non-public API? API keys are common, with three methods often used to pass the key from client to server. - Passing the API key as a **query string in the URL** is easy (e.g., `https://example.com/api/v1/widget?apikey=mysecretkey`). However, this is not the most secure option, because it's so easy to accidentally leak a key by pasting a URL in the wrong place. - Passing the API key in the **HTTP Basic Authentication header** is OK. But do you pass the key as the username or password? What if you need both API keys and distinct authenticated users? - Passing the API key in the **HTTP Authorizaton header** is probably the best way, like `Authorization: ApiKey mysecretkey`. - Another option is to implement a custom header (e.g., `X-MyCo-ApiKey`), but this is non-standard and offers no advantage over the standard Authorization header. Links -------------------------------------------------- - http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api - https://en.wikipedia.org/wiki/Representational_state_transfer - https://en.wikipedia.org/wiki/JSON - http://www.json.org/ - https://project-open-data.cio.gov/api-basics/ - https://zapier.com/learn/apis/ - http://www.restapitutorial.com/ - https://news.ycombinator.com/item?id=11971491 - https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API - https://davidwalsh.name/fetch - https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en - https://fetch.spec.whatwg.org/ - https://github.com/github/fetch - https://en.wikipedia.org/wiki/Polyfill - https://www.w3.org/TR/cors/ - https://en.wikipedia.org/wiki/Cross-origin_resource_sharing - https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy - https://fetch.spec.whatwg.org/ - https://stackoverflow.com/questions/4850702/is-cors-a-secure-way-to-do-cross-domain-ajax-requests