11# Fluture Node
22
3- Common Node API's wrapped to return [ Fluture] [ ] Futures.
3+ FP-style HTTP and streaming utils for Node based on [ Fluture] [ ] .
4+
5+ ``` console
6+ $ npm install fluture fluture-node
7+ ```
48
59## API
610
7- #### <a name =" once " href =" https://github.com/fluture-js/fluture-node/blob/v2.0.0/index.js#L9 " >` once :: String -> EventEmitter -> Future Error a ` </a >
11+ ### EventEmitter
12+
13+ #### <a name =" once " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L29 " >` once :: String -> EventEmitter -> Future Error a ` </a >
814
915Resolve a Future with the first event emitted over
1016the given event emitter under the given event name.
@@ -19,9 +25,38 @@ itself from the event emitter.
1925Future .of (42 );
2026```
2127
22- #### <a name =" buffer " href =" https://github.com/fluture-js/fluture-node/blob/v2.0.0/index.js#L41 " >` buffer :: ReadableStream a -> Future Error (Array a) ` </a >
28+ ### Buffer
29+
30+ #### <a name =" encode " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L63 " >` encode :: Charset -> Buffer -> Future Error String ` </a >
31+
32+ Given an encoding and a [ Buffer] [ ] , returns a Future of the result of
33+ encoding said buffer using the given encoding. The Future will reject
34+ with an Error if the encoding is unknown.
35+
36+ ``` js
37+ > encode (' utf8' ) (Buffer .from (' Hello world!' ));
38+ ' Hello world!'
39+ ```
40+
41+ ### Stream
42+
43+ #### <a name =" streamOf " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L80 " >` streamOf :: Buffer -> Future a (Readable Buffer) ` </a >
44+
45+ Given a [ Buffer] [ ] , returns a Future of a [ Readable] [ ] stream which will
46+ emit the given Buffer before ending.
2347
24- Buffer all data on a Stream into a Future of an Array.
48+ The stream is wrapped in a Future because creation of a stream causes
49+ side-effects if it's not consumed in time, making it safer to pass it
50+ around wrapped in a Future.
51+
52+ #### <a name =" emptyStream " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L96 " >` emptyStream :: Future a (Readable Buffer) ` </a >
53+
54+ A [ Readable] [ ] stream which ends after emiting zero bytes. Can be useful
55+ as an empty [ ` request ` ] ( #request ) body, for example.
56+
57+ #### <a name =" buffer " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L102 " >` buffer :: Readable a -> Future Error (Array a) ` </a >
58+
59+ Buffer all data on a [ Readable] [ ] stream into a Future of an Array.
2560
2661When the Future is cancelled, it removes any trace of
2762itself from the Stream.
@@ -37,7 +72,16 @@ itself from the Stream.
3772Future .of ([Buffer .from (' hello' ), Buffer .from (' world' )]);
3873```
3974
40- #### <a name =" instant " href =" https://github.com/fluture-js/fluture-node/blob/v2.0.0/index.js#L80 " >` instant :: b -> Future a b ` </a >
75+ #### <a name =" bufferString " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L141 " >` bufferString :: Charset -> Readable Buffer -> Future Error String ` </a >
76+
77+ A version of [ ` buffer ` ] ( #buffer ) specialized in Strings.
78+
79+ Takes a charset and a [ Readable] [ ] stream of [ Buffer] [ ] s, and returns
80+ a Future containing a String with the fully buffered and encoded result.
81+
82+ ### Event Loop
83+
84+ #### <a name =" instant " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L153 " >` instant :: b -> Future a b ` </a >
4185
4286Resolves a Future with the given value in the next tick,
4387using [ ` process.nextTick ` ] [ ] . The scheduled job cannot be
@@ -49,7 +93,7 @@ blocking the event loop until it's completed.
4993Future .of (' noodles' )
5094```
5195
52- #### <a name =" immediate " href =" https://github.com/fluture-js/fluture-node/blob/v2.0 .0/index.js#L96 " >` immediate :: b -> Future a b ` </a >
96+ #### <a name =" immediate " href =" https://github.com/fluture-js/fluture-node/blob/v2.1 .0/index.js#L169 " >` immediate :: b -> Future a b ` </a >
5397
5498Resolves a Future with the given value in the next tick,
5599using [ ` setImmediate ` ] [ ] . This job will run as soon as all
@@ -61,6 +105,181 @@ job is unscheduled.
61105Future .of (' results' )
62106```
63107
64- [ Fluture ] : https://github.com/fluture-js/Fluture
108+ ### Http
109+
110+ The functions below are to be used in compositions such as the one shown
111+ below, in order to cover a wide variety of HTTP-related use cases.
112+
113+ ``` js
114+ import {map , chain , chainRej , encase , fork } from ' fluture/index.js' ;
115+ import {retrieve ,
116+ acceptStatus ,
117+ autoBufferResponse ,
118+ responseToError } from ' ./index.js' ;
119+
120+ const rejectUnacceptable = res => (
121+ acceptStatus (200 ) (res)
122+ .pipe (chainRej (responseToError))
123+ );
124+
125+ retrieve (' https://api.github.com/users/Avaq' ) ({' User-Agent' : ' Avaq' })
126+ .pipe (chain (rejectUnacceptable))
127+ .pipe (chain (autoBufferResponse))
128+ .pipe (chain (encase (JSON .parse )))
129+ .pipe (map (avaq => avaq .name ))
130+ .pipe (fork (console .error ) (console .log ));
131+ ```
132+
133+ The example above will either:
134+
135+ 1 . log ` "Aldwin Vlasblom" ` to the terminal if nothing weird happens; or
136+ 2 . log an error to the console if:
137+ * a network error occurs;
138+ * the response code is not 200; or
139+ * the JSON is malformed.
140+
141+ Note that we were in control of how an unexpected status was treated,
142+ how an erroneous response would be formatted as an error message,
143+ whether the response would be parsed as JSON, and how a failure of parsing
144+ the JSON would have been treated.
145+
146+ The goal of the functions below us to give you as much control over HTTP
147+ requests as possible, while still keeping boilerplate low by leveraging
148+ function composition.
149+
150+ This contrasts with many of the popular HTTP client libraries out there,
151+ which often make decisions for you, taking away control in an attempt to
152+ provide a smoother usage experience.
153+
154+ #### <a name =" request " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L255 " >` request :: Object -> Url -> Readable Buffer -> Future Error IncomingMessage ` </a >
155+
156+ This is the "lowest level" function for making HTTP requests. It does not
157+ handle buffering, encoding, content negotiation, or anything really.
158+ For most use cases, you can use one of the more specialized functions:
159+
160+ * [ ` send ` ] ( #send ) : Make a generic HTTP request.
161+ * [ ` retrieve ` ] ( #retrieve ) : Make a GET request.
162+
163+ Given an Object of [ http options] [ ] , a String containing the request URL,
164+ and a [ Readable] [ ] stream of [ Buffer] [ ] s to be sent as the request body,
165+ returns a Future which makes an HTTP request and resolves with its
166+ [ IncomingMessage] [ ] . If the Future is cancelled, the request is aborted.
167+
168+ ``` js
169+ import {attempt , chain } from ' fluture/index.js' ;
170+ import {createReadStream } from ' fs' ;
171+
172+ const sendBinary = request ({
173+ method: ' POST' ,
174+ headers: {' Transfer-Encoding' : ' chunked' },
175+ });
176+
177+ const eventualBody = attempt (() => createReadStream (' ./data.bin' ));
178+
179+ eventualBody .pipe (chain (sendBinary (' https://example.com' )));
180+ ```
181+
182+ If you want to use this function to transfer a stream of data, don't forget
183+ to set the Transfer-Encoding header to "chunked".
184+
185+ #### <a name =" retrieve " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L299 " >` retrieve :: Url -> StrMap String -> Future Error IncomingMessage ` </a >
186+
187+ A version of [ ` request ` ] ( #request ) specialized in the ` GET ` method.
188+
189+ Given a URL and a StrMap of request headers, returns a Future which
190+ makes a GET requests to the given resource.
191+
192+ ``` js
193+ retrieve (' https://api.github.com/users/Avaq' ) ({' User-Agent' : ' Avaq' })
194+ ```
195+
196+ #### <a name =" send " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L313 " >` send :: Mimetype -> Method -> Url -> StrMap String -> Buffer -> Future Error IncomingMessage ` </a >
197+
198+ A version of [ ` request ` ] ( #request ) for sending arbitrary data to a server.
199+ There's also more specific versions for sending common types of data:
200+
201+ * [ ` sendJson ` ] ( #sendJson ) sends JSON stringified data.
202+ * [ ` sendForm ` ] ( #sendForm ) sends form encoded data.
203+
204+ Given a MIME type, a request method, a URL, a StrMap of headers, and
205+ finally a Buffer, returns a Future which will send the Buffer to the
206+ server at the given URL using the given request method, telling it the
207+ buffer contains data of the given MIME type.
208+
209+ This function will always send the Content-Type and Content-Length headers,
210+ alongside the provided headers. Manually provoding either of these headers
211+ override those generated by this function.
212+
213+ #### <a name =" sendJson " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L337 " >` sendJson :: Method -> String -> StrMap String -> JsonValue -> Future Error IncomingMessage ` </a >
214+
215+ A version of [ ` send ` ] ( #send ) specialized in sending JSON.
216+
217+ Given a request method, a URL, a StrMap of headers and a JavaScript plain
218+ object, returns a Future which sends the object to the server at the
219+ given URL after JSON-encoding it.
220+
221+ ``` js
222+ sendJson (' PUT' )
223+ (' https://example.com/users/bob' )
224+ ({Authorization: ' Bearer asd123' })
225+ ({name: ' Bob' , email: ' bob@example.com' });
226+ ```
227+
228+ #### <a name =" sendForm " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L356 " >` sendForm :: Method -> String -> StrMap String -> JsonValue -> Future Error IncomingMessage ` </a >
229+
230+ A version of [ ` send ` ] ( #send ) specialized in sending form data.
231+
232+ Given a request method, a URL, a StrMap of headers and a JavaScript plain
233+ object, returns a Future which sends the object to the server at the
234+ given URL after www-form-urlencoding it.
235+
236+ ``` js
237+ sendForm (' POST' )
238+ (' https://example.com/users/create' )
239+ ({})
240+ ({name: ' Bob' , email: ' bob@example.com' });
241+ ```
242+
243+ #### <a name =" acceptStatus " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L375 " >` acceptStatus :: Number -> IncomingMessage -> Future IncomingMessage IncomingMessage ` </a >
244+
245+ This function "tags" an [ IncomingMessage] [ ] based on a given status code.
246+ If the response status matches the given status code, the returned Future
247+ will resolve. If it doesn't, the returned Future will reject.
248+
249+ The idea is that you can compose this function with one that returns an
250+ IncomingMessage, and reject any responses that don't meet the expected
251+ status code. In combination with [ ` responseToError ` ] ( #responseToError ) ,
252+ you can then flatten it back into the outer Future.
253+
254+ The usage example under the [ Http] ( #http ) section shows this.
255+
256+ #### <a name =" bufferResponse " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L391 " >` bufferResponse :: Charset -> IncomingMessage -> Future Error String ` </a >
257+
258+ A version of [ ` buffer ` ] ( #buffer ) specialized in [ IncomingMessage] [ ] s.
259+
260+ See also [ ` autoBufferResponse ` ] ( #autoBufferResponse ) .
261+
262+ Given a charset and an IncomingMessage, returns a Future with the buffered,
263+ encoded, message body.
264+
265+ #### <a name =" autoBufferResponse " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L404 " >` autoBufferResponse :: IncomingMessage -> Future Error String ` </a >
266+
267+ Given an IncomingMessage, buffers and decodes the message body using the
268+ charset provided in the message headers. Falls back to UTF-8 if the
269+ charset was not provided.
270+
271+ Returns a Future with the buffered, encoded, message body.
272+
273+ #### <a name =" responseToError " href =" https://github.com/fluture-js/fluture-node/blob/v2.1.0/index.js#L418 " >` responseToError :: IncomingMessage -> Future Error a ` </a >
274+
275+ Given a response, returns a * rejected* Future of an instance of Error
276+ with a message based on the content of the response.
277+
65278[ `process.nextTick` ] : https://nodejs.org/api/process.html#process_process_nexttick_callback_args
66279[ `setImmediate` ] : https://nodejs.org/api/timers.html#timers_setimmediate_callback_args
280+
281+ [ Buffer ] : https://nodejs.org/api/buffer.html#buffer_class_buffer
282+ [ Fluture ] : https://github.com/fluture-js/Fluture
283+ [ http options ] : https://nodejs.org/api/http.html#http_http_request_url_options_callback
284+ [ IncomingMessage ] : https://nodejs.org/api/http.html#http_class_http_incomingmessage
285+ [ Readable ] : https://nodejs.org/api/stream.html#stream_class_stream_readable
0 commit comments