geoserver-node-client 0.0.7 → 1.2.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,222 @@ 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;
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);
81
+
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);
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Returns all layers in the GeoServer.
115
+ *
116
+ * @throws Error if request fails
117
+ *
118
+ * @returns {Object} An object with all layer information
119
+ */
120
+ async getAll () {
121
+ const response = await fetch(this.url + 'layers.json', {
122
+ credentials: 'include',
123
+ method: 'GET',
124
+ headers: {
125
+ Authorization: this.auth
69
126
  }
70
- if (attributionLink) {
71
- jsonBody.layer.attribution.href = attributionLink;
127
+ });
128
+
129
+ if (!response.ok) {
130
+ const geoServerResponse = await getGeoServerResponseText(response);
131
+ throw new GeoServerResponseError(null, geoServerResponse);
132
+ }
133
+ return response.json();
134
+ }
135
+
136
+ /**
137
+ * Get all layers of a workspace.
138
+ *
139
+ * @param {String} workspace The workspace
140
+ *
141
+ * @throws Error if request fails
142
+ *
143
+ * @return {Object} An object with the information about the layers
144
+ */
145
+ async getLayers (workspace) {
146
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/layers.json', {
147
+ credentials: 'include',
148
+ method: 'GET',
149
+ headers: {
150
+ Authorization: this.auth,
151
+ }
152
+ });
153
+
154
+ if (!response.ok) {
155
+ const geoServerResponse = await getGeoServerResponseText(response);
156
+ throw new GeoServerResponseError(null, geoServerResponse);
157
+ }
158
+
159
+ return await response.json();
160
+ }
161
+
162
+ /**
163
+ * Returns information about a cascaded WMS layer.
164
+ *
165
+ * @param {String} workspace The workspace
166
+ * @param {String} datastore The datastore
167
+ * @param {String} layerName The WMS layer name
168
+ *
169
+ * @throws Error if request fails
170
+ *
171
+ * @returns {Object} An object with layer information or undefined if it cannot be found
172
+ */
173
+ async getWmsLayer (workspace, datastore, layerName) {
174
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/wmsstores/' + datastore + '/wmslayers/' + layerName + '.json', {
175
+ credentials: 'include',
176
+ method: 'GET',
177
+ headers: {
178
+ Authorization: this.auth,
72
179
  }
180
+ });
73
181
 
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;
182
+ if (!response.ok) {
183
+ const grc = new AboutClient(this.url, this.auth);
184
+ if (await grc.exists()) {
185
+ // GeoServer exists, but requested item does not exist, we return empty
186
+ return;
88
187
  } else {
89
- console.warn(await response.text());
90
- return false;
188
+ // There was a general problem with GeoServer
189
+ const geoServerResponse = await getGeoServerResponseText(response);
190
+ throw new GeoServerResponseError(null, geoServerResponse);
91
191
  }
92
- } catch (error) {
93
- console.log(error);
94
- return false;
95
192
  }
193
+
194
+ return await response.json();
96
195
  }
97
196
 
197
+ // TODO: automated test needed
98
198
  /**
99
- * Returns all layers in the GeoServer.
199
+ * Returns information about a cascaded WMTS layer.
200
+ *
201
+ * @param {String} workspace The workspace
202
+ * @param {String} datastore The datastore
203
+ * @param {String} layerName The WMTS layer name
100
204
  *
101
- * @returns {Object|Boolean} An object with all layer information or 'false'
205
+ * @throws Error if request fails
206
+ *
207
+ * @returns {Object} An object with layer information or undefined if it cannot be found
102
208
  */
103
- 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
- });
209
+ async getWmtsLayer (workspace, datastore, layerName) {
210
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/wmtsstores/' + datastore + '/layers/' + layerName + '.json', {
211
+ credentials: 'include',
212
+ method: 'GET',
213
+ headers: {
214
+ Authorization: this.auth,
215
+ }
216
+ });
113
217
 
114
- if (response.status === 200) {
115
- return await response.json();
218
+ if (!response.ok) {
219
+ const grc = new AboutClient(this.url, this.auth);
220
+ if (await grc.exists()) {
221
+ // GeoServer exists, but requested item does not exist, we return empty
222
+ return;
116
223
  } else {
117
- console.warn(await response.text());
118
- return false;
224
+ // There was a general problem with GeoServer
225
+ const geoServerResponse = await getGeoServerResponseText(response);
226
+ throw new GeoServerResponseError(null, geoServerResponse);
119
227
  }
120
- } catch (error) {
121
- return false;
122
228
  }
229
+
230
+ return await response.json();
123
231
  }
124
232
 
125
233
  /**
@@ -133,40 +241,33 @@ export default class LayerClient {
133
241
  * @param {String} enabled Flag to enable FeatureType by default
134
242
  * @param {String} [abstract] The abstract of the layer
135
243
  *
136
- * @returns {Boolean} If FeatureType could be published.
244
+ * @throws Error if request fails
137
245
  */
138
246
  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;
247
+ const body = {
248
+ featureType: {
249
+ name: name,
250
+ nativeName: nativeName || name,
251
+ title: title || name,
252
+ srs: srs || 'EPSG:4326',
253
+ enabled: enabled,
254
+ abstract: abstract || ''
167
255
  }
168
- } catch (error) {
169
- return false;
256
+ };
257
+
258
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/featuretypes', {
259
+ credentials: 'include',
260
+ method: 'POST',
261
+ headers: {
262
+ Authorization: this.auth,
263
+ 'Content-Type': 'application/json'
264
+ },
265
+ body: JSON.stringify(body)
266
+ });
267
+
268
+ if (!response.ok) {
269
+ const geoServerResponse = await getGeoServerResponseText(response);
270
+ throw new GeoServerResponseError(null, geoServerResponse);
170
271
  }
171
272
  }
172
273
 
@@ -183,50 +284,78 @@ export default class LayerClient {
183
284
  * @param {String} [abstract] The abstract of the layer
184
285
  * @param {String} [nativeBoundingBox] The native BoundingBox of the FeatureType (has to be set if no data is in store at creation time)
185
286
  *
186
- * @returns {Boolean} If the FeatureType could be published
287
+ * @throws Error if request fails
187
288
  */
188
289
  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
- }
290
+ // apply CRS info for native BBOX if not provided
291
+ if (nativeBoundingBox && !nativeBoundingBox.crs) {
292
+ nativeBoundingBox.crs = {
293
+ '@class': 'projected',
294
+ $: srs
196
295
  }
296
+ }
197
297
 
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;
298
+ const body = {
299
+ featureType: {
300
+ name: name || nativeName,
301
+ nativeName: nativeName,
302
+ title: title || name,
303
+ srs: srs || 'EPSG:4326',
304
+ enabled: enabled,
305
+ abstract: abstract || '',
306
+ nativeBoundingBox: nativeBoundingBox
307
+ }
308
+ };
309
+
310
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes', {
311
+ credentials: 'include',
312
+ method: 'POST',
313
+ headers: {
314
+ Authorization: this.auth,
315
+ 'Content-Type': 'application/json'
316
+ },
317
+ body: JSON.stringify(body)
318
+ });
319
+
320
+ if (!response.ok) {
321
+ const geoServerResponse = await getGeoServerResponseText(response);
322
+ throw new GeoServerResponseError(null, geoServerResponse);
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Get detailed information about a FeatureType.
328
+ *
329
+ * @param {String} workspace The workspace of the FeatureType
330
+ * @param {String} datastore The datastore of the FeatureType
331
+ * @param {String} name The name of the FeatureType
332
+ *
333
+ * @throws Error if request fails
334
+ *
335
+ * @returns {Object} The object of the FeatureType
336
+ */
337
+ async getFeatureType (workspace, datastore, name) {
338
+ const url = this.url + 'workspaces/' + workspace + '/datastores/' + datastore + '/featuretypes/' + name + '.json';
339
+ const response = await fetch(url, {
340
+ credentials: 'include',
341
+ method: 'GET',
342
+ headers: {
343
+ Authorization: this.auth
344
+ }
345
+ });
346
+
347
+ if (!response.ok) {
348
+ const grc = new AboutClient(this.url, this.auth);
349
+ if (await grc.exists()) {
350
+ // GeoServer exists, but requested item does not exist, we return empty
351
+ return;
223
352
  } else {
224
- console.warn(await response.text());
225
- return false;
353
+ // There was a general problem with GeoServer
354
+ const geoServerResponse = await getGeoServerResponseText(response);
355
+ throw new GeoServerResponseError(null, geoServerResponse);
226
356
  }
227
- } catch (error) {
228
- return false;
229
357
  }
358
+ return response.json();
230
359
  }
231
360
 
232
361
  /**
@@ -241,40 +370,33 @@ export default class LayerClient {
241
370
  * @param {String} enabled Flag to enable WMS layer by default
242
371
  * @param {String} [abstract] The abstract of the layer
243
372
  *
244
- * @returns {Boolean} If the wms layer could be published
373
+ * @throws Error if request fails
245
374
  */
246
375
  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;
376
+ const body = {
377
+ wmsLayer: {
378
+ name: name || nativeName,
379
+ nativeName: nativeName,
380
+ title: title || name || nativeName,
381
+ srs: srs || 'EPSG:4326',
382
+ enabled: enabled,
383
+ abstract: abstract || ''
275
384
  }
276
- } catch (error) {
277
- return false;
385
+ };
386
+
387
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/wmsstores/' + dataStore + '/wmslayers', {
388
+ credentials: 'include',
389
+ method: 'POST',
390
+ headers: {
391
+ Authorization: this.auth,
392
+ 'Content-Type': 'application/json'
393
+ },
394
+ body: JSON.stringify(body)
395
+ });
396
+
397
+ if (!response.ok) {
398
+ const geoServerResponse = await getGeoServerResponseText(response);
399
+ throw new GeoServerResponseError(null, geoServerResponse);
278
400
  }
279
401
  }
280
402
 
@@ -290,39 +412,33 @@ export default class LayerClient {
290
412
  * @param {String} enabled Flag to enable layer by default
291
413
  * @param {String} [abstract] The abstract of the layer
292
414
  *
293
- * @returns {Boolean} If raster could be published
415
+ * @throws Error if request fails
294
416
  */
295
417
  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;
418
+ const body = {
419
+ coverage: {
420
+ name: name || nativeName,
421
+ nativeName: nativeName,
422
+ title: title || name,
423
+ srs: srs,
424
+ enabled: enabled,
425
+ abstract: abstract || ''
323
426
  }
324
- } catch (error) {
325
- return false;
427
+ };
428
+
429
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages', {
430
+ credentials: 'include',
431
+ method: 'POST',
432
+ headers: {
433
+ Authorization: this.auth,
434
+ 'Content-Type': 'application/json'
435
+ },
436
+ body: JSON.stringify(body)
437
+ });
438
+
439
+ if (!response.ok) {
440
+ const geoServerResponse = await getGeoServerResponseText(response);
441
+ throw new GeoServerResponseError(null, geoServerResponse);
326
442
  }
327
443
  }
328
444
 
@@ -334,27 +450,20 @@ export default class LayerClient {
334
450
  * @param {String} name Layer to delete
335
451
  * @param {Boolean} recurse Flag to enable recursive deletion
336
452
  *
337
- * @returns {Boolean} If the feature type could be deleted
453
+ * @throws Error if request fails
338
454
  */
339
455
  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;
456
+ const response = await fetch(this.url + 'workspaces/' + workspace + '/datastores/' + datastore + '/featuretypes/' + name + '?recurse=' + recurse, {
457
+ credentials: 'include',
458
+ method: 'DELETE',
459
+ headers: {
460
+ Authorization: this.auth
355
461
  }
356
- } catch (error) {
357
- return false;
462
+ });
463
+
464
+ if (!response.ok) {
465
+ const geoServerResponse = await getGeoServerResponseText(response);
466
+ throw new GeoServerResponseError(null, geoServerResponse);
358
467
  }
359
468
  }
360
469
 
@@ -371,56 +480,46 @@ export default class LayerClient {
371
480
  * @param {Boolean} [rawNearestMatchEnabled] Enable raw nearest match
372
481
  * @param {String} [acceptableInterval] Acceptable interval for nearest match, e.g.'PT30M'
373
482
  *
374
- * @returns If time dimension could be enabled
483
+ * @throws Error if request fails
375
484
  */
376
485
  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
- }
486
+ const body = {
487
+ coverage: {
488
+ metadata: {
489
+ entry: [
490
+ {
491
+ '@key': 'time',
492
+ dimensionInfo: {
493
+ presentation: presentation || 'DISCRETE_INTERVAL',
494
+ resolution: resolution,
495
+ units: 'ISO8601',
496
+ defaultValue: {
497
+ strategy: defaultValue
498
+ },
499
+ nearestMatchEnabled: nearestMatchEnabled,
500
+ rawNearestMatchEnabled: rawNearestMatchEnabled,
501
+ acceptableInterval: acceptableInterval
396
502
  }
397
- ]
398
- }
503
+ }
504
+ ]
399
505
  }
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
506
  }
421
- } catch (error) {
422
- console.log(error);
423
- return false;
507
+ };
508
+
509
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + dataStore + '/coverages/' + name + '.json';
510
+ const response = await fetch(url, {
511
+ credentials: 'include',
512
+ method: 'PUT',
513
+ headers: {
514
+ Authorization: this.auth,
515
+ 'Content-Type': 'application/json'
516
+ },
517
+ body: JSON.stringify(body)
518
+ });
519
+
520
+ if (!response.ok) {
521
+ const geoServerResponse = await getGeoServerResponseText(response);
522
+ throw new GeoServerResponseError(null, geoServerResponse);
424
523
  }
425
524
  }
426
525
 
@@ -436,57 +535,48 @@ export default class LayerClient {
436
535
  * @param {String} defaultValue The default time value, e.g. 'MINIMUM' or 'MAXIMUM' or 'NEAREST' or 'FIXED'
437
536
  * @param {Boolean} [nearestMatchEnabled] Enable nearest match
438
537
  * @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
538
  *
441
- * @returns {Boolean} If TIME dimension could be enabled
539
+ * @throws Error if request fails
442
540
  */
443
541
  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
- }
542
+ const body = {
543
+ featureType: {
544
+ metadata: {
545
+ entry: [
546
+ {
547
+ '@key': 'time',
548
+ dimensionInfo: {
549
+ attribute: attribute,
550
+ presentation: presentation,
551
+ resolution: resolution,
552
+ units: 'ISO8601',
553
+ defaultValue: {
554
+ strategy: defaultValue
555
+ },
556
+ nearestMatchEnabled: nearestMatchEnabled,
557
+ rawNearestMatchEnabled: rawNearestMatchEnabled,
558
+ acceptableInterval: acceptableInterval
464
559
  }
465
- ]
466
- }
560
+ }
561
+ ]
467
562
  }
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
563
  }
488
- } catch (error) {
489
- return false;
564
+ };
565
+
566
+ const url = this.url + 'workspaces/' + workspace + '/datastores/' + dataStore + '/featuretypes/' + name + '.json';
567
+ const response = await fetch(url, {
568
+ credentials: 'include',
569
+ method: 'PUT',
570
+ headers: {
571
+ Authorization: this.auth,
572
+ 'Content-Type': 'application/json'
573
+ },
574
+ body: JSON.stringify(body)
575
+ });
576
+
577
+ if (!response.ok) {
578
+ const geoServerResponse = await getGeoServerResponseText(response);
579
+ throw new GeoServerResponseError(null, geoServerResponse);
490
580
  }
491
581
  }
492
582
 
@@ -497,28 +587,79 @@ export default class LayerClient {
497
587
  * @param {String} coverageStore The coveragestore containing the coverage
498
588
  * @param {String} name Coverage to query
499
589
  *
500
- * @returns {Object|Boolean} An object with coverage information or 'false'
590
+ * @throws Error if request fails
591
+ *
592
+ * @returns {Object} An object with coverage information or undefined if it cannot be found
501
593
  */
502
594
  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
- });
595
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + coverageStore + '/coverages/' + name + '.json';
596
+ const response = await fetch(url, {
597
+ credentials: 'include',
598
+ method: 'GET',
599
+ headers: {
600
+ Authorization: this.auth
601
+ }
602
+ });
513
603
 
514
- if (response.status === 200) {
515
- return await response.json();
604
+ if (!response.ok) {
605
+ const grc = new AboutClient(this.url, this.auth);
606
+ if (await grc.exists()) {
607
+ // GeoServer exists, but requested item does not exist, we return empty
608
+ return;
516
609
  } else {
517
- console.warn(await response.text());
518
- return false;
610
+ // There was a general problem with GeoServer
611
+ const geoServerResponse = await getGeoServerResponseText(response);
612
+ throw new GeoServerResponseError(null, geoServerResponse);
613
+ }
614
+ }
615
+ return response.json();
616
+ }
617
+
618
+ /**
619
+ * Renames the existing bands of a coverage layer.
620
+ *
621
+ * Make sure to provide the same number of bands as existing in the layer.
622
+ *
623
+ * @param {String} workspace Workspace of layer
624
+ * @param {String} datastore The datastore of the layer
625
+ * @param {String} layername The layer name
626
+ * @param {String[]} bandNames An array of the new band names in correct order
627
+ *
628
+ * @throws Error if request fails
629
+ */
630
+ async renameCoverageBands (workspace, dataStore, layername, bandNames) {
631
+ const body = {
632
+ coverage: {
633
+ dimensions: {
634
+ coverageDimension: [
635
+ ]
636
+ }
519
637
  }
520
- } catch (error) {
521
- return false;
638
+ };
639
+
640
+ // dynamically create the body
641
+ bandNames.forEach(bandName => {
642
+ body.coverage.dimensions.coverageDimension.push(
643
+ {
644
+ name: bandName
645
+ }
646
+ );
647
+ })
648
+
649
+ const url = this.url + 'workspaces/' + workspace + '/coveragestores/' + dataStore + '/coverages/' + layername + '.json';
650
+ const response = await fetch(url, {
651
+ credentials: 'include',
652
+ method: 'PUT',
653
+ headers: {
654
+ Authorization: this.auth,
655
+ 'Content-Type': 'application/json'
656
+ },
657
+ body: JSON.stringify(body)
658
+ });
659
+
660
+ if (!response.ok) {
661
+ const geoServerResponse = await getGeoServerResponseText(response);
662
+ throw new GeoServerResponseError(null, geoServerResponse);
522
663
  }
523
664
  }
524
665
  }