1 | # Subrequests
|
2 |
|
3 | [![Coverage Status](https://coveralls.io/repos/github/e0ipso/subrequests/badge.svg)](https://coveralls.io/github/e0ipso/subrequests)
|
4 | [![Known Vulnerabilities](https://snyk.io/test/github/e0ipso/subrequests/badge.svg)](https://snyk.io/test/github/e0ipso/subrequests)
|
5 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
|
6 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
|
7 | [![Greenkeeper badge](https://badges.greenkeeper.io/e0ipso/subrequests.svg)](https://greenkeeper.io/)
|
8 | [![Build Status](https://travis-ci.org/e0ipso/subrequests.svg?branch=master)](https://travis-ci.org/e0ipso/subrequests)
|
9 |
|
10 | [![NPM](https://nodei.co/npm/subrequests.png)](https://nodei.co/npm/subrequests/)
|
11 |
|
12 | ## Installation
|
13 |
|
14 | ```npm
|
15 | npm install --save subrequests
|
16 | ```
|
17 |
|
18 | or
|
19 |
|
20 | ```
|
21 | yarn add subrequests
|
22 | ```
|
23 |
|
24 | ## Usage
|
25 |
|
26 | ### On the Server
|
27 |
|
28 | If you want to enable subrequests in an Express application, please see
|
29 | [Subrequests Express](https://github.com/e0ipso/subrequests-express#readme) to learn how to do so
|
30 | in two lines of code.
|
31 |
|
32 | You can use _Subrequests_ anywhere you are serving requests. I makes a lot of sense to add it as a middleware in an
|
33 | Express application, for instance. In order to provide an easier testing experience _Subrequests_ comes with a super
|
34 | simple server that will:
|
35 |
|
36 | - Collect requests with a blueprint from the consumers.
|
37 | - Make an HTTP request for each subrequest in the blueprint resolving dependencies.
|
38 | - Respond to the consumer with all the responses to the subrequests in the blueprint.
|
39 |
|
40 | To start the demo server:
|
41 |
|
42 | ```
|
43 | npm start
|
44 | ```
|
45 |
|
46 | That will create the server in `127.0.0.1:3456`. This server is now ready to receive request blueprints.
|
47 |
|
48 | #### Use It in Your App
|
49 |
|
50 | Even if having that small server deployed will already give you a bunch of nice features, _Subrequests_ is most useful
|
51 | when integrated in your stack. _Subrequests_ uses a _"requestor"_ to resolve each request in the blueprint. Best overall
|
52 | performance will be achieved when resolving the requests to your service locally.
|
53 |
|
54 | Imagine that you have an Express application. In that you install _Subrequests_ and create a route that accepts
|
55 | blueprints in `/subrequests`. In that scenario, when the blueprint contains a request you want to treat differenrly
|
56 | based on some conditions. To do so, extend the `HttpRequestor` as your `MyCustomRequestor`. `MyCustomRequestor`
|
57 | detects the _special conditions_ in the requests and reacts accordingly (maybe dropping the request) and uses HTTP to
|
58 | resolve the other requests. You can tell the system to use your new requestor. Istead of
|
59 | [this code](./exampleServer.js#L25) use:
|
60 |
|
61 | ```js
|
62 | subrequests.request(blueprint, new MyCustomRequestor())
|
63 | ```
|
64 |
|
65 | ### Client Code
|
66 |
|
67 | Once your API server has `subrequests` installed just make a regular request to
|
68 | the route listening to subrequests.
|
69 |
|
70 | I created a collection of JSON documents for this test that you can use. You can
|
71 | find them in
|
72 | [foo-bar.json](https://gist.github.com/e0ipso/7cafb6b7debe786cfb60f617fa89ba81).
|
73 |
|
74 | ```js
|
75 | // You can use whatever HTTP library you like.
|
76 | const axios = require('axios');
|
77 |
|
78 | const blueprint = [
|
79 | {
|
80 | requestId: 'req1',
|
81 | uri: 'https://gist.githubusercontent.com/e0ipso/7cafb6b7debe786cfb60f617fa89ba81/raw/a6590d3cc87d0c00485c9e428c8b7c29da21b704/foo-bar.json',
|
82 | action: 'view'
|
83 | },
|
84 | {
|
85 | requestId: 'req2',
|
86 | uri: 'https://gist.githubusercontent.com/e0ipso/7cafb6b7debe786cfb60f617fa89ba81/raw/a6590d3cc87d0c00485c9e428c8b7c29da21b704/the-end.json',
|
87 | action: 'view'
|
88 | },
|
89 | {
|
90 | requestId: 'req1.1',
|
91 | uri: "https://gist.githubusercontent.com/e0ipso/7cafb6b7debe786cfb60f617fa89ba81/raw/a6590d3cc87d0c00485c9e428c8b7c29da21b704/{{req1.body@$['my-key']}}.json",
|
92 | action: 'view',
|
93 | waitFor: 'req1'
|
94 | },
|
95 | {
|
96 | requestId: 'req1.1.1',
|
97 | uri: 'https://gist.githubusercontent.com/e0ipso/7cafb6b7debe786cfb60f617fa89ba81/raw/a6590d3cc87d0c00485c9e428c8b7c29da21b704/{{req1.1.body@$.akward[*]}}.json',
|
98 | action: 'view',
|
99 | waitFor: 'req1.1'
|
100 | }
|
101 | ];
|
102 |
|
103 | // Assuming '/subrequests' is listening for subrequests calls.
|
104 | axios.get('http://127.0.0.1:3456/subrequests', {
|
105 | params: {
|
106 | query: JSON.stringify(blueprint),
|
107 | }
|
108 | })
|
109 | .then(function (response) {
|
110 | console.log(response);
|
111 | })
|
112 | .catch(function (error) {
|
113 | console.log(error);
|
114 | });
|
115 | ```
|
116 |
|
117 | This will return a response body like the following (it's been abbreviated for
|
118 | readability purposes).
|
119 |
|
120 | ```
|
121 | 9799c4--
|
122 | content-length: 23
|
123 | …
|
124 | x-subrequest-id: req1
|
125 | Content-ID: <req1>
|
126 |
|
127 | {
|
128 | "my-key": "lorem"
|
129 | }
|
130 | --9799c4
|
131 | x-cache: HIT
|
132 | …
|
133 | x-subrequest-id: req2
|
134 | Content-ID: <req2>
|
135 |
|
136 | {
|
137 | "runs": {
|
138 | "in": "parallel"
|
139 | }
|
140 | }
|
141 | --9799c4
|
142 | x-xss-protection: 1; mode=block
|
143 | expires: Fri, 21 Jul 2017 13:51:19 GMT
|
144 | …
|
145 | x-subrequest-id: req1.1#uri{0}
|
146 | Content-ID: <req1.1#uri{0}>
|
147 |
|
148 | {
|
149 | "akward": ["moar", "hip", "tests"]
|
150 | }
|
151 | --9799c4
|
152 | content-length: 26
|
153 | …
|
154 | x-subrequest-id: req1.1.1#uri{0}
|
155 | Content-ID: <req1.1.1#uri{0}>
|
156 |
|
157 | [
|
158 | {
|
159 | "ha": "li"
|
160 | }
|
161 | ]
|
162 | --9799c4
|
163 | date: Fri, 21 Jul 2017 13:46:19 GMT
|
164 | via: 1.1 varnish
|
165 | …
|
166 | x-subrequest-id: req1.1.1#uri{1}
|
167 | Content-ID: <req1.1.1#uri{1}>
|
168 |
|
169 | true
|
170 | --9799c4
|
171 | etag: "1a55725f5478ba88781322669bc08b4b633e67a0"
|
172 | content-type: text/plain; charset=utf-8
|
173 | …
|
174 | x-subrequest-id: req1.1.1#uri{2}
|
175 | Content-ID: <req1.1.1#uri{2}>
|
176 |
|
177 | {
|
178 | "we need": "nonsensical strings"
|
179 | }
|
180 | --9799c4--
|
181 | ```
|
182 |
|
183 | #### Customizing the Response Format
|
184 |
|
185 | If you want to have a different format consider providing a different
|
186 | sub-responses merger. You can see an example of that in the
|
187 | [`subrequests-json-merger`](https://github.com/e0ipso/subrequests-json-merger) contributed module. For greater control,
|
188 | write your own!
|