github.com/hernad/nomad@v1.6.112/ui/app/adapters/application.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 import { inject as service } from '@ember/service'; 7 import { computed } from '@ember/object'; 8 import { camelize } from '@ember/string'; 9 import RESTAdapter from '@ember-data/adapter/rest'; 10 import codesForError from '../utils/codes-for-error'; 11 import removeRecord from '../utils/remove-record'; 12 import { default as NoLeaderError, NO_LEADER } from '../utils/no-leader-error'; 13 import classic from 'ember-classic-decorator'; 14 15 export const namespace = 'v1'; 16 17 @classic 18 export default class ApplicationAdapter extends RESTAdapter { 19 namespace = namespace; 20 21 @service system; 22 @service token; 23 24 @computed('token.secret') 25 get headers() { 26 const token = this.get('token.secret'); 27 if (token) { 28 return { 29 'X-Nomad-Token': token, 30 }; 31 } 32 33 return undefined; 34 } 35 36 handleResponse(status, headers, payload) { 37 if (status === 500 && payload === NO_LEADER) { 38 return new NoLeaderError(); 39 } 40 return super.handleResponse(...arguments); 41 } 42 43 findAll() { 44 return super.findAll(...arguments).catch((error) => { 45 const errorCodes = codesForError(error); 46 47 const isNotImplemented = 48 errorCodes.includes('501') || 49 error.message.includes("rpc: can't find service"); 50 51 if (isNotImplemented) { 52 return []; 53 } 54 55 // Rethrow to be handled downstream 56 throw error; 57 }); 58 } 59 60 ajaxOptions(url, verb, options = {}) { 61 options.data || (options.data = {}); 62 if (this.get('system.shouldIncludeRegion')) { 63 // Region should only ever be a query param. The default ajaxOptions 64 // behavior is to include data attributes in the requestBody for PUT 65 // and POST requests. This works around that. 66 const region = this.get('system.activeRegion'); 67 if (region) { 68 url = associateRegion(url, region); 69 } 70 } 71 return super.ajaxOptions(url, verb, options); 72 } 73 74 // In order to remove stale records from the store, findHasMany has to unload 75 // all records related to the request in question. 76 findHasMany(store, snapshot, link, relationship) { 77 return super.findHasMany(...arguments).then((payload) => { 78 const relationshipType = relationship.type; 79 const inverse = snapshot.record.inverseFor(relationship.key); 80 if (inverse) { 81 store 82 .peekAll(relationshipType) 83 .filter((record) => record.get(`${inverse.name}.id`) === snapshot.id) 84 .forEach((record) => { 85 removeRecord(store, record); 86 }); 87 } 88 return payload; 89 }); 90 } 91 92 // Single record requests deviate from REST practice by using 93 // the singular form of the resource name. 94 // 95 // REST: /some-resources/:id 96 // Nomad: /some-resource/:id 97 // 98 // This is the original implementation of _buildURL 99 // without the pluralization of modelName 100 urlForFindRecord(id, modelName) { 101 let path; 102 let url = []; 103 let host = this.host; 104 let prefix = this.urlPrefix(); 105 106 if (modelName) { 107 path = camelize(modelName); 108 if (path) { 109 url.push(path); 110 } 111 } 112 113 if (id) { 114 url.push(encodeURIComponent(id)); 115 } 116 117 if (prefix) { 118 url.unshift(prefix); 119 } 120 121 url = url.join('/'); 122 if (!host && url && url.charAt(0) !== '/') { 123 url = '/' + url; 124 } 125 126 return url; 127 } 128 129 urlForUpdateRecord() { 130 return this.urlForFindRecord(...arguments); 131 } 132 } 133 134 function associateRegion(url, region) { 135 return url.indexOf('?') !== -1 136 ? `${url}®ion=${region}` 137 : `${url}?region=${region}`; 138 }