HTTP client for browser, a wrapper for ky
.
$ npm install @risan/http-client
You can also use the CDN directly:
<script src="https://unpkg.com/@risan/http-client@latest/dist/HttpClient.umd.js"></script>
<!-- Or the minified version -->
<script src="https://unpkg.com/@risan/http-client@latest/dist/HttpClient.umd.min.js"></script>
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json')
.then(res => console.log(res.body));
client.post('/post', { foo: 'bar' })
.then(res => console.log(res.body));
HttpClient
HttpClient()
HttpClient.request()
HttpClient.get()
HttpClient.post()
HttpClient.put()
HttpClient.patch()
HttpClient.delete()
HttpClient.setDefaultOption()
HttpClient.removeDefaultOption()
HttpClient.setDefaultHeader()
HttpClient.removeDefaultHeader()
HttpClient.setDefaultBearerToken()
HttpClient.removeDefaultBearerToken()
HttpResponse
HttpResponse.body
HttpResponse.status
HttpResponse.headers
HttpResponse.isSuccess()
HttpResponse.isError()
HttpResponse.isOk()
HttpResponse.isClientError()
HttpResponse.isServerError()
HttpResponse.isUnauthorized()
HttpResponse.isForbidden()
HttpResponse.isNotFound()
HttpResponse.isValidationError()
HttpResponse.contentType()
HttpResponse.isImage()
HttpResponse.isJson()
HttpResponse.isText()
HttpHeaders
HttpError
HttpError.message
HttpError.response
HttpError.validationErrors
HttpError.hasResponse
HttpError.hasValidationErrors
Create a new HttpClient
instance.
new HttpClient(prefixUrl: String, defaultOptions = {})
prefixUrl
(String
): A prefix to prepend to the URL when making the request.defaultOptions
(Object
): A default options to use when making the request. ThisdefaultOptions
will be merged with theoptions
parameter when making the request. Check Options for all possible configurations.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: ['application/json', 'text/plain'],
},
credentials: 'same-origin',
timeout: 10000,
onError(error) {
console.log(error.message);
throw new Error('custom error');
},
onSuccess(res) {
console.log(res.body);
return 'custom result';
},
});
The request's options are similar to fetch()
with slight differences:
headers
(Object
): Unlikefetch()
, it only accepts an object literal.credentials
(String
): Default tosame-origin
.
It also accepts similar options as ky
:
searchParams
: Search parameters to include in the request URL.retry
(Object|Number
): Maximum retry count.timeout
(Number|false
): Timeout in milliseconds for getting a response, default to10000
.hooks
(Object
): Hooks allow modifications during the request lifecycle.onDownloadProgress
(Function
): Download progress event handler.
However this library will always set the throwHttpErrors
option to true
.
This library also accepts the following options:
onError
(Function
): A callback function to call when an error response is received (status code >= 400). The function will receive anHttpError
instance as its parameter.onSuccess
(Function
): A callback function to call when a successful response is received (status code between 200-299). The function will receive anHttpResponse
instance as its parameter.responseType
(String
): Responses' body type, its theBody
's method name to call to read and parse the responses' body (arrayBuffer
,blob
,formData
,json
, ortext
). If you don't set theresponseType
, the body will be parsed based on its content-type header.errorMessagePath
(String
): A path to a custom error message in JSON response.validationErrorsPath
(String
): A path to a custom validation errors detail in JSON response.
Send HTTP request to url
with the given HTTP method
. The given options
will be merged with the previously set defaultOptions
. On successful operation, it will return a Promise
that will resolve to the HttpResponse
instance. On error, it will throw an HttpError
.
HttpClient.request(method: String, url: String, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.request('GET', '/json', {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
A shortcut method to send HTTP GET request.
HttpClient.get(url: String, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json', {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
A shortcut method to send HTTP POST request.
HttpClient.post(url: String, body = null, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.post('/post', { foo: 'bar' }, {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
A shortcut method to send HTTP PUT request.
HttpClient.put(url: String, body = null, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.put('/put', { foo: 'bar' }, {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
A shortcut method to send HTTP PATCH request.
HttpClient.patch(url: String, body = null, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.patch('/patch', { foo: 'bar' }, {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
A shortcut method to send HTTP DELETE request.
HttpClient.delete(url: String, options = {}): Promise
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.delete('/delete', {
headers: {
accept: 'application/json',
},
}).then(res => console.log(res.body));
Set a default option at key
with value
. This method returns the HttpClient
instance itself.
HttpClient.setDefaultOption(key: String, value: Any): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
mode: 'same-origin',
headers: {
accept: 'image/png',
},
});
client.setDefaultOption('mode', 'cors')
.setDefaultOption('headers.accept', ['application/json', 'text/plain']);
// {
// mode: 'cors',
// headers: {
// accept: ['application/json', 'text/plain'],
// },
// }
console.log(client.defaultOptions);
Remove a default option at key
. This method returns the HttpClient
instance itself.
HttpClient.removeDefaultOption(key: String): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
mode: 'same-origin',
credentials: 'same-origin',
headers: {
accept: ['application/json', 'text/plain'],
},
});
client.removeDefaultOption('mode')
.removeDefaultOption('headers.accept');
// {
// credentials: 'same-origin',
// headers: {},
// }
console.log(client.defaultOptions);
Set a default header at key
with value
. This method returns the HttpClient
instance itself.
HttpClient.setDefaultHeader(key: String, value: String | Array): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: 'image/png',
},
});
client.setDefaultHeader('accept', ['application/json', 'text/plain'])
.setDefaultHeader('content-type', 'application/json');
// {
// headers: {
// accept: ['application/json', 'text/plain'],
// 'content-type': 'application/json',
// },
// }
console.log(client.defaultOptions);
Remove a default header at key
. This method returns the HttpClient
instance itself.
HttpClient.removeDefaultHeader(key: String): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: 'image/png',
'content-type': 'application/json',
},
});
client.removeDefaultHeader('accept');
// {
// headers: {
// 'content-type': 'application/json',
// },
// }
console.log(client.defaultOptions);
Set a default bearer token in authorization header. This method returns the HttpClient
instance itself.
HttpClient.setDefaultBearerToken(token: String): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: 'application/json',
},
});
client.setDefaultBearerToken('secret');
// {
// headers: {
// accept: 'application/json',
// authorization: 'Bearer secret',
// },
// }
console.log(client.defaultOptions);
Remove any default authorization header. This method returns the HttpClient
instance itself.
HttpClient.removeDefaultBearerToken(): HttpClient
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: 'application/json',
authorization: 'Bearer secret',
},
});
client.removeDefaultBearerToken();
// {
// headers: {
// accept: 'application/json',
// },
// }
console.log(client.defaultOptions);
Get the responses' body.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
// If responses' content-type is application/json, response.body will be
// automatically parsed to object.
client.get('/json')
.then(res => console.log(res.body));
Get the responses' status code (Number
).
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/204')
.then(res => console.log(res.status)); // 204
Get the responses' headers (HttpHeaders
).
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json').then(res => {
console.log(res.headers.has('content-type')); // true
console.log(res.headers.get('content-type')); // application/json
console.log(res.headers['content-type']); // application/json
});
Check if the received HttpResponse
instance is successful (status code between 200-299).
HttpResponse.isSuccess(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/200')
.then(res => console.log(res.isSuccess())); // true
client.get('/status/400').then(
res => {},
error => console.log(error.response.isSuccess()) // false
);
Check if the received HttpResponse
instance is error (status code >= 400).
HttpResponse.isError(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/200')
.then(res => console.log(res.isError())); // false
client.get('/status/400').then(
res => {},
error => console.log(error.response.isError()) // true
);
Check if the status code is 200.
HttpResponse.isOk(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/200')
.then(res => console.log(res.isOk())); // true
client.get('/status/201')
.then(res => console.log(res.isOk())); // false
Check if the received HttpResponse
instance is client error (status code between 400-499).
HttpResponse.isClientError(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/401').then(
res => {},
error => console.log(error.response.isClientError()) // true
);
client.get('/status/500').then(
res => {},
error => console.log(error.response.isClientError()) // false
);
Check if the received HttpResponse
instance is server error (status code >= 500).
HttpResponse.isServerError(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/500').then(
res => {},
error => console.log(error.response.isServerError()) // true
);
client.get('/status/404').then(
res => {},
error => console.log(error.response.isServerError()) // false
);
Check if the status code is 401.
HttpResponse.isUnauthorized(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/401').then(
res => {},
error => console.log(error.response.isUnauthorized()) // true
);
client.get('/status/404').then(
res => {},
error => console.log(error.response.isUnauthorized()) // false
);
Check if the status code is 403.
HttpResponse.isForbidden(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/403').then(
res => {},
error => console.log(error.response.isForbidden()) // true
);
client.get('/status/404').then(
res => {},
error => console.log(error.response.isForbidden()) // false
);
Check if the status code is 404.
HttpResponse.isNotFound(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/404').then(
res => {},
error => console.log(error.response.isNotFound()) // true
);
client.get('/status/400').then(
res => {},
error => console.log(error.response.isNotFound()) // false
);
Check if the status code is 422.
HttpResponse.isValidationError(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/422').then(
res => {},
error => console.log(error.response.isValidationError()) // true
);
client.get('/status/400').then(
res => {},
error => console.log(error.response.isValidationError()) // false
);
Get response content-type header value.
HttpResponse.contentType(): String
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json')
.then(res => console.log(res.contentType())); // application/json
client.get('/image/png')
.then(res => console.log(res.contentType())); // image/png
Check if the response content-type header starts with image/
.
HttpResponse.isImage(): String
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/image/png')
.then(res => console.log(res.isImage())); // true
client.get('/json')
.then(res => console.log(res.isImage())); // false
Check if the response content-type header contains /json
or +json
.
HttpResponse.isJson(): String
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json')
.then(res => console.log(res.isJson())); // true
client.get('/image/png')
.then(res => console.log(res.isJson())); // false
Check if the response content-type header starts with text/
.
HttpResponse.isText(): String
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/html')
.then(res => console.log(res.isText())); // true
client.get('/json')
.then(res => console.log(res.isText())); // false
It represents the HTTP headers on the response. The HttpResponse.headers
is an instance of this class. You can access the header value by accessing the HttpHeader
property directly. Note that the property key is in lower case.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/image/png').then(res => {
console.log(res.headers['content-type']); // image/png
console.log(res.headers['content-length']); // 8090
console.log(res.headers.foo); // undefined
});
Get the header value at key
. The key
is case insensitive.
HttpHeaders.get(key: String): String | undefined
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/image/png').then(res => {
console.log(res.headers.get('content-type')); // image/png
console.log(res.headers.get('foo')); // undefined
});
Check if the header at key
exists. The key
is case insensitive.
HttpHeaders.get(key: String): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/image/png').then(res => {
console.log(res.headers.has('content-type')); // true
console.log(res.headers.has('foo')); // false
});
Get the header content-type value.
HttpHeaders.contentType(): String
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/image/png')
.then(res => console.log(res.headers.contentType())); // image/png
The HttpError
instance will be thrown when request failed or the error response is received (status code >= 400).
The error mesage.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/foo').then(
res => {},
error => console.log(error.message) // Failed to fetch
);
The HttpResponse
instance. If there's no response, this property will have null
value.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/400').then(
res => {},
error => console.log(error.response) // HttpResponse instance
);
client.get('/foo').then(
res => {},
error => console.log(error.response) // null
);
The validation errors object. It will only be available if the status code is 422 and the given validationErrorsPath
exists in the response JSON.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('http://www.mocky.io/v2', {
validationErrorsPath: 'errors',
});
// http://www.mocky.io/v2/5e4ffabc3000005100226d1c
// {
// "message": "Custom error",
// "errors": {
// "email": ["error1", "error2"]
// }
// }
client.get('/5e4ffabc3000005100226d1c').then(
res => {},
error => console.log(error.validationErrors) // { email: ["error1", "error2"] }
);
Check if the error has HttpResponse
instance.
HttpError.hasResponse(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/status/400').then(
res => {},
error => console.log(error.hasResponse()) // true
);
client.get('/foo').then(
res => {},
error => console.log(error.hasResponse()) // false
);
Check if the validationErrors
property is not empty.
HttpError.hasValidationErrors(): Boolean
import HttpClient from '@/risan/http-client';
const client = new HttpClient('http://www.mocky.io/v2', {
validationErrorsPath: 'errors',
});
// http://www.mocky.io/v2/5e4ffabc3000005100226d1c
// {
// "message": "Custom error",
// "errors": {
// "email": ["error1", "error2"]
// }
// }
client.get('/5e4ffabc3000005100226d1c').then(
res => {},
error => console.log(error.hasValidationErrors()) // true
);
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org', {
headers: {
accept: 'application/json',
},
});
client.get('/json')
.then(res => console.log(res.body));
// Override default accept headers.
client.get('/html', {
headers: {
accept: 'text/html',
},
}).then(res => console.log(res.body));
If you don't set any header content-type, the body
with object literal will be sent as JSON. The header content-type will also be set to application/json
.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.post('/post', { id: 123, name: 'john' })
.then(res => console.log(res.body));
To send a URL encoded body, all you have to do is set the header content-type to application/x-www-form-urlencoded
.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.post('/post', { id: 123, name: 'john' }, {
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
}).then(res => console.log(res.body));
Or you can also pass the URLSearchParams
instance as the body.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
const searchParams = new URLSearchParams();
searchParams.set('id', 123);
searchParams.set('name', 'john');
client.post('/post', searchParams)
.then(res => console.log(res.body));
To send a multipart form data body, all you have to do is set the header content-type to multipart/form-data
.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.post('/post', { id: 123, name: 'john' }, {
headers: {
'content-type': 'multipart/form-data',
},
}).then(res => console.log(res.body));
Or you can also pass the FormData
instance as the body.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
const formData = new FormData();
formData.append('id', 123);
formData.append('name', 'john');
client.post('/post', formData)
.then(res => console.log(res.body));
By default, the error message in HttpError
is coming from the HTTP status text in the received response. If the received error response is in JSON, you may pass the errorMessagePath
option to retrieve the error message from the responses' body. You may pass it as a defaultOptions
or as options
at each request.
import HttpClient from '@/risan/http-client';
const client = new HttpClient('http://www.mocky.io/v2', {
errorMessagePath: 'message',
});
// http://www.mocky.io/v2/5e4ffabc3000005100226d1c
// {
// "message": "Custom error",
// ...
// }
client.get('/5e4ffabc3000005100226d1c').then(
res => {},
error => console.log(error.message) // Custom error
);
If the error message is deeply nested, you can use dot notation.
// {
// "data": {
// "message": "Custom error",
// }
// }
client.get('/5e4ffabc3000005100226d1c', { errorMessagePath: 'data.message' }).then(
res => {},
error => console.log(error.message)
);
You might be using an API that returns 200 status code even if there's an error. To handle this kind of case, you may pass the onSuccess
callback and throws an error if the received response is an error.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json', {
onSuccess(res) {
if (res.body.status !== true) {
throw new Error('Status code 200 but throws error');
}
},
}).then(
res => {},
error => console.error(error.message)
);
By default this library will read and parsed the responses' body based on its header content-type:
- Content-type that contains
/json
or+json
will be parsed as JSON object. - Content-type that starts with
text/
will be parsed as text. - Content-type that starts with
image/
will be parsed as a blob.
However, you may override this behavior by passing the responseType
parameter. You may pass: arrayBuffer
, blob
, formData
, json
, or text
.
import HttpClient from '@risan/http-client';
const client = new HttpClient('https://httpbin.org');
client.get('/json', { responseType: 'blob' })
.then(res => console.log(res.body));