| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 |
1x
1x
1x
1x
1x
4x
| /**
* @name Request
* @description This module handles the HTTP requests to Pagar.me's API. '
* It exports GET, PUT, POST, DELETE functions based upon
* the `fetch` module.
*
* @module request
* @private
*/
import Promise from 'bluebird'
import {
merge,
mergeAll,
length,
keys,
} from 'ramda'
import qs from 'qs'
import routes from './routes'
import ApiError from './errors'
require('isomorphic-fetch')
const version = typeof PAGARME_VERSION !== 'undefined' ? PAGARME_VERSION : ''
const defaultHeaders = {
'Content-Type': 'application/json',
'X-PagarMe-User-Agent': `pagarme-js/${version}`,
}
const isBrowser = typeof window !== 'undefined'
&& ({}).toString.call(window) === '[object Window]'
const mergeWithDefaultHeaders = (headers) => {
if (isBrowser && window.navigator) {
const userAgent = window.navigator.userAgent
? `${window.navigator.userAgent} `
: ''
const customAgentHeaders = {
'User-Agent': `${userAgent}pagarme-js/${version}`,
'X-PagarMe-User-Agent': `${userAgent}pagarme-js/${version}`,
}
return mergeAll([headers, defaultHeaders, customAgentHeaders])
}
return merge(headers, defaultHeaders)
}
/**
* This method builds the final method, body and headers
* that will be used in `fetch`.
*
* @param {String} method
* @param {String} endpoint
* @param {Object} options
* @param {Object} data
* @returns {Object} An object containing a URL property
* and an object in the form of
* `{ method, body, headers }`
* @private
*/
function buildRequestParams (method, endpoint, options, data) {
let query = ''
let body = ''
let params = null
let headers = options.headers || {}
const payload = merge(
options.body || {},
data || {}
)
const queries = options.qs || {}
if (length(keys(queries))) {
query = `${qs.stringify(queries)}`
}
const shouldStringifyPayload = ['GET', 'HEAD'].includes(method)
const requestHasBody = !['GET', 'HEAD'].includes(method)
if (shouldStringifyPayload) {
const qsOptions = merge({ encode: false }, options.qsOptions)
query += `${query ? '&' : ''}${qs.stringify(payload, qsOptions)}`
params = {
method,
headers,
}
}
if (requestHasBody) {
body = JSON.stringify(payload)
headers = mergeWithDefaultHeaders(headers)
params = {
method,
body,
headers,
}
}
const url = `${endpoint}${query ? `?${query}` : ''}`
return {
url,
params,
}
}
/**
* This function handles the request erros,
* returning a Promise that will reject to
* a custom ApiError with a relevant message.
*
* @param {Object} response
* @returns {Promise} A Promise rejection with a
* Server Error message or the
* error response body
* @private
*/
function handleError (response) {
if (response.status === 500) {
return Promise.reject(
new ApiError({
status: 500,
errors: [{ message: 'Pagar.me server error' }],
})
)
}
return response.json()
.then(body => Promise.reject(
new ApiError(merge(body, { status: response.status }))
))
}
/**
* This simple function handles the result of a
* request, returning either a JSON response
* or forwarding the error handling to another
* function.
*
* @param {Object} response
* @returns {Promise} A promise that will either
* resolve to the Response JSON
* conversion or further the chain to
* [handleError]{@link handleError}
* @private
*/
function handleResult (response) {
const contentType = response.headers.get('Content-Type')
if (response.ok) {
if (contentType.includes('application/json')) {
return response.json()
}
if (contentType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|| contentType === 'application/pdf') {
return response.arrayBuffer()
}
return response.text()
}
return handleError(response)
}
/**
* This function returns a new function,
* created from the supplied `method`.
* The returned function uses
* [buildRequestParams]{@link buildRequestParams}
* to define the request's URL, headers and body.
*
* @param {String} method
* @returns {Function} A `request` function that
* will return a Promise with
* the server response
* @private
*/
function buildRequest (method) {
return function request (options = {}, path, body = {}) {
const endpoint = (options.baseURL || routes.base) + path
const { url, params } = buildRequestParams(method, endpoint, options, body)
return fetch(url, params).then(handleResult)
}
}
export default {
get: buildRequest('GET'),
put: buildRequest('PUT'),
post: buildRequest('POST'),
delete: buildRequest('DELETE'),
}
|