diff --git a/source/learn/_sidebar.slim b/source/learn/_sidebar.slim index 0df063d24..f5f5680cc 100644 --- a/source/learn/_sidebar.slim +++ b/source/learn/_sidebar.slim @@ -36,6 +36,8 @@ ul.sidebar__items li.sidebar__sub-item= nav_link_to 'Commands', '/learn/sql/commands', class: 'sidebar__sub-link' li.sidebar__sub-item= nav_link_to 'Transactions', '/learn/sql/transactions', class: 'sidebar__sub-link' li.sidebar__sub-item= nav_link_to 'Migrations', '/learn/sql/migrations', class: 'sidebar__sub-link' + li.sidebar__item + = nav_link_to 'HTTP', '/learn/http', class: 'sidebar__link' li.sidebar__item = nav_link_to 'Kafka', '/learn/kafka', class: 'sidebar__link' li.sidebar__item diff --git a/source/learn/http/index.html.md b/source/learn/http/index.html.md new file mode 100644 index 000000000..16297e470 --- /dev/null +++ b/source/learn/http/index.html.md @@ -0,0 +1,47 @@ +--- +title: HTTP +chapter: Setup +--- + +*The adapter is still in beta. If you find any inconsistency, please feel free to ask your questions at the [ROM chatroom] and report issues [on github][rom-http].* + +ROM supports HTTP-based services via the `rom-http` adapter, which is +client-agnostic. The adapter presents a request-response wrapper, allowing +the use of an arbitrary HTTP client gem. + +By implementing the request and response handlers, it should be possible to +interact with any arbitrary HTTP service; however as each service provides +different semantics and expectations, `rom-http` is presented as a "batteries +not included" adapter. + +Refer to the general [setup](/learn/setup) for information on how to setup +ROM with specific adapters. `ROM::HTTP` will require some additional +configuration for each of it's Gateways. + +## Establishing Gateways + +Each remote HTTP host should be established as it's own gateway in the ROM +container. + +```ruby + ROM.container( + github: [:http, { + uri: "https://api.github.com", + headers: { Accept: 'application/json' }, + request_handler: GithubRequestHandler.new, + response_handler: GithubResponseHandler.new + }], + placeholder: [:http, { + uri: "https://jsonplaceholder.typicode.com", + headers: { Accept: 'application/json' }, + request_handler: PlaceholderRequestHandler.new, + response_handler: PlaceholderResponseHandler.new + }] + ) +``` + +`request_handler` and `resposne_handler` are responsible for the work of +communicating with the HTTP server, and processing the response, respectively. +Learn more about them in the [requests](/learn/http/requests) section. These +objects are used by the [relation](/learn/http/relations) when communicating +with the web server. diff --git a/source/learn/http/relations.html.md b/source/learn/http/relations.html.md new file mode 100644 index 000000000..de5ca2ae8 --- /dev/null +++ b/source/learn/http/relations.html.md @@ -0,0 +1,43 @@ +--- +title: HTTP +chapter: Relations +--- + +To define an HTTP relation, you can use the standard way of defining relations +in ROM: + +```ruby +class Users < ROM::Relation[:http] + gateway :placeholder + dataset :users +end +``` + +The dataset name may be used by a request handler to help build the resource +path. In the case of a namespaced resource, it is possible to provide a string +name for the dataset: + +```ruby +class Users < ROM::Relation[:http] + gateway :placeholder + dataset 'admin/users' +end +``` + +To define relations that are exposed to your application, you can define your +own methods and use the internal [dataset API](/learn/http/datasets): + +```ruby +class Users < ROM::Relation[:http] + gateway :placeholder + dataset :users + + def by_id(id) + append_path(id.to_s) + end + + def limit(count) + with_params(params.merge(per_page: count.to_i)) + end +end +``` diff --git a/source/learn/http/requests.html.md b/source/learn/http/requests.html.md new file mode 100644 index 000000000..a01fe76b4 --- /dev/null +++ b/source/learn/http/requests.html.md @@ -0,0 +1,38 @@ +--- +title: HTTP +chapter: Requests +--- + +In order to remain client and adapter agnostic, ROM::HTTP does not attempt +to perform the actual process of sending web-queries. This allows you to +choose your favorite HTTP client library, or even to make use of a +service-specific client gem. + +A request handler expects to receive the `#call` method, and is provided with +an HTTP `dataset` object, from which the URL, HTTP verb, headers and query +parameters will be drawn. The results of this method will be passed directly +into the response handler object's `#call` method, which is expected to return +the ROM standard array of tuples. Taken together, these two objects will +isolate the specifics of your HTTP library, and service responses from the +rest of your data layer. + +``` +class RequestHandler + def call(dataset) + uri = URI(dataset.uri) + + path = "/#{dataset.name}/#{dataset.path}" + + client = Faraday.new(uri, headers: dataset.headers) + + response = client.send(dataset.request_method, path, dataset.params) + end +end + + +class ResponseHandler + def call(response, dataset) + Array([JSON.parse(response.body)]).flatten + end +end +```