Last active
February 6, 2017 19:46
-
-
Save bendman/50d5b549bf29c4ed30cd0c92c38f9763 to your computer and use it in GitHub Desktop.
Proxy `fetch` in a way that automatically handles file uploads and/or JSON parsing/serializing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fetch from './fetch-proxy.js'; | |
export async function saveImage(imageURI) { | |
return await fetch('user/picture', { | |
method: 'PUT', | |
body: { photoContent: imageURI }, | |
fileKeys: ['photoContent'], | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Proxy `fetch` in a way that automatically handles file uploads and/or JSON parsing/serializing | |
// The most important part here is the default export, `apiFetch(source, options)`. | |
const getExtension = (uri) => { | |
const fileExtension = uri.match(/[^\.]+$/); | |
if (fileExtension && fileExtension.length) { | |
return fileExtension[0]; | |
} | |
return null; | |
} | |
const getMimeType = (uri) => { | |
const mimeTypes = { | |
jpeg: 'image/jpeg', | |
jpg: 'image/jpeg', | |
png: 'image/png', | |
gif: 'image/gif', | |
pdf: 'application/pdf', | |
}; | |
const fileExtension = getExtension(uri); | |
if (fileExtension && mimeTypes.hasOwnProperty(fileExtension)) { | |
return mimeTypes[fileExtension]; | |
} | |
console.warn(`No Mime Type for file "${uri}"`); | |
return null; | |
} | |
const buildOutboundBody = ({ body, fileKeys }) => { | |
// Body needs no transformation | |
if (!body || body instanceof FormData || typeof body === 'string') return body; | |
// Body includes a file upload and must be converted to FormData | |
if (fileKeys) { | |
return Object.entries(body).reduce((formData, [key, value]) => { | |
if (fileKeys.includes(key) && value) { | |
// File value, include as data structure | |
formData.append(key, { | |
type: getMimeType(value), | |
name: `file.${getExtension(value)}`, | |
uri: value, | |
}); | |
} else if (value) { | |
// Normal value, include in the form | |
formData.append(key, value); | |
} | |
return formData; | |
}, new FormData()); | |
} | |
// Body is JSON and must be stringified | |
return JSON.stringify(body); | |
} | |
export default async function apiFetch(source, options = {}) { | |
let fetchOpts, res, resBody; | |
try { | |
const body = buildOutboundBody(options); | |
// Omit fileKeys from options sent to `fetch` | |
const { fileKeys, ...passThroughOpts } = options; | |
fetchOpts = { | |
...passThroughOpts, | |
body, | |
headers: { | |
'Accept': 'application/json', | |
'Content-Type': 'application/json', | |
...(options.headers || {}), | |
} | |
}; | |
// FormData requires a special content header | |
if (body && body instanceof FormData) fetchOpts.headers['Content-Type'] = 'multipart/form-data'; | |
res = await fetch(source, fetchOpts); | |
resBody = await res.json(); | |
if (!res.ok) { | |
throw new Error(); | |
} | |
return { data: resBody.data, msg: resBody.msg }; | |
} catch (error) { | |
// Add custom error handling here, for example attaching the response | |
throw error; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment