import { Deserializer, Serializer } from '../core/storage' const CREATED = 201 const NO_CONTENT = 204 const NOT_FOUND = 404 const GONE = 410 export default class RemoteStorage { constructor( private readonly baseUrl: string, private readonly getItemId = item => item['id'], private readonly serializers: Map = new Map([ ['*/*', JSON.stringify], ['application/json', JSON.stringify], ['text/json', JSON.stringify], ]), private readonly deserializers: Map = new Map([ ['*/*', JSON.parse], ['application/json', JSON.parse], ['text/json', JSON.parse], ]), ) {} async getCollection(collectionId: string) { const response = await window.fetch([this.baseUrl, collectionId].join('/')) const contentType = response.headers.get('content-type') const { [contentType]: deserializer = this.deserializers.get('*/*'), } = Object.fromEntries(this.deserializers.entries()) const payload = await response.text() return deserializer(payload) } async setItem(collectionId: string, item: U, contentType = 'application/json') { const { [contentType]: serializer = this.serializers.get('application/json'), } = Object.fromEntries(this.serializers.entries()) const response = await window.fetch([this.baseUrl, collectionId, this.getItemId(item)].join('/'), { method: 'put', body: serializer(item), }) // resource is created if (response.status === CREATED) { return } if (100 <= response.status && response.status <= 399) { console.warn(`Expected response is ${CREATED}, got ${response.status}.`) return } throw new Error(response.statusText) } async removeItem(collectionId: string, item: U) { const response = await window.fetch([this.baseUrl, collectionId, this.getItemId(item)].join('/'), { method: 'delete', }) // resource is deleted if (response.status === NO_CONTENT) { return true } // resource is already deleted if (response.status === NOT_FOUND || response.status === GONE) { return false } if (100 <= response.status && response.status <= 399) { console.warn(`Expected response is ${NO_CONTENT}, got ${response.status}.`) // assume there's a change in the collection return true } throw new Error(response.statusText) } // TODO do removeCollection for account closing? }