UNPKG

oxe

Version:

A mighty tiny web components framework/library

181 lines (144 loc) 6.14 kB
type FetcherOption = { path?: string; method?: string; origin?: string; headers?: object; acceptType?: string; credentials?: string; contentType?: string; responseType?: string; before?: (option: FetchOption) => any; after?: (option: FetchOption) => any; }; type FetchOption = FetcherOption & { body?: any; url?: string; aborted?: boolean; }; export default new class Fetcher { option: FetcherOption = {}; readonly types = [ 'json', 'text', 'blob', 'formData', 'arrayBuffer' ]; readonly mime = { xml: 'text/xml; charset=utf-8', html: 'text/html; charset=utf-8', text: 'text/plain; charset=utf-8', json: 'application/json; charset=utf-8', js: 'application/javascript; charset=utf-8' }; async setup (option: FetcherOption = {}) { this.option.path = option.path; this.option.method = option.method; this.option.origin = option.origin; this.option.before = option.before; this.option.headers = option.headers; this.option.after = option.after; this.option.acceptType = option.acceptType; this.option.credentials = option.credentials; this.option.contentType = option.contentType; this.option.responseType = option.responseType; } async method (method: string, data?: string | object) { data = typeof data === 'string' ? { url: data } : data; return this.fetch({ ...data, method }); } async get () { return this.method('get', ...arguments); } async put () { return this.method('put', ...arguments); } async post () { return this.method('post', ...arguments); } async head () { return this.method('head', ...arguments); } async patch () { return this.method('patch', ...arguments); } async delete () { return this.method('delete', ...arguments); } async options () { return this.method('options', ...arguments); } async connect () { return this.method('connect', ...arguments); } async serialize (data) { let query = ''; for (const name in data) { query = query.length > 0 ? query + '&' : query; query = query + encodeURIComponent(name) + '=' + encodeURIComponent(data[ name ]); } return query; } async fetch (data: FetchOption = {}) { const { option } = this; const context = { ...option, ...data }; if (context.path && typeof context.path === 'string' && context.path.charAt(0) === '/') context.path = context.path.slice(1); if (context.origin && typeof context.origin === 'string' && context.origin.charAt(context.origin.length - 1) === '/') context.origin = context.origin.slice(0, -1); if (context.path && context.origin && !context.url) context.url = context.origin + '/' + context.path; if (!context.method) throw new Error('Oxe.fetcher.fetch - requires method option'); if (!context.url) throw new Error('Oxe.fetcher.fetch - requires url or origin and path option'); context.aborted = false; context.headers = context.headers || {}; context.method = context.method.toUpperCase(); Object.defineProperty(context, 'abort', { enumerable: true, value () { context.aborted = true; return context; } }); if (context.contentType) { switch (context.contentType) { case 'js': context.headers[ 'Content-Type' ] = this.mime.js; break; case 'xml': context.headers[ 'Content-Type' ] = this.mime.xml; break; case 'html': context.headers[ 'Content-Type' ] = this.mime.html; break; case 'json': context.headers[ 'Content-Type' ] = this.mime.json; break; default: context.headers[ 'Content-Type' ] = context.contentType; } } if (context.acceptType) { switch (context.acceptType) { case 'js': context.headers[ 'Accept' ] = this.mime.js; break; case 'xml': context.headers[ 'Accept' ] = this.mime.xml; break; case 'html': context.headers[ 'Accept' ] = this.mime.html; break; case 'json': context.headers[ 'Accept' ] = this.mime.json; break; default: context.headers[ 'Accept' ] = context.acceptType; } } if (typeof option.before === 'function') await option.before(context); if (context.aborted) return; if (context.body) { if (context.method === 'GET') { context.url = context.url + '?' + await this.serialize(context.body); // } else if (context.contentType === 'json') { } else if (typeof context.body === 'object') { context.body = JSON.stringify(context.body); } } const result = await window.fetch(context.url, (context as any)); Object.defineProperties(context, { result: { enumerable: true, value: result }, code: { enumerable: true, value: result.status } // headers: { enumerable: true, value: result.headers } // message: { enumerable: true, value: result.statusText } }); const responseType = context.responseType === 'buffer' ? 'arrayBuffer' : context.responseType || ''; const contentType = result.headers.get('content-type') || result.headers.get('Content-Type') || ''; let type: string; if (responseType) type = responseType; else if (contentType.includes('application/json')) type = 'json'; else if (contentType.includes('text/plain')) type = 'text'; if (!this.types.includes(type)) throw new Error('Oxe.fetcher.fetch - invalid responseType'); context.body = await result[ type ](); if (typeof option.after === 'function') await option.after(context); if (context.aborted) return; return context; } };