Skip to content

Instantly share code, notes, and snippets.

@zeraphie
Last active May 14, 2018 14:11
Show Gist options
  • Save zeraphie/547aa3b7ebbe6221df5e4e4fb4ca6e7f to your computer and use it in GitHub Desktop.
Save zeraphie/547aa3b7ebbe6221df5e4e4fb4ca6e7f to your computer and use it in GitHub Desktop.
A fetch wrapper that takes the same parameters and formats the fetch request for you
export default class SuperFetch {
constructor(url, data, params = {}){
this.url = url;
this.data = data;
this.params = params;
}
/**
* Send a get request using the fetch api
*
* @returns {Promise<Response>}
*/
async get(){
let url = this.url;
if(this.constructor.isObject(this.data)){
if(this.data instanceof FormData){
let parsed = {};
[...this.data.keys()].map(key => parsed[key] = this.data.get(key));
url += '?' + this.constructor.queryParameters(parsed);
} else {
url += '?' + this.constructor.queryParameters(this.data);
}
}
return await fetch(url, this.mergeParams({
method: 'GET'
}));
}
/**
* Send a post request using the fetch api
*
* @returns {Promise<Response>}
*/
async post(){
if(this.constructor.isObject(this.data)){
if(this.data instanceof FormData){
this.params.body = this.data;
} else {
this.params.body = JSON.stringify(this.data);
}
}
return await fetch(this.url, this.mergeParams({
method: 'POST'
}));
}
/**
* Send a put request using the fetch api
*
* @returns {Promise<Response>}
*/
async put(){
if(this.constructor.isObject(this.data)){
if(this.data instanceof FormData){
this.data.append('_method', 'PUT');
this.params.body = this.data;
} else {
this.data['_method'] = 'PUT';
this.params.body = JSON.stringify(this.data);
}
}
return await fetch(this.url, this.mergeParams({
method: 'POST'
}));
}
/**
* Send a patch request using the fetch api
*
* @returns {Promise<Response>}
*/
async patch(){
if(this.constructor.isObject(this.data)){
if(this.data instanceof FormData){
this.data.append('_method', 'PATCH');
this.params.body = this.data;
} else {
this.data['_method'] = 'PATCH';
this.params.body = JSON.stringify(this.data);
}
}
return await fetch(this.url, this.mergeParams({
method: 'POST'
}));
}
/**
* Send a delete request using the fetch api
*
* @returns {Promise<Response>}
*/
async delete(){
return await fetch(this.url, this.mergeParams({
method: 'DELETE'
}));
}
/**
* Send a get request using the fetch api and convert the response to text
*
* @param method
* @returns {Promise<*>}
*/
async text(method = 'GET'){
if(method === 'GET'){
let got = await this.get();
return await got.text();
}
if(method === 'POST'){
let posted = await this.post();
return await posted.text();
}
return Promise.reject('Bad Method: ' + method);
}
/**
* Send a get request using the fetch api and convert the response to json
*
* @param method
* @returns {Promise<*>}
*/
async json(method = 'GET'){
if(method === 'GET'){
let got = await this.get();
return await got.json();
}
if(method === 'POST'){
let posted = await this.post();
return await posted.json();
}
return Promise.reject('Bad Method: ' + method);
}
/**
* Override the parameters
*
* @param overrides
* @returns {{}}
*/
mergeParams(overrides){
// Only allow same origin
const unchangeable = {
mode: 'same-origin',
credentials: 'same-origin'
};
// Add the token if it's present for post requests
const token = this.constructor.getToken();
if(token){
unchangeable.headers = new Headers({
'X-CSRF-TOKEN': this.constructor.getToken(),
});
}
// Return a combined params object
return {
...this.params,
...overrides,
...unchangeable,
};
}
/**
* Get the csrf token on the page or return false if not found
*
* @returns {*}
*/
static getToken(){
// Typical csrf token elements (present in laravel)
const metaTokenElement = document.querySelector('meta[name="csrf-token"]');
const inputTokenElement = document.querySelector('input[name="_token"]');
if(metaTokenElement){
return metaTokenElement.getAttribute('content');
}
if(inputTokenElement){
return inputTokenElement.value;
}
return false;
}
/**
* Convert an object into query string
*
* @param obj
* @returns {string}
*/
static queryParameters(obj){
return Object.keys(obj).map(
p => encodeURIComponent(p) + '=' + encodeURIComponent(obj[p])
).join('&');
}
/**
* Test if the thing is an object
*
* @param thing
* @returns {boolean}
*/
static isObject(thing){
if(thing === null){
return false;
}
return ((typeof thing === 'function') || (typeof thing === 'object'));
}
}
@zeraphie
Copy link
Author

zeraphie commented May 9, 2018

Example Usage

Getting a response from a webpage using an object

let req = await new SuperFetch('/some-url', {
    hey: "I'm Awesome",
    index: 1
}).get();

// Makes a get request to '/some-url?hey=I'm%20Awesome&index=1'

Getting a response from a webpage using an object

let form = document.querySelector('form');
let req = await new SuperFetch('/some-url', new FormData(form)).get();

// Makes a get request to '/some-url' with the query parameters being all the values in the form

Updating a field on a resource using an object

let req = await new SuperFetch('/some-url-to-post-to', {
    change: true
}).patch();

// Makes a post request to '/some-url-to-post-to' updating the field change to true

Updating a field on a resource using FormData

let form = document.querySelector('form');
let req = await new SuperFetch('/some-url-to-post-to', new FormData(form)).patch();

// Makes a post request to '/some-url-to-post-to' updating any fields in the form

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment