All Projects → simov → Request Compose

simov / Request Compose

Licence: apache-2.0
Composable HTTP Client

Programming Languages

javascript
184084 projects - #8 most used programming language
js
455 projects

Projects that are alternatives of or similar to Request Compose

Bow
🏹 Bow is a cross-platform library for Typed Functional Programming in Swift
Stars: ✭ 538 (+572.5%)
Mutual labels:  functional-programming, fp
D4s
Dynamo DB Database Done Scala-way
Stars: ✭ 27 (-66.25%)
Mutual labels:  functional-programming, fp
Fkit
A functional programming toolkit for JavaScript.
Stars: ✭ 588 (+635%)
Mutual labels:  functional-programming, fp
Kotlin Result
A multiplatform Result monad for modelling success or failure operations.
Stars: ✭ 369 (+361.25%)
Mutual labels:  functional-programming, fp
Stm4cats
STM monad for cats-effect
Stars: ✭ 35 (-56.25%)
Mutual labels:  functional-programming, fp
Fasy
FP iterators that are both eager and asynchronous
Stars: ✭ 488 (+510%)
Mutual labels:  functional-programming, fp
Frameless
Expressive types for Spark.
Stars: ✭ 717 (+796.25%)
Mutual labels:  functional-programming, fp
Shapeless
Generic programming for Scala
Stars: ✭ 3,207 (+3908.75%)
Mutual labels:  functional-programming, fp
Flawless
WIP Delightful, purely functional testing no-framework. Don't even try to use it at work!
Stars: ✭ 33 (-58.75%)
Mutual labels:  functional-programming, fp
Gentleman
Full-featured, plugin-driven, extensible HTTP client toolkit for Go
Stars: ✭ 886 (+1007.5%)
Mutual labels:  http-client, client
Fun Task
Abstraction for managing asynchronous code in JS
Stars: ✭ 363 (+353.75%)
Mutual labels:  functional-programming, fp
Rambda
Faster and smaller alternative to Ramda
Stars: ✭ 1,066 (+1232.5%)
Mutual labels:  functional-programming, fp
Monio
Async-capable IO monad for JS
Stars: ✭ 311 (+288.75%)
Mutual labels:  functional-programming, fp
Fp Jargon Zh
函数式编程术语及示例。本项目译自 https://github.com/hemanth/functional-programming-jargon
Stars: ✭ 507 (+533.75%)
Mutual labels:  functional-programming, fp
Prelude Ts
Functional programming, immutable collections and FP constructs for typescript and javascript
Stars: ✭ 315 (+293.75%)
Mutual labels:  functional-programming, fp
Funfix
Functional Programming Library for JavaScript, TypeScript and Flow ✨⚡️
Stars: ✭ 596 (+645%)
Mutual labels:  functional-programming, fp
Pfps Shopping Cart
🛒 The Shopping Cart application developed in the book "Practical FP in Scala: A hands-on approach"
Stars: ✭ 262 (+227.5%)
Mutual labels:  functional-programming, fp
Eslint Plugin Functional
ESLint rules to disable mutation and promote fp in JavaScript and TypeScript.
Stars: ✭ 282 (+252.5%)
Mutual labels:  functional-programming, fp
Bugz
🐛 Composable User Agent Detection using Ramda
Stars: ✭ 15 (-81.25%)
Mutual labels:  functional-programming, fp
Funland
Type classes for interoperability of common algebraic structures in JavaScript, TypeScript and Flow
Stars: ✭ 46 (-42.5%)
Mutual labels:  functional-programming, fp

request-compose

npm-version travis-ci coveralls-status

Composable HTTP Client

var compose = require('request-compose')
var Request = compose.Request
var Response = compose.Response

;(async () => {
  try {
    var {res, body} = await compose(
      Request.defaults({headers: {'user-agent': 'request-compose'}}),
      Request.url('https://api.github.com/users/simov'),
      Request.send(),
      Response.buffer(),
      Response.string(),
      Response.parse(),
    )()
    console.log(res.statusCode, res.statusMessage)
    console.log(res.headers['x-ratelimit-remaining'])
    console.log(body)
  }
  catch (err) {
    console.error(err)
  }
})()

Goals

  • No dependencies
  • No abstraction
  • No state

Table of Contents

Compose

In computer science, function composition (not to be confused with object composition) is an act or mechanism to combine simple functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole.

var compose = require('request-compose')

Accepts a list of functions to execute and returns a Promise:

var doit = compose(
  (a) => a + 2,
  (a) => a * 2,
)

Then we can call it:

var result = await doit(5) // 14

A more practical example however would be to compose our own HTTP client:

var compose = require('request-compose')
var https = require('https')

var request = compose(
  (options) => {
    options.headers = options.headers || {}
    options.headers['user-agent'] = 'request-compose'
    return options
  },
  (options) => new Promise((resolve, reject) => {
    https.request(options)
      .on('response', resolve)
      .on('error', reject)
      .end()
  }),
  async (res) => await new Promise((resolve, reject) => {
    var body = ''
    res
      .on('data', (chunk) => body += chunk)
      .on('end', () => resolve({res, body}))
      .on('error', reject)
  }),
  ({res, body}) => ({res, body: JSON.parse(body)}),
)

Then we can use it like this:

;(async () => {
  try {
    var {res, body} = await request({
      protocol: 'https:',
      hostname: 'api.github.com',
      path: '/users/simov',
    })
    console.log(res.statusCode, res.statusMessage)
    console.log(res.headers['x-ratelimit-remaining'])
    console.log(body)
  }
  catch (err) {
    console.error(err)
  }
})()

Bundled Middlewares

request-compose comes with a bunch of pre-defined middlewares for transforming the request and the response:

var compose = require('request-compose')
var Request = compose.Request
var Response = compose.Response

We can use these middlewares to compose our own HTTP client:

;(async () => {
  try {
    var {res, body} = await compose(
      Request.defaults({headers: {'user-agent': 'request-compose'}}),
      Request.url('https://api.github.com/users/simov'),
      Request.send(),
      Response.buffer(),
      Response.string(),
      Response.parse(),
    )()
    console.log(res.statusCode, res.statusMessage)
    console.log(res.headers['x-ratelimit-remaining'])
    console.log(body)
  }
  catch (err) {
    console.error(err)
  }
})()
Type Middleware Input Arguments Returns
Request defaults {input} {input} {options}
Request url, proxy, qs, cookie see options {options} {options}
Request form, json, multipart, body see options {options} {options, body}
Request auth, oauth see options {options, body} {options, body}
Request length - {options, body} {options, body}
Request send - {options, body} {options, res}
Response buffer - {options, res} {options, res, body}
Response gzip - {options, res, body, raw} {options, res, body, raw}
Response string see options {options, res, body, raw} {options, res, body, raw}
Response parse, status - {options, res, body, raw} {options, res, body, raw}
Response redirect (input, client) {options, res, body, raw} new composition

Opinionated Client

request-compose comes with opinionated HTTP client that is composed of the above middlewares.

There are 3 types of composition available based on the returned data type:

client

var request = require('request-compose').client
var {res, body} = await request({options})

The client composition does the following:

  • buffers the response body
  • decompresses gzip and deflate encoded bodies with valid content-encoding header
  • converts the response body to string using utf8 encoding by default
  • tries to parse JSON and querystring encoded bodies with valid content-type header

Returns either String or Object.

buffer

var request = require('request-compose').buffer
var {res, body} = await request({options})

The buffer composition does the following:

  • buffers the response body
  • decompresses gzip and deflate encoded bodies with valid content-encoding header

Returns Buffer.

stream

var request = require('request-compose').stream
var {res} = await request({options})

The stream composition returns the response Stream.

options

The above compositions accept any of the Node's http.request and https.request options:

var {res, body} = await request({
  method: 'GET',
  url: 'https://api.github.com/users/simov',
  headers: {
    'user-agent': 'request-compose'
  }
})

Additionally the following options are available:

Option Type Description
url 'string' url object URL (encoding - see below)
proxy 'string' url object Proxy URL
qs {object} 'string' URL querystring (encoding - see below)
form {object} 'string' application/x-www-form-urlencoded request body (encoding - see below)
json {object} 'string' JSON encoded request body
multipart {object} [array] multipart request body using request-multipart, see examples
body 'string' Buffer Stream request body
auth {user, pass} Basic authorization
oauth {object} OAuth 1.0a authorization using request-oauth, see examples
encoding 'string' response body encoding (default: 'utf8')
cookie {object} cookie store using request-cookie, see examples
redirect {object} see below

Querystring set in the url, and/or in qs and/or in form as 'string' is left untouched, meaning that the proper encoding is left to the user.

When qs and/or form is {object} the querystring is encoded using the Node's querystring module which mirrors the global encodeURIComponent method. Additionally all reserved characters according to RFC3986 are encoded as well. Full list of all reserved characters that are being encoded can be found here.

redirect

Option Default Description
max 3 maximum number of redirects to follow
all false follow non-GET HTTP 3xx responses as redirects
method true follow original HTTP method, otherwise convert all redirects to GET
auth true keep Authorization header when changing hostnames
referer false add Referer header

extend

Extend or override any of the bundled request and response middlewares:

var request = require('request-compose').extend({
  Request: {
    oauth: require('request-oauth'),
    multipart: require('request-multipart'),
    cookie: require('request-cookie').Request
  },
  Response: {cookie: require('request-cookie').Response},
}).client

Errors

Non 200/300 responses are thrown as Error object with the following properties:

  • message - status code + status message
  • res - the response object
  • body - the parsed response body
  • raw - the raw response body

Debug Logs

Fancy request-logs:

npm i --save-dev request-logs

Pick any of the following debug options:

DEBUG=req,res,body,json,nocolor node app.js

Examples

Basics

Topic Example
Types of lambda functions Get GitHub user profile
Bundled middlewares Get GitHub user profile
Wrap it up and extend it Get GitHub user profile

Compositions

Topic Example
Client Get GitHub user profile
Buffer Decoding response body using iconv-lite
Stream Stream Tweets

External Middlewares

Topic Example
OAuth (request-oauth) Get Twitter User Profile
Multipart (request-multipart) Upload photo to Twitter
Cookie (request-cookie) Login to Wallhaven.cc

Stream

Topic Example
Stream request body Upload file to Dropbox
HTTP stream Upload image from Dropbox to Slack
HTTP stream Copy file from Dropbox to GDrive

Misc

Topic Example
Gzip decompression Request Gzip compressed body
HTTPS proxy Tunnel Agent
HTTPS proxy Proxy Agent
Override bundled middleware - per compose instance Override the qs middleware
Override bundled middleware - process-wide Override the form and the parse middlewares to use the qs module

Pipeline

Topic Example
App pipeline Slack Weather Status
App pipeline Simultaneously search for repos in GitHub, GitLab and BitBucket

Modules

Topic Example
Google Chrome Web Store HTTP Client chrome-webstore
wallhaven.cc HTTP Client wallhaven-client
REST API Client Library purest
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].