Skip to content

Commit

Permalink
Make the response object configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed Jul 8, 2016
1 parent 898f3b6 commit c180f08
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 46 deletions.
22 changes: 16 additions & 6 deletions lib/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export default class Base {
return headers
}

set (name: string, value?: string | string[]): Base {
set (name: string, value?: string | string[]): this {
this.remove(name)
this.append(name, value)

Expand Down Expand Up @@ -168,15 +168,25 @@ export default class Base {

get (name: string): string {
const lowered = lowerHeader(name)
let value: string

for (let i = 0; i < this.rawHeaders.length; i += 2) {
if (lowerHeader(this.rawHeaders[i]) === lowered) {
value = value == null ? this.rawHeaders[i + 1] : `${value}, ${this.rawHeaders[i + 1]}`
return this.rawHeaders[i + 1]
}
}
}

getAll (name: string): string[] {
const lowered = lowerHeader(name)
const result: string[] = []

for (let i = 0; i < this.rawHeaders.length; i += 2) {
if (lowerHeader(this.rawHeaders[i]) === lowered) {
result.push(this.rawHeaders[i + 1])
}
}

return value
return result
}

remove (name: string) {
Expand All @@ -193,8 +203,8 @@ export default class Base {
}

type (): string
type (value: string): Base
type (value?: string): any {
type (value: string): this
type (value?: string): string | this {
if (arguments.length === 0) {
return type(this.get('Content-Type'))
}
Expand Down
8 changes: 4 additions & 4 deletions lib/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { defaults as use } from './plugins/index'
*/
export { open, abort, use }

function open (request: Request) {
function open (request: Request<Response>) {
return new Promise(function (resolve, reject) {
const { url, method } = request
const responseType = request.options.responseType
Expand All @@ -22,13 +22,13 @@ function open (request: Request) {
const xhr = request._raw = new XMLHttpRequest()

function done () {
return resolve({
return resolve(new Response({
status: xhr.status === 1223 ? 204 : xhr.status,
statusText: xhr.statusText,
rawHeaders: parseToRawHeaders(xhr.getAllResponseHeaders()),
body: responseType ? xhr.response : xhr.responseText,
url: xhr.responseURL
})
}))
}

xhr.onload = done
Expand Down Expand Up @@ -94,7 +94,7 @@ function open (request: Request) {
/**
* Close the current HTTP request.
*/
function abort (request: Request) {
function abort (request: Request<Response>) {
request._raw.abort()
}

Expand Down
6 changes: 3 additions & 3 deletions lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import * as transport from './index'
/**
* Generate a default popsicle instance.
*/
export function defaults (defaultsOptions: DefaultsOptions) {
export function defaults <T extends Response> (defaultsOptions: DefaultsOptions<T>) {
const defaults = extend({ transport }, defaultsOptions)

return function popsicle (options: RequestOptions | string): Request {
let opts: RequestOptions
return function popsicle (options: RequestOptions<T> | string): Request<T> {
let opts: RequestOptions<T>

if (typeof options === 'string') {
opts = extend(defaults, { url: options })
Expand Down
4 changes: 2 additions & 2 deletions lib/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import Request from './request'
export default class PopsicleError extends makeErrorCause.BaseError {

code: string
popsicle: Request
popsicle: Request<any>
name = 'PopsicleError'

constructor (message: string, code: string, original: Error, popsicle: Request) {
constructor (message: string, code: string, original: Error, popsicle: Request<any>) {
super(message, original)

this.code = code
Expand Down
14 changes: 7 additions & 7 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { request as httpRequest, IncomingMessage } from 'http'
import { request as httpsRequest } from 'https'
import { request as httpsRequest, RequestOptions } from 'https'
import { PassThrough } from 'stream'
import urlLib = require('url')
import extend = require('xtend')
Expand Down Expand Up @@ -40,7 +40,7 @@ const REDIRECT_STATUS: { [status: number]: number } = {
/**
* Open a HTTP request with node.
*/
function open (request: Request) {
function open (request: Request<Response>) {
const { url, method, body, options } = request
const maxRedirects = num(options.maxRedirects, 5)
const followRedirects = options.followRedirects !== false
Expand Down Expand Up @@ -136,14 +136,14 @@ function open (request: Request) {

rawResponse.pipe(responseStream)

return Promise.resolve({
return Promise.resolve(new Response({
body: responseStream,
status: status,
statusText: rawResponse.statusMessage,
headers: rawResponse.headers,
rawHeaders: rawResponse.rawHeaders,
url: url
})
}))
}

// Emit a request error.
Expand Down Expand Up @@ -187,7 +187,7 @@ function open (request: Request) {
/**
* Close the current HTTP request.
*/
function abort (request: Request) {
function abort (request: Request<Response>) {
request._raw.abort()
}

Expand All @@ -212,7 +212,7 @@ function falsey () {
/**
* Read cookies from the cookie jar.
*/
function getAttachCookies (request: Request): (url: string) => Promise<any> {
function getAttachCookies (request: Request<Response>): (url: string) => Promise<any> {
const { jar } = request.options
const cookie = request.get('Cookie')

Expand Down Expand Up @@ -242,7 +242,7 @@ function getAttachCookies (request: Request): (url: string) => Promise<any> {
/**
* Put cookies in the cookie jar.
*/
function getStoreCookies (request: Request): (url: string, message: IncomingMessage) => Promise<any> {
function getStoreCookies (request: Request<Response>): (url: string, message: IncomingMessage) => Promise<any> {
const { jar } = request.options

if (!jar) {
Expand Down
6 changes: 3 additions & 3 deletions lib/plugins/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function wrap <T> (value: T): () => T {
/**
* Remove default headers.
*/
export const headers = wrap(function (request: Request, next: () => Promise<Response>) {
export const headers = wrap(function (request: Request<any>, next: () => Promise<Response>) {
// If we have no accept header set already, default to accepting
// everything. This is needed because otherwise Firefox defaults to
// an accept header of `html/xml`.
Expand All @@ -37,7 +37,7 @@ export const headers = wrap(function (request: Request, next: () => Promise<Resp
/**
* Stringify the request body.
*/
export const stringify = wrap(function (request: Request, next: () => Promise<Response>) {
export const stringify = wrap(function (request: Request<any>, next: () => Promise<Response>) {
const { body } = request

// Convert primitives types into strings.
Expand Down Expand Up @@ -85,7 +85,7 @@ export const stringify = wrap(function (request: Request, next: () => Promise<Re
/**
* Automatic stringification and parsing middleware.
*/
export const parse = wrap(function (request: Request, next: () => Promise<Response>) {
export const parse = wrap(function (request: Request<any>, next: () => Promise<Response>) {
return next()
.then(function (response) {
const { body } = response
Expand Down
6 changes: 3 additions & 3 deletions lib/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Response from '../response'
/**
* Support gzipped responses.
*/
export const unzip = wrap(function (request: Request, next: () => Promise<Response>) {
export const unzip = wrap(function (request: Request<any>, next: () => Promise<Response>) {
if (!request.get('Accept-Encoding')) {
request.set('Accept-Encoding', 'gzip,deflate')
}
Expand All @@ -34,7 +34,7 @@ export const unzip = wrap(function (request: Request, next: () => Promise<Respon
* compatibility (and honestly just making it easier to use).
*/
export function concatStream (encoding: string) {
return function (request: Request, next: () => Promise<Response>) {
return function (request: Request<any>, next: () => Promise<Response>) {
return next()
.then(function (response) {
return new Promise(function (resolve, reject) {
Expand All @@ -57,7 +57,7 @@ export function concatStream (encoding: string) {
export function headers () {
const common = commonHeaders()

return function (request: Request, next: () => Promise<Response>) {
return function (request: Request<any>, next: () => Promise<Response>) {
// Set up common headers.
return common(request, function () {
// Specify a default user agent in node.
Expand Down
33 changes: 15 additions & 18 deletions lib/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import Base, { BaseOptions, Headers } from './base'
import Response, { ResponseOptions } from './response'
import PopsicleError from './error'

export interface DefaultsOptions extends BaseOptions {
export interface DefaultsOptions <T extends Response> extends BaseOptions {
url?: string
method?: string
timeout?: number
body?: any
options?: any
use?: Middleware[]
progress?: ProgressFunction[]
transport?: TransportOptions
transport?: TransportOptions<T>
}

export interface RequestOptions extends DefaultsOptions {
export interface RequestOptions <T extends Response> extends DefaultsOptions<T> {
url: string
}

Expand All @@ -30,24 +30,21 @@ export interface RequestJSON {
method: string
}

export interface TransportOptions {
open: OpenHandler
abort?: AbortHandler
export interface TransportOptions <T extends Response> {
open: (request: Request<T>) => Promise<T>
abort?: (request: Request<T>) => any
use?: Middleware[]
}

export type Middleware = (request: Request, next: () => Promise<Response>) => Response | Promise<Response>
export type ProgressFunction = (request: Request) => any
export type Middleware = (request: Request<any>, next: () => Promise<Response>) => Response | Promise<Response>
export type ProgressFunction = (request: Request<any>) => any

export type OpenHandler = (request: Request) => Promise<ResponseOptions>
export type AbortHandler = (request: Request) => any

export default class Request extends Base implements Promise<Response> {
export default class Request <T extends Response> extends Base implements Promise<T> {
method: string
timeout: number
body: any
options: any
transport: TransportOptions
transport: TransportOptions<T>
middleware: Middleware[] = []

opened = false
Expand All @@ -64,7 +61,7 @@ export default class Request extends Base implements Promise<Response> {
private _resolve: (response: Response) => void
private _reject: (error: Error) => void

constructor (options: RequestOptions) {
constructor (options: RequestOptions<T>) {
super(options)

this.timeout = (options.timeout | 0)
Expand Down Expand Up @@ -104,21 +101,21 @@ export default class Request extends Base implements Promise<Response> {
return new PopsicleError(message, code, original, this)
}

then (onFulfilled: (response?: Response) => any, onRejected?: (error?: PopsicleError) => any) {
then (onFulfilled: (response?: T) => any, onRejected?: (error?: PopsicleError) => any) {
return this._promise.then(onFulfilled, onRejected)
}

catch (onRejected: (error?: PopsicleError) => any) {
return this._promise.then(null, onRejected)
}

exec (cb: (err: PopsicleError, response?: Response) => any) {
exec (cb: (err: PopsicleError, response?: T) => any) {
this.then(function (response) {
cb(null, response)
}, cb)
}

toOptions (): RequestOptions {
toOptions (): RequestOptions<T> {
return {
url: this.url,
method: this.method,
Expand Down Expand Up @@ -229,7 +226,7 @@ export default class Request extends Base implements Promise<Response> {
// Proxy the transport promise into the current request.
return this.transport.open(this)
.then(
res => this._resolve(new Response(res)),
res => this._resolve(res),
err => this._reject(err)
)
}
Expand Down

0 comments on commit c180f08

Please sign in to comment.