# API Client Design When working with API clients there are several distinct areas of concern. Each of these happen in sequence and are used with the goal of receiving a **Domain Model** at the end. * [Routing](#routing) * [Configuration](#configuration) * [Logging](#logging) * [Connection Handling](#connection-handling) * [Error Handling](#error-handling) * [Request Building](#request-building) * [Request Handling](#request-handling) * [Response Handling](#response-handling) * [Domain Modeling](#domain-modeling) ## Routing This answers the question: **what can I do with this API?** When embedded links or hypermedia are not available, routing should be confined to a single responsibility and include: * Fully qualified URIs * Specified [URI Template](https://tools.ietf.org/html/rfc6570) By using `HTTP` and available methods we can see more details as to how we can interact with a specific link. For instance, we may have a route like: `/products`. This tells us the route, but doesn't tell us how to interact with it. By making a call to `OPTIONS /products`, we can learn that the `Allow` header specifies `GET,POST,OPTIONS,HEAD`. This means we can then issue a `GET` request to retrieve all products, or we can issue a `POST` request to create a new product. By providing extended meta information in the `OPTIONS` request, we can also describe the requests in greater detail. We can answer questions like: * What are my available filters on a `GET` request? (their names, data types, formats, etc) * What are the `Content-Type`s available to me? Can I `GET` this as `JSON` and `CSV`? * What are the parameters required when `POST`ing to a new record? (their names, data types, formats, validation rules, etc) The biggest advantage to a centralized routing library: **You are not manually building URIs throughout your application code**. You can see this in many applications, where the routes are scattered about the JavaScript or server side code with mixed templating and interpolation strategies. Keep it simple. ## Configuration This answers the question: **how should I communicate with the API?** The configuration object sets up the different _variables_ you will use throughout your interactions. It can be used to: * Set Defaults * Allow User Provided values A set of configuration options may include * API Host * API Version * Proxy Information * Basic Auth Information * OAuth Bearer Token Information * Default HTTP Headers * User Agent * Media Type * Content Type * Pagination Handling ## Logging This answers the question: **what is happening behind the scenes?** Logging can be used in several areas: * Raw _request_ logging. These are the raw HTTP requests. * _Cache_ logging. When utilizing HTTP Caching, this provides information into your hits and misses. * _Application_ logging. This provides feedback in the **client** itself. This is useful to provide feedback and information such as: * Deprecation warnings * Debugging information when calling certain methods ## Connection Handling This answers the question: **can we communicate with the API server?** This involves things like: * Establishing a connection (is the server responding at all?) * Specifying a timeout for retries * Ensuring the response code is not in the `500` range ## Error Handling This answers the question: **something is wrong, but what is it and can I fix it?** Whether we are dealing with _connection_ errors or _request_ errors, there should be a consistent way to handle when something goes wrong. * When there are _connection_ errors, this is an `Exception`. We can't do anything else with the API until we can connect. * When there are _request_ errors, it could be either an `Exception` or silent failure. ## Request Building This phase allows you to prepare your request that you want to make. This includes things like: * HTTP Headers * HTTP Query String Params * HTTP Body Params This phase should provide a _DSL_ to build requests in a consistent manner. The specific client could then have very specific implementations of the details (IE: Using Query String params like Google API) ## Request Handling This answers the question: **Can you provide me the resource with this representation?** This takes the _Request Builder_ from the last phase, combines in with the _Connection Handling_, and issues a request to the server. ## Response Handling One a request has been issued, there is a response that includes things like: * HTTP Response body (according to content negotiation - CSV, JSON, etc) * HTTP Status Code * HTTP Headers * Full Raw Response The response _Status Code_ itself allows us to immediately handle the request accordingly: * If it's a non-successful code, [handle as an error](#error-handling) * If it's successful, we can continue. The response _Header_ itself carries some important client information as well, such as: * Scope listing * Content Negotiation * `Allow` information * Caching information * OAuth Information * `Link` information The goal here is to ensure we get a `200` range response. Not all responses will include a body. We also need to figure out if we want to _follow redirects_ and for how many hops (avoid infinite redirect loops). ## Domain Modeling We've _configured_, _connected_, _built our request_, _issued the request to the server_, and _received a response_. Now it's time to take that response and turn it into the **Core Domain Model**. In most cases this is translating the `JSON` response into meaningful objects. The body itself may include other pieces of helpful information: * Metadata * Paginatation Information * Links * Data/Results - the body itself Each of these models will translate accordingly and can be used to then issue subsequent requests. ### Examples and Inspiration * [PAW: Mac Client](https://luckymarmot.com/paw), allows you to build requests and see responses. * Build the request itself with _headers_ and _params_ * View the _request_ as a URL and as cURL and other tools. * View the _response_ as raw output, or separated by _headers_ and _body_ * Allows you to extract _environment variables_ for use in requests (_configuration_) * [Github Octokit](https://github.com/octokit/octokit.rb)