Skip to content

Commit

Permalink
v1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ejnshtein committed May 10, 2020
1 parent e04e9e3 commit 980b8b7
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 169 deletions.
140 changes: 0 additions & 140 deletions Request.cjs

This file was deleted.

138 changes: 136 additions & 2 deletions Request.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,137 @@
import request from './Request.cjs'
// docs: https://nodejs.org/dist/latest-v10.x/docs/api/https.html#https_https_request_url_options_callback
const qs = require('querystring')
const https = require('https')
const http = require('http')
const fs = require('fs')
const { createUnzip } = require('zlib')
const { cleanObject, mergeUrl, isBlob, deepmerge } = require('./lib')
const pkg = JSON.parse(fs.readFileSync('./package.json'))
const nativeRequestKeys = ['agent', 'auth', 'createConnection', 'defaultPort', 'family', 'headers', 'host', 'hostname', 'insecureHTTPParser', 'localAddress', 'lookup', 'maxHeaderSize', 'method', 'path', 'port', 'protocol', 'setHost', 'socketPath', 'timeout']

export default request
module.exports = function smolrequest (url, options = {}, formData = null) {
const [body, dataIsObject] = Object.prototype.toString.call(formData) === '[object Object]' ? [qs.stringify(formData), true] : [formData, false]
const mergedOptions = [
{
method: 'GET',
responseType: 'text',
headers: {
'User-Agent': `smol-request/${pkg.version}`,
Accept: '*/*'
}
}
]
if (dataIsObject && body) {
mergedOptions.push(
{ headers: { 'Content-Length': Buffer.byteLength(body) } }
)
}
if (dataIsObject && typeof body === 'string') {
mergedOptions.push({
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
}
mergedOptions.push(options)
if (options.responseType && options.responseType === 'buffer') {
mergedOptions.push(
{ headers: { 'Content-Type': 'application/octet-stream' } }
)
}
const requestOptions = deepmerge(...mergedOptions)
if (requestOptions.params && typeof requestOptions.params === 'object') {
url = mergeUrl(url, requestOptions.params)
}
return new Promise((resolve, reject) => {
const client = url.startsWith('https') ? https : http
let resolved = false
const result = {
data: null,
headers: null,
status: null,
statusText: null
}
const cleanRequestOptions = cleanObject(requestOptions, nativeRequestKeys)
const req = client.request(
url,
cleanRequestOptions
)
req.on('error', onError)
req.on('response', onResponse)
req.on('close', onClose)
if (requestOptions.headers) {
Object.entries(requestOptions.headers)
.forEach(([name, value]) => req.setHeader(name, value))
}
function onClose () {
if (resolved) {
return
}
switch (requestOptions.responseType) {
case 'buffer': {
result.data = Buffer.concat(result.data)
break
}
case 'json': {
try {
result.data = JSON.parse(result.data.join(''))
} catch (e) {
return reject(new Error(`JSON parsing error: ${e.message}: ${result.data}`))
}
break
}
default: {
result.data = result.data.join('')
break
}
}
resolve(result)
}
function onError (err) {
req.removeListener('error', onError)
reject(err)
}
function onResponse (res) {
result.headers = res.headers
result.status = res.statusCode
result.statusText = res.statusMessage
if (requestOptions.responseType === 'headers') {
resolved = true
return resolve(result)
}
const stream = ['gzip', 'compress', 'deflate'].includes(res.headers['content-encoding']) && res.statusCode === 204
? res.pipe(createUnzip())
: res
if (requestOptions.responseType === 'stream') {
result.data = stream
resolved = true
return resolve(result)
}
// stream.setEncoding('utf8')
const responseData = []
const onData = chunk => { responseData.push(requestOptions.responseType === 'buffer' ? Buffer.from(chunk) : chunk) }
const onError = err => {
stream.removeListener('error', onError)
stream.removeListener('data', onData)
reject(err)
}
const onRequestEnd = () => {
stream.removeListener('error', onError)
stream.removeListener('data', onData)
stream.removeListener('end', onRequestEnd)
result.data = responseData
}
stream.on('data', onData)
stream.on('error', onError)
stream.on('end', onRequestEnd)
}
if (body === null || !body) {
req.end()
} else if (isBlob(body)) {
body.stream().pipe(req)
} else if (Buffer.isBuffer(body) || typeof body === 'string') {
req.write(body)
req.end()
} else {
body.pipe(req)
}
})
}
File renamed without changes.
File renamed without changes.
11 changes: 0 additions & 11 deletions lib/index.cjs

This file was deleted.

11 changes: 11 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const cleanObject = require('./clean-object')
const mergeUrl = require('./merge-url')
const deepmerge = require('./deepmerge')
const isBlob = require('./is-blob')

module.exports = {
cleanObject,
mergeUrl,
deepmerge,
isBlob
}
File renamed without changes.
File renamed without changes.
12 changes: 4 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
{
"name": "@ejnshtein/smol-request",
"version": "1.1.0",
"description": "Tiny http/https request wrapper for Node.js 10+ (Version 13.5 and newer supports ESM)",
"type": "module",
"main": "Request.cjs",
"exports": {
"import": "./Request.js",
"require": "./Request.cjs"
},
"version": "1.1.1",
"description": "Tiny http/https request wrapper for Node.js 10 and newer",
"type": "commonjs",
"main": "Request.js",
"scripts": {},
"repository": {
"type": "git",
Expand Down
10 changes: 2 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
[![npm downloads](https://img.shields.io/npm/dm/@ejnshtein/smol-request.svg?style=flat-square)](http://npm-stat.com/charts.html?package=@ejnshtein/smol-request)
[![install size](https://packagephobia.now.sh/badge?p=@ejnshtein/smol-request)](https://packagephobia.now.sh/result?p=@ejnshtein/smol-request)

Small async request client for Node.js 10.20.x+ and newer with 0 dependencies (And ESM support for Node 13.5+).
Mostly meant to be used as an http layer for some API library.
Small async request client for Node.js 10+ and newer with 0 dependencies.

# Install

Expand All @@ -16,13 +15,8 @@ Mostly meant to be used as an http layer for some API library.
### JSON

```js
// import with esm
import request from '@ejnshtein/smol-request'

// or commonjs

const request = require('@ejnshtein/smol-request')

request('https://ghibliapi.herokuapp.com/films', { responseType: 'json' })
.then(({ data }) => {
console.log(`Studio Ghibli has ${response.data.length} movies out there!`)
Expand All @@ -35,7 +29,7 @@ request('https://ghibliapi.herokuapp.com/films', { responseType: 'json' })
request('https://bbc.com')
.then(({ data }) => {
// bbc page is too big to log it to console, but we can save it to the drive!
fs.promises.writeFile('./bbc.html', data) // we are using only Node 13.5 and newer and promises are stable here
fs.promises.writeFile('./bbc.html', data)
.then(() => {
console.log('bbc page saved!')
})
Expand Down

0 comments on commit 980b8b7

Please sign in to comment.