geoserver-node-client 0.0.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/layer.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import fetch from 'node-fetch';
2
+ import { getGeoServerResponseText, GeoServerResponseError } from './util/geoserver.js';
3
+ import AboutClient from './about.js'
2
4
 
3
5
  /**
4
6
  * Client for GeoServer layers
@@ -10,116 +12,125 @@ export default class LayerClient {
10
12
  * Creates a GeoServer REST LayerClient instance.
11
13
  *
12
14
  * @param {String} url The URL of the GeoServer REST API endpoint
13
- * @param {String} user The user for the GeoServer REST API
14
- * @param {String} password The password for the GeoServer REST API
15
+ * @param {String} auth The Basic Authentication string
15
16
  */
16
- constructor (url, user, password) {
17
- this.url = url.endsWith('/') ? url : url + '/';
18
- this.user = user;
19
- this.password = password;
17
+ constructor (url, auth) {
18
+ this.url = url;
19
+ this.auth = auth;
20
20
  }
21
21
 
22
22
  /**
23
- * Returns a GeoServer layer by the given full qualified layer name,
23
+ * Returns a GeoServer layer by the given workspace and layer name,
24
24
  * e.g. "myWs:myLayer".
25
25
  *
26
- * @param {String} qualifiedName GeoServer layer name with workspace prefix
26
+ * @param {String} workspace The name of the workspace, can be undefined
27
+ * @param {String} layerName The name of the layer to query
27
28
  *
28
- * @returns {Object|Boolean} An object with layer information or 'false'
29
+ * @throws Error if request fails
30
+ *
31
+ * @returns {Object} An object with layer information or undefined if it cannot be found
29
32
  */
30
- async get (qualifiedName) {
31
- try {
32
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
33
- const response = await fetch(this.url + 'layers/' + qualifiedName + '.json', {
34
- credentials: 'include',
35
- method: 'GET',
36
- headers: {
37
- Authorization: 'Basic ' + auth
38
- }
39
- });
33
+ async get (workspace, layerName) {
34
+ let qualifiedName;
35
+ if (workspace) {
36
+ qualifiedName = `${workspace}:${layerName}`;
37
+ } else {
38
+ qualifiedName = layerName;
39
+ }
40
+ const response = await fetch(this.url + 'layers/' + qualifiedName + '.json', {
41
+ credentials: 'include',
42
+ method: 'GET',
43
+ headers: {
44
+ Authorization: this.auth
45
+ }
46
+ });
40
47
 
41
- if (response.status === 200) {
42
- return await response.json();
48
+ if (!response.ok) {
49
+ const grc = new AboutClient(this.url, this.auth);
50
+ if (await grc.exists()) {
51
+ // GeoServer exists, but requested item does not exist, we return empty
52
+ return;
43
53
  } else {
44
- console.warn(await response.text());
45
- return false;
54
+ // There was a general problem with GeoServer
55
+ const geoServerResponse = await getGeoServerResponseText(response);
56
+ throw new GeoServerResponseError(null, geoServerResponse);
46
57
  }
47
- } catch (error) {
48
- return false;
49
58
  }
59
+ return response.json();
50
60
  }
51
61
 
52
62
  /**
53
63
  * Sets the attribution text and link of a layer.
54
64
  *
55
- * @param {String} qualifiedName GeoServer layer name with workspace prefix
65
+ * @param {String} workspace The name of the workspace, can be undefined
66
+ * @param {String} layerName The name of the layer to query
56
67
  * @param {String} [attributionText] The attribution text
57
68
  * @param {String} [attributionLink] The attribution link
58
69
  *
59
- * @returns {Boolean} If attribution could be updated
70
+ * @throws Error if request fails
60
71
  */
61
- async modifyAttribution (qualifiedName, attributionText, attributionLink) {
62
- try {
63
- // take existing layer properties as template
64
- const jsonBody = await this.get(qualifiedName);
65
-
66
- // set attribution text and link
67
- if (attributionText) {
68
- jsonBody.layer.attribution.title = attributionText;
69
- }
70
- if (attributionLink) {
71
- jsonBody.layer.attribution.href = attributionLink;
72
- }
72
+ async modifyAttribution (workspace, layerName, attributionText, attributionLink) {
73
+ let qualifiedName;
74
+ if (workspace) {
75
+ qualifiedName = `${workspace}:${layerName}`;
76
+ } else {
77
+ qualifiedName = layerName;
78
+ }
79
+ // take existing layer properties as template
80
+ const jsonBody = await this.get(workspace, layerName);
73
81
 
74
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
75
- const url = this.url + 'layers/' + qualifiedName + '.json';
76
- const response = await fetch(url, {
77
- credentials: 'include',
78
- method: 'PUT',
79
- headers: {
80
- Authorization: 'Basic ' + auth,
81
- 'Content-Type': 'application/json'
82
- },
83
- body: JSON.stringify(jsonBody)
84
- });
85
-
86
- if (response.status === 200) {
87
- return true;
88
- } else {
89
- console.warn(await response.text());
90
- return false;
91
- }
92
- } catch (error) {
93
- console.log(error);
94
- return false;
82
+ if (!jsonBody || !jsonBody.layer || !jsonBody.layer.attribution) {
83
+ throw new GeoServerResponseError(
84
+ `layer '${workspace}:${layerName}' misses the property 'attribution'`
85
+ );
86
+ }
87
+
88
+ // set attribution text and link
89
+ if (attributionText) {
90
+ jsonBody.layer.attribution.title = attributionText;
91
+ }
92
+ if (attributionLink) {
93
+ jsonBody.layer.attribution.href = attributionLink;
94
+ }
95
+
96
+ const url = this.url + 'layers/' + qualifiedName + '.json';
97
+ const response = await fetch(url, {
98
+ credentials: 'include',
99
+ method: 'PUT',
100
+ headers: {
101
+ Authorization: this.auth,
102
+ 'Content-Type': 'application/json'
103
+ },
104
+ body: JSON.stringify(jsonBody)
105
+ });
106
+
107
+ if (!response.ok) {
108
+ const geoServerResponse = await getGeoServerResponseText(response);
109
+ throw new GeoServerResponseError(null, geoServerResponse);
95
110
  }
96
111
  }
97
112
 
98
113
  /**
99
114
  * Returns all layers in the GeoServer.
100
115
  *
101
- * @returns {Object|Boolean} An object with all layer information or 'false'
116
+ * @throws Error if request fails
117
+ *
118
+ * @returns {Object} An object with all layer information
102
119
  */
103
120
  async getAll () {
104
- try {
105
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
106
- const response = await fetch(this.url + 'layers.json', {
107
- credentials: 'include',
108
- method: 'GET',
109
- headers: {
110
- Authorization: 'Basic ' + auth
111
- }
112
- });
113
-
114
- if (response.status === 200) {
115
- return await response.json();
116
- } else {
117
- console.warn(await response.text());
118
- return false;
121
+ const response = await fetch(this.url + 'layers.json', {
122
+ credentials: 'include',
123
+ method: 'GET',
124
+ headers: {
125
+ Authorization: this.auth
119
126
  }
120
- } catch (error) {
121
- return false;
127
+ });
128
+
129
+ if (!response.ok) {
130
+ const geoServerResponse = await getGeoServerResponseText(response);
131
+ throw new GeoServerResponseError(null, geoServerResponse);
122
132
  }
133
+ return response.json();
123
134
  }
124
135
 
125
136
  /**
@@ -133,40 +144,33 @@ export default class LayerClient {
133
144
  * @param {String} enabled Flag to enable FeatureType by default
134
145
  * @param {String} [abstract] The abstract of the layer
135
146
  *
136
- * @returns {Boolean} If FeatureType could be published.
147
+ * @throws Error if request fails
137
148
  */
138
149
  async publishFeatureTypeDefaultDataStore (workspace, nativeName, name, title, srs, enabled, abstract) {
139
- try {
140
- const body = {
141
- featureType: {
142
- name: name,
143
- nativeName: name,
144
- title: title || name,
145
- srs: srs || 'EPSG:4326',
146
- enabled: enabled,
147
- abstract: abstract || ''
148
- }
149
- };
150
-
151
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
152
- const response = await fetch(this.url + 'workspaces/' + workspace + '/featuretypes', {
153
- credentials: 'include',
154
- method: 'POST',
155
- headers: {
156
- Authorization: 'Basic ' + auth,
157
- 'Content-Type': 'application/json'
158
- },
159
- body: JSON.stringify(body)
160
- });
161
-
162
- if (response.status === 201) {
163
- return true;
164
- } else {
165
- console.warn(await response.text());
166
- return false;
150
+ const body = {
151
+ featureType: {
152
+ name: name,
153
+ nativeName: nativeName || name,
154
+ title: title || name,
155
+ srs: srs || 'EPSG:4326',
156
+ enabled: enabled,
157
+ abstract: abstract || ''
167
158
  }
168
- } catch (error) {
169
- return false;
159
+ };
160
+
161
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/featuretypes', {
162
+ credentials: 'include',
163
+ method: 'POST',
164
+ headers: {
165
+ Authorization: this.auth,
166
+ 'Content-Type': 'application/json'
167
+ },
168
+ body: JSON.stringify(body)
169
+ });
170
+
171
+ if (!response.ok) {
172
+ const geoServerResponse = await getGeoServerResponseText(response);
173
+ throw new GeoServerResponseError(null, geoServerResponse);
170
174
  }
171
175
  }
172
176
 
@@ -183,50 +187,78 @@ export default class LayerClient {
183
187
  * @param {String} [abstract] The abstract of the layer
184
188
  * @param {String} [nativeBoundingBox] The native BoundingBox of the FeatureType (has to be set if no data is in store at creation time)
185
189
  *
186
- * @returns {Boolean} If the FeatureType could be published
190
+ * @throws Error if request fails
187
191
  */
188
192
  async publishFeatureType (workspace, dataStore, nativeName, name, title, srs, enabled, abstract, nativeBoundingBox) {
189
- try {
190
- // apply CRS info for native BBOX if not provided
191
- if (nativeBoundingBox && !nativeBoundingBox.crs) {
192
- nativeBoundingBox.crs = {
193
- '@class': 'projected',
194
- $: srs
195
- }
193
+ // apply CRS info for native BBOX if not provided
194
+ if (nativeBoundingBox && !nativeBoundingBox.crs) {
195
+ nativeBoundingBox.crs = {
196
+ '@class': 'projected',
197
+ $: srs
196
198
  }
199
+ }
197
200
 
198
- const body = {
199
- featureType: {
200
- name: name || nativeName,
201
- nativeName: nativeName,
202
- title: title || name,
203
- srs: srs || 'EPSG:4326',
204
- enabled: enabled,
205
- abstract: abstract || '',
206
- nativeBoundingBox: nativeBoundingBox
207
- }
208
- };
209
-
210
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
211
- const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes', {
212
- credentials: 'include',
213
- method: 'POST',
214
- headers: {
215
- Authorization: 'Basic ' + auth,
216
- 'Content-Type': 'application/json'
217
- },
218
- body: JSON.stringify(body)
219
- });
220
-
221
- if (response.status === 201) {
222
- return true;
201
+ const body = {
202
+ featureType: {
203
+ name: name || nativeName,
204
+ nativeName: nativeName,
205
+ title: title || name,
206
+ srs: srs || 'EPSG:4326',
207
+ enabled: enabled,
208
+ abstract: abstract || '',
209
+ nativeBoundingBox: nativeBoundingBox
210
+ }
211
+ };
212
+
213
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes', {
214
+ credentials: 'include',
215
+ method: 'POST',
216
+ headers: {
217
+ Authorization: this.auth,
218
+ 'Content-Type': 'application/json'
219
+ },
220
+ body: JSON.stringify(body)
221
+ });
222
+
223
+ if (!response.ok) {
224
+ const geoServerResponse = await getGeoServerResponseText(response);
225
+ throw new GeoServerResponseError(null, geoServerResponse);
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Get detailed information about a FeatureType.
231
+ *
232
+ * @param {String} workspace The workspace of the FeatureType
233
+ * @param {String} datastore The datastore of the FeatureType
234
+ * @param {String} name The name of the FeatureType
235
+ *
236
+ * @throws Error if request fails
237
+ *
238
+ * @returns {Object} The object of the FeatureType
239
+ */
240
+ async getFeatureType (workspace, datastore, name) {
241
+ const url = this.url + 'workspaces/' + workspace + '/datastores/' + datastore + '/featuretypes/' + name + '.json';
242
+ const response = await fetch(url, {
243
+ credentials: 'include',
244
+ method: 'GET',
245
+ headers: {
246
+ Authorization: this.auth
247
+ }
248
+ });
249
+
250
+ if (!response.ok) {
251
+ const grc = new AboutClient(this.url, this.auth);
252
+ if (await grc.exists()) {
253
+ // GeoServer exists, but requested item does not exist, we return empty
254
+ return;
223
255
  } else {
224
- console.warn(await response.text());
225
- return false;
256
+ // There was a general problem with GeoServer
257
+ const geoServerResponse = await getGeoServerResponseText(response);
258
+ throw new GeoServerResponseError(null, geoServerResponse);
226
259
  }
227
- } catch (error) {
228
- return false;
229
260
  }
261
+ return response.json();
230
262
  }
231
263
 
232
264
  /**
@@ -241,40 +273,33 @@ export default class LayerClient {
241
273
  * @param {String} enabled Flag to enable WMS layer by default
242
274
  * @param {String} [abstract] The abstract of the layer
243
275
  *
244
- * @returns {Boolean} If the wms layer could be published
276
+ * @throws Error if request fails
245
277
  */
246
278
  async publishWmsLayer (workspace, dataStore, nativeName, name, title, srs, enabled, abstract) {
247
- try {
248
- const body = {
249
- wmsLayer: {
250
- name: name || nativeName,
251
- nativeName: nativeName,
252
- title: title || name || nativeName,
253
- srs: srs || 'EPSG:4326',
254
- enabled: enabled,
255
- abstract: abstract || ''
256
- }
257
- };
258
-
259
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
260
- const response = await fetch(this.url + 'workspaces/' + workspace + '/wmsstores/' + dataStore + '/wmslayers', {
261
- credentials: 'include',
262
- method: 'POST',
263
- headers: {
264
- Authorization: 'Basic ' + auth,
265
- 'Content-Type': 'application/json'
266
- },
267
- body: JSON.stringify(body)
268
- });
269
-
270
- if (response.status === 201) {
271
- return true;
272
- } else {
273
- console.warn(await response.text());
274
- return false;
279
+ const body = {
280
+ wmsLayer: {
281
+ name: name || nativeName,
282
+ nativeName: nativeName,
283
+ title: title || name || nativeName,
284
+ srs: srs || 'EPSG:4326',
285
+ enabled: enabled,
286
+ abstract: abstract || ''
275
287
  }
276
- } catch (error) {
277
- return false;
288
+ };
289
+
290
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/wmsstores/' + dataStore + '/wmslayers', {
291
+ credentials: 'include',
292
+ method: 'POST',
293
+ headers: {
294
+ Authorization: this.auth,
295
+ 'Content-Type': 'application/json'
296
+ },
297
+ body: JSON.stringify(body)
298
+ });
299
+
300
+ if (!response.ok) {
301
+ const geoServerResponse = await getGeoServerResponseText(response);
302
+ throw new GeoServerResponseError(null, geoServerResponse);
278
303
  }
279
304
  }
280
305
 
@@ -290,39 +315,33 @@ export default class LayerClient {
290
315
  * @param {String} enabled Flag to enable layer by default
291
316
  * @param {String} [abstract] The abstract of the layer
292
317
  *
293
- * @returns {Boolean} If raster could be published
318
+ * @throws Error if request fails
294
319
  */
295
320
  async publishDbRaster (workspace, coverageStore, nativeName, name, title, srs, enabled, abstract) {
296
- try {
297
- const body = {
298
- coverage: {
299
- name: name || nativeName,
300
- nativeName: nativeName,
301
- title: title || name,
302
- srs: srs,
303
- enabled: enabled,
304
- abstract: abstract || ''
305
- }
306
- };
307
-
308
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
309
- const response = await fetch(this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages', {
310
- credentials: 'include',
311
- method: 'POST',
312
- headers: {
313
- Authorization: 'Basic ' + auth,
314
- 'Content-Type': 'application/json'
315
- },
316
- body: JSON.stringify(body)
317
- });
318
-
319
- if (response.status === 201) {
320
- return true;
321
- } else {
322
- return false;
321
+ const body = {
322
+ coverage: {
323
+ name: name || nativeName,
324
+ nativeName: nativeName,
325
+ title: title || name,
326
+ srs: srs,
327
+ enabled: enabled,
328
+ abstract: abstract || ''
323
329
  }
324
- } catch (error) {
325
- return false;
330
+ };
331
+
332
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages', {
333
+ credentials: 'include',
334
+ method: 'POST',
335
+ headers: {
336
+ Authorization: this.auth,
337
+ 'Content-Type': 'application/json'
338
+ },
339
+ body: JSON.stringify(body)
340
+ });
341
+
342
+ if (!response.ok) {
343
+ const geoServerResponse = await getGeoServerResponseText(response);
344
+ throw new GeoServerResponseError(null, geoServerResponse);
326
345
  }
327
346
  }
328
347
 
@@ -334,27 +353,20 @@ export default class LayerClient {
334
353
  * @param {String} name Layer to delete
335
354
  * @param {Boolean} recurse Flag to enable recursive deletion
336
355
  *
337
- * @returns {Boolean} If the feature type could be deleted
356
+ * @throws Error if request fails
338
357
  */
339
358
  async deleteFeatureType (workspace, datastore, name, recurse) {
340
- try {
341
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
342
- const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + datastore + '/featuretypes/' + name + '?recurse=' + recurse, {
343
- credentials: 'include',
344
- method: 'DELETE',
345
- headers: {
346
- Authorization: 'Basic ' + auth
347
- }
348
- });
349
-
350
- if (response.status === 200) {
351
- return true;
352
- } else {
353
- console.warn(await response.text());
354
- return false;
359
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + datastore + '/featuretypes/' + name + '?recurse=' + recurse, {
360
+ credentials: 'include',
361
+ method: 'DELETE',
362
+ headers: {
363
+ Authorization: this.auth
355
364
  }
356
- } catch (error) {
357
- return false;
365
+ });
366
+
367
+ if (!response.ok) {
368
+ const geoServerResponse = await getGeoServerResponseText(response);
369
+ throw new GeoServerResponseError(null, geoServerResponse);
358
370
  }
359
371
  }
360
372
 
@@ -371,56 +383,46 @@ export default class LayerClient {
371
383
  * @param {Boolean} [rawNearestMatchEnabled] Enable raw nearest match
372
384
  * @param {String} [acceptableInterval] Acceptable interval for nearest match, e.g.'PT30M'
373
385
  *
374
- * @returns If time dimension could be enabled
386
+ * @throws Error if request fails
375
387
  */
376
388
  async enableTimeCoverage (workspace, dataStore, name, presentation, resolution, defaultValue, nearestMatchEnabled, rawNearestMatchEnabled, acceptableInterval) {
377
- try {
378
- const body = {
379
- coverage: {
380
- metadata: {
381
- entry: [
382
- {
383
- '@key': 'time',
384
- dimensionInfo: {
385
- enabled: true,
386
- presentation: 'DISCRETE_INTERVAL',
387
- resolution: resolution,
388
- units: 'ISO8601',
389
- defaultValue: {
390
- strategy: defaultValue
391
- },
392
- nearestMatchEnabled: nearestMatchEnabled,
393
- rawNearestMatchEnabled: rawNearestMatchEnabled,
394
- acceptableInterval: acceptableInterval
395
- }
389
+ const body = {
390
+ coverage: {
391
+ metadata: {
392
+ entry: [
393
+ {
394
+ '@key': 'time',
395
+ dimensionInfo: {
396
+ presentation: presentation || 'DISCRETE_INTERVAL',
397
+ resolution: resolution,
398
+ units: 'ISO8601',
399
+ defaultValue: {
400
+ strategy: defaultValue
401
+ },
402
+ nearestMatchEnabled: nearestMatchEnabled,
403
+ rawNearestMatchEnabled: rawNearestMatchEnabled,
404
+ acceptableInterval: acceptableInterval
396
405
  }
397
- ]
398
- }
406
+ }
407
+ ]
399
408
  }
400
- };
401
-
402
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
403
- const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + dataStore + '/coverages/' + name + '.json';
404
- console.log(url);
405
- const response = await fetch(url, {
406
- credentials: 'include',
407
- method: 'PUT',
408
- headers: {
409
- Authorization: 'Basic ' + auth,
410
- 'Content-Type': 'application/json'
411
- },
412
- body: JSON.stringify(body)
413
- });
414
-
415
- if (response.status === 200) {
416
- return true;
417
- } else {
418
- console.warn(await response.text());
419
- return false;
420
409
  }
421
- } catch (error) {
422
- console.log(error);
423
- return false;
410
+ };
411
+
412
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + dataStore + '/coverages/' + name + '.json';
413
+ const response = await fetch(url, {
414
+ credentials: 'include',
415
+ method: 'PUT',
416
+ headers: {
417
+ Authorization: this.auth,
418
+ 'Content-Type': 'application/json'
419
+ },
420
+ body: JSON.stringify(body)
421
+ });
422
+
423
+ if (!response.ok) {
424
+ const geoServerResponse = await getGeoServerResponseText(response);
425
+ throw new GeoServerResponseError(null, geoServerResponse);
424
426
  }
425
427
  }
426
428
 
@@ -436,57 +438,48 @@ export default class LayerClient {
436
438
  * @param {String} defaultValue The default time value, e.g. 'MINIMUM' or 'MAXIMUM' or 'NEAREST' or 'FIXED'
437
439
  * @param {Boolean} [nearestMatchEnabled] Enable nearest match
438
440
  * @param {Boolean} [rawNearestMatchEnabled] Enable raw nearest match
439
- * @param {String} [acceptableInterval] Tolerance interval for nearest mach (e.g. 'PT30M'), only has an effect if 'nearestMatchEnabled' is true
440
441
  *
441
- * @returns {Boolean} If TIME dimension could be enabled
442
+ * @throws Error if request fails
442
443
  */
443
444
  async enableTimeFeatureType (workspace, dataStore, name, attribute, presentation, resolution, defaultValue, nearestMatchEnabled, rawNearestMatchEnabled, acceptableInterval) {
444
- try {
445
- const body = {
446
- featureType: {
447
- metadata: {
448
- entry: [
449
- {
450
- '@key': 'time',
451
- dimensionInfo: {
452
- enabled: true,
453
- attribute: attribute,
454
- presentation: presentation,
455
- resolution: resolution,
456
- units: 'ISO8601',
457
- defaultValue: {
458
- strategy: defaultValue
459
- },
460
- nearestMatchEnabled: nearestMatchEnabled,
461
- rawNearestMatchEnabled: rawNearestMatchEnabled,
462
- acceptableInterval: acceptableInterval
463
- }
445
+ const body = {
446
+ featureType: {
447
+ metadata: {
448
+ entry: [
449
+ {
450
+ '@key': 'time',
451
+ dimensionInfo: {
452
+ attribute: attribute,
453
+ presentation: presentation,
454
+ resolution: resolution,
455
+ units: 'ISO8601',
456
+ defaultValue: {
457
+ strategy: defaultValue
458
+ },
459
+ nearestMatchEnabled: nearestMatchEnabled,
460
+ rawNearestMatchEnabled: rawNearestMatchEnabled,
461
+ acceptableInterval: acceptableInterval
464
462
  }
465
- ]
466
- }
463
+ }
464
+ ]
467
465
  }
468
- };
469
-
470
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
471
- const url = this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes/' + name + '.json';
472
- const response = await fetch(url, {
473
- credentials: 'include',
474
- method: 'PUT',
475
- headers: {
476
- Authorization: 'Basic ' + auth,
477
- 'Content-Type': 'application/json'
478
- },
479
- body: JSON.stringify(body)
480
- });
481
-
482
- if (response.status === 200) {
483
- return true;
484
- } else {
485
- console.warn(await response.text());
486
- return false;
487
466
  }
488
- } catch (error) {
489
- return false;
467
+ };
468
+
469
+ const url = this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes/' + name + '.json';
470
+ const response = await fetch(url, {
471
+ credentials: 'include',
472
+ method: 'PUT',
473
+ headers: {
474
+ Authorization: this.auth,
475
+ 'Content-Type': 'application/json'
476
+ },
477
+ body: JSON.stringify(body)
478
+ });
479
+
480
+ if (!response.ok) {
481
+ const geoServerResponse = await getGeoServerResponseText(response);
482
+ throw new GeoServerResponseError(null, geoServerResponse);
490
483
  }
491
484
  }
492
485
 
@@ -497,28 +490,79 @@ export default class LayerClient {
497
490
  * @param {String} coverageStore The coveragestore containing the coverage
498
491
  * @param {String} name Coverage to query
499
492
  *
500
- * @returns {Object|Boolean} An object with coverage information or 'false'
493
+ * @throws Error if request fails
494
+ *
495
+ * @returns {Object} An object with coverage information or undefined if it cannot be found
501
496
  */
502
497
  async getCoverage (workspace, coverageStore, name) {
503
- try {
504
- const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
505
- const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages/' + name + '.json';
506
- const response = await fetch(url, {
507
- credentials: 'include',
508
- method: 'GET',
509
- headers: {
510
- Authorization: 'Basic ' + auth
511
- }
512
- });
498
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages/' + name + '.json';
499
+ const response = await fetch(url, {
500
+ credentials: 'include',
501
+ method: 'GET',
502
+ headers: {
503
+ Authorization: this.auth
504
+ }
505
+ });
513
506
 
514
- if (response.status === 200) {
515
- return await response.json();
507
+ if (!response.ok) {
508
+ const grc = new AboutClient(this.url, this.auth);
509
+ if (await grc.exists()) {
510
+ // GeoServer exists, but requested item does not exist, we return empty
511
+ return;
516
512
  } else {
517
- console.warn(await response.text());
518
- return false;
513
+ // There was a general problem with GeoServer
514
+ const geoServerResponse = await getGeoServerResponseText(response);
515
+ throw new GeoServerResponseError(null, geoServerResponse);
519
516
  }
520
- } catch (error) {
521
- return false;
517
+ }
518
+ return response.json();
519
+ }
520
+
521
+ /**
522
+ * Renames the existing bands of a coverage layer.
523
+ *
524
+ * Make sure to provide the same number of bands as existing in the layer.
525
+ *
526
+ * @param {String} workspace Workspace of layer
527
+ * @param {String} datastore The datastore of the layer
528
+ * @param {String} layername The layer name
529
+ * @param {String[]} bandNames An array of the new band names in correct order
530
+ *
531
+ * @throws Error if request fails
532
+ */
533
+ async renameCoverageBands (workspace, dataStore, layername, bandNames) {
534
+ const body = {
535
+ coverage: {
536
+ dimensions: {
537
+ coverageDimension: [
538
+ ]
539
+ }
540
+ }
541
+ };
542
+
543
+ // dynamically create the body
544
+ bandNames.forEach(bandName => {
545
+ body.coverage.dimensions.coverageDimension.push(
546
+ {
547
+ name: bandName
548
+ }
549
+ );
550
+ })
551
+
552
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + dataStore + '/coverages/' + layername + '.json';
553
+ const response = await fetch(url, {
554
+ credentials: 'include',
555
+ method: 'PUT',
556
+ headers: {
557
+ Authorization: this.auth,
558
+ 'Content-Type': 'application/json'
559
+ },
560
+ body: JSON.stringify(body)
561
+ });
562
+
563
+ if (!response.ok) {
564
+ const geoServerResponse = await getGeoServerResponseText(response);
565
+ throw new GeoServerResponseError(null, geoServerResponse);
522
566
  }
523
567
  }
524
568
  }