geoserver-node-client 0.0.7 → 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/README.md +74 -7
- package/dist/geoserver-rest-client.js +87 -0
- package/dist/package.json +55 -0
- package/dist/src/about.js +145 -0
- package/dist/src/datastore.js +1050 -0
- package/dist/src/imagemosaic.js +297 -0
- package/dist/src/layer.js +1040 -0
- package/dist/src/namespace.js +315 -0
- package/dist/src/security.js +297 -0
- package/dist/src/settings.js +345 -0
- package/dist/src/style.js +597 -0
- package/dist/src/util/geoserver.js +97 -0
- package/dist/src/workspace.js +321 -0
- package/geoserver-rest-client.js +15 -52
- package/package.json +23 -6
- package/src/about.js +59 -0
- package/src/datastore.js +161 -200
- package/src/imagemosaic.js +74 -97
- package/src/layer.js +376 -332
- package/src/namespace.js +84 -83
- package/src/security.js +61 -84
- package/src/settings.js +76 -91
- package/src/style.js +165 -171
- package/src/util/geoserver.js +41 -0
- package/src/workspace.js +89 -81
- package/.eslintrc.json +0 -20
- package/.github/workflows/ci-geoserver-node-client.yml +0 -54
- package/.github/workflows/ci-publish-docs.yml +0 -24
- package/.github/workflows/wait-for.sh +0 -145
- package/.vscode/settings.json +0 -3
- package/DOCS_HOME.md +0 -26
- package/demo/index.js +0 -188
- package/release-it.json +0 -8
- package/test/sample_data/iceland.gpkg +0 -0
- package/test/sample_data/world.geotiff +0 -0
- package/test/test.js +0 -502
package/src/style.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fetch from 'node-fetch';
|
|
2
2
|
import WorkspaceClient from './workspace.js';
|
|
3
|
+
import { getGeoServerResponseText, GeoServerResponseError } from './util/geoserver.js';
|
|
4
|
+
import AboutClient from './about.js'
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Client for GeoServer styles
|
|
@@ -11,41 +13,34 @@ export default class StyleClient {
|
|
|
11
13
|
* Creates a GeoServer REST StyleClient instance.
|
|
12
14
|
*
|
|
13
15
|
* @param {String} url The URL of the GeoServer REST API endpoint
|
|
14
|
-
* @param {String}
|
|
15
|
-
* @param {String} password The password for the GeoServer REST API
|
|
16
|
+
* @param {String} auth The Basic Authentication string
|
|
16
17
|
*/
|
|
17
|
-
constructor (url,
|
|
18
|
-
this.url = url
|
|
19
|
-
this.
|
|
20
|
-
this.password = password;
|
|
18
|
+
constructor (url, auth) {
|
|
19
|
+
this.url = url;
|
|
20
|
+
this.auth = auth;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Returns all default styles.
|
|
25
25
|
*
|
|
26
|
-
* @
|
|
26
|
+
* @throws Error if request fails
|
|
27
|
+
*
|
|
28
|
+
* @returns {Object} An object with the default styles
|
|
27
29
|
*/
|
|
28
30
|
async getDefaults () {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
method: 'GET',
|
|
35
|
-
headers: {
|
|
36
|
-
Authorization: 'Basic ' + auth
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (response.status === 200) {
|
|
41
|
-
return await response.json();
|
|
42
|
-
} else {
|
|
43
|
-
console.warn(await response.text());
|
|
44
|
-
return false;
|
|
31
|
+
const response = await fetch(this.url + 'styles.json', {
|
|
32
|
+
credentials: 'include',
|
|
33
|
+
method: 'GET',
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: this.auth
|
|
45
36
|
}
|
|
46
|
-
}
|
|
47
|
-
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
41
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
48
42
|
}
|
|
43
|
+
return response.json();
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
/**
|
|
@@ -53,76 +48,80 @@ export default class StyleClient {
|
|
|
53
48
|
*
|
|
54
49
|
* @param {String} workspace Workspace name to get styles for
|
|
55
50
|
*
|
|
56
|
-
* @
|
|
51
|
+
* @throws Error if request fails
|
|
52
|
+
*
|
|
53
|
+
* @returns {Object} An object with all styles
|
|
57
54
|
*/
|
|
58
55
|
async getInWorkspace (workspace) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
method: 'GET',
|
|
65
|
-
headers: {
|
|
66
|
-
Authorization: 'Basic ' + auth
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (response.status === 200) {
|
|
71
|
-
return await response.json();
|
|
72
|
-
} else {
|
|
73
|
-
console.warn(await response.text());
|
|
74
|
-
return false;
|
|
56
|
+
const response = await fetch(this.url + 'workspaces/' + workspace + '/styles.json', {
|
|
57
|
+
credentials: 'include',
|
|
58
|
+
method: 'GET',
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: this.auth
|
|
75
61
|
}
|
|
76
|
-
}
|
|
77
|
-
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
66
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
78
67
|
}
|
|
68
|
+
return response.json();
|
|
79
69
|
}
|
|
80
70
|
|
|
81
71
|
/**
|
|
82
72
|
* Returns all styles defined in workspaces.
|
|
83
73
|
*
|
|
84
|
-
* @
|
|
74
|
+
* @throws Error if request fails
|
|
75
|
+
*
|
|
76
|
+
* @returns {Object[]} An array with all style objects
|
|
85
77
|
*/
|
|
86
78
|
async getAllWorkspaceStyles () {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
const allStyles = [];
|
|
80
|
+
const ws = new WorkspaceClient(this.url, this.auth);
|
|
81
|
+
const allWs = await ws.getAll();
|
|
82
|
+
|
|
83
|
+
if (!allWs ||
|
|
84
|
+
!allWs.workspaces ||
|
|
85
|
+
!allWs.workspaces.workspace ||
|
|
86
|
+
!Array.isArray(allWs.workspaces.workspace)) {
|
|
87
|
+
throw new GeoServerResponseError('Response of available workspaces is malformed');
|
|
88
|
+
}
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
// go over all workspaces and query the styles for
|
|
91
|
+
for (let i = 0; i < allWs.workspaces.workspace.length; i++) {
|
|
92
|
+
const ws = allWs.workspaces.workspace[i];
|
|
93
|
+
const wsStyles = await this.getInWorkspace(ws.name);
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
95
|
+
if (wsStyles.styles.style) {
|
|
96
|
+
wsStyles.styles.style.forEach(wsStyle => {
|
|
97
|
+
allStyles.push(wsStyle);
|
|
98
|
+
});
|
|
102
99
|
}
|
|
103
|
-
|
|
104
|
-
return allStyles;
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return false;
|
|
107
100
|
}
|
|
101
|
+
|
|
102
|
+
return allStyles;
|
|
108
103
|
}
|
|
109
104
|
|
|
110
105
|
/**
|
|
111
106
|
* Returns all styles as combined object (default ones and those in
|
|
112
107
|
* workspaces).
|
|
113
108
|
*
|
|
114
|
-
* @returns {Object
|
|
109
|
+
* @returns {Object[]} An array with all style objects
|
|
115
110
|
*/
|
|
116
111
|
async getAll () {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
112
|
+
const defaultStyles = await this.getDefaults();
|
|
113
|
+
const wsStyles = await this.getAllWorkspaceStyles();
|
|
114
|
+
if (
|
|
115
|
+
!defaultStyles ||
|
|
116
|
+
!defaultStyles.styles ||
|
|
117
|
+
!defaultStyles.styles.style ||
|
|
118
|
+
!Array.isArray(defaultStyles.styles.style)
|
|
119
|
+
) {
|
|
120
|
+
throw new GeoServerResponseError('Response of default styles malformed')
|
|
125
121
|
}
|
|
122
|
+
const allStyles = defaultStyles.styles.style.concat(wsStyles);
|
|
123
|
+
|
|
124
|
+
return allStyles;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
/**
|
|
@@ -132,29 +131,22 @@ export default class StyleClient {
|
|
|
132
131
|
* @param {String} name Name of the style
|
|
133
132
|
* @param {String} sldBody SLD style (as XML text)
|
|
134
133
|
*
|
|
135
|
-
* @
|
|
134
|
+
* @throws Error if request fails
|
|
136
135
|
*/
|
|
137
136
|
async publish (workspace, name, sldBody) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
body: sldBody
|
|
148
|
-
});
|
|
137
|
+
const response = await fetch(this.url + 'workspaces/' + workspace + '/styles?name=' + name, {
|
|
138
|
+
credentials: 'include',
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: this.auth,
|
|
142
|
+
'Content-Type': 'application/vnd.ogc.sld+xml'
|
|
143
|
+
},
|
|
144
|
+
body: sldBody
|
|
145
|
+
});
|
|
149
146
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
console.warn(await response.text());
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return false;
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
149
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
158
150
|
}
|
|
159
151
|
}
|
|
160
152
|
|
|
@@ -165,8 +157,6 @@ export default class StyleClient {
|
|
|
165
157
|
* @param {String} name The name of the style to delete
|
|
166
158
|
* @param {Boolean} [recurse=false] If references to the specified style in existing layers should be deleted
|
|
167
159
|
* @param {Boolean} [purge=false] Whether the underlying file containing the style should be deleted on disk
|
|
168
|
-
*
|
|
169
|
-
* @returns {Boolean} If the style could be deleted
|
|
170
160
|
*/
|
|
171
161
|
async delete (workspace, name, recurse, purge) {
|
|
172
162
|
let paramPurge = false;
|
|
@@ -179,117 +169,121 @@ export default class StyleClient {
|
|
|
179
169
|
paramRecurse = true;
|
|
180
170
|
}
|
|
181
171
|
|
|
182
|
-
|
|
183
|
-
const auth = Buffer.from(this.user + ':' + this.password).toString('base64');
|
|
184
|
-
let endpoint;
|
|
172
|
+
let endpoint;
|
|
185
173
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
174
|
+
if (workspace) {
|
|
175
|
+
// delete style inside workspace
|
|
176
|
+
endpoint = this.url + 'workspaces/' + workspace + '/styles/' + name +
|
|
189
177
|
'?' + 'purge=' + paramPurge + '&' + 'recurse=' + paramRecurse;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
178
|
+
} else {
|
|
179
|
+
// delete style without workspace
|
|
180
|
+
endpoint = this.url + 'styles/' + name +
|
|
193
181
|
'?' + 'purge=' + paramPurge + '&' + 'recurse=' + paramRecurse;
|
|
194
|
-
|
|
182
|
+
}
|
|
195
183
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
184
|
+
const response = await fetch(endpoint, {
|
|
185
|
+
credentials: 'include',
|
|
186
|
+
method: 'DELETE',
|
|
187
|
+
headers: {
|
|
188
|
+
Authorization: this.auth
|
|
189
|
+
}
|
|
190
|
+
});
|
|
203
191
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
194
|
+
switch (response.status) {
|
|
195
|
+
case 403:
|
|
196
|
+
throw new GeoServerResponseError(
|
|
197
|
+
'Deletion failed. There might be dependant layers to this style. Delete them first or call this with "recurse=false"',
|
|
198
|
+
geoServerResponse
|
|
199
|
+
);
|
|
200
|
+
default:
|
|
201
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
214
202
|
}
|
|
215
|
-
} catch (error) {
|
|
216
|
-
return false;
|
|
217
203
|
}
|
|
218
204
|
}
|
|
219
205
|
|
|
220
206
|
/**
|
|
221
207
|
* Assigns a style to a layer.
|
|
222
208
|
*
|
|
223
|
-
* @param {String}
|
|
209
|
+
* @param {String} workspaceOfLayer The name of the layer's workspace, can be undefined
|
|
210
|
+
* @param {String} layerName The name of the layer to query
|
|
211
|
+
* @param {String} workspaceOfStyle The workspace of the style, can be undefined
|
|
224
212
|
* @param {String} styleName The name of the style
|
|
225
|
-
* @param {String} [workspaceStyle] The workspace of the style
|
|
226
213
|
* @param {Boolean} [isDefaultStyle=true] If the style should be the default style of the layer
|
|
227
214
|
*
|
|
228
|
-
* @
|
|
215
|
+
* @throws Error if request fails
|
|
229
216
|
*/
|
|
230
|
-
async assignStyleToLayer (
|
|
231
|
-
|
|
232
|
-
|
|
217
|
+
async assignStyleToLayer (workspaceOfLayer, layerName, workspaceOfStyle, styleName, isDefaultStyle) {
|
|
218
|
+
let qualifiedName;
|
|
219
|
+
if (workspaceOfLayer) {
|
|
220
|
+
qualifiedName = `${workspaceOfLayer}:${layerName}`;
|
|
221
|
+
} else {
|
|
222
|
+
qualifiedName = layerName;
|
|
223
|
+
}
|
|
224
|
+
const styleBody = await this.getStyleInformation(workspaceOfStyle, styleName);
|
|
233
225
|
|
|
234
|
-
|
|
226
|
+
let url;
|
|
227
|
+
// we set the style as defaultStyle, unless user explicitly provides 'false'
|
|
228
|
+
if (isDefaultStyle !== false) {
|
|
229
|
+
url = this.url + 'layers/' + qualifiedName + '/styles?default=true';
|
|
230
|
+
} else {
|
|
231
|
+
url = this.url + 'layers/' + qualifiedName + '/styles';
|
|
232
|
+
}
|
|
235
233
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
234
|
+
const response = await fetch(url, {
|
|
235
|
+
credentials: 'include',
|
|
236
|
+
method: 'POST',
|
|
237
|
+
headers: {
|
|
238
|
+
Authorization: this.auth,
|
|
239
|
+
'Content-Type': 'application/json'
|
|
240
|
+
},
|
|
241
|
+
body: JSON.stringify(styleBody)
|
|
242
|
+
});
|
|
245
243
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.warn(await response.text());
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
} catch (error) {
|
|
253
|
-
return false;
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
246
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
254
247
|
}
|
|
255
248
|
}
|
|
256
249
|
|
|
257
250
|
/**
|
|
258
251
|
* Get information about a style.
|
|
259
252
|
*
|
|
253
|
+
* @param {String} workspace The name of the workspace, can be undefined
|
|
260
254
|
* @param {String} styleName The name of the style
|
|
261
|
-
* @param {String} [workspace] The name of the workspace
|
|
262
255
|
*
|
|
263
|
-
* @
|
|
256
|
+
* @throws Error if request fails
|
|
257
|
+
*
|
|
258
|
+
* @returns {Object} An object about the style or undefined if it cannot be found
|
|
264
259
|
*/
|
|
265
|
-
async getStyleInformation (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
260
|
+
async getStyleInformation (workspace, styleName) {
|
|
261
|
+
let url;
|
|
262
|
+
if (workspace) {
|
|
263
|
+
url = this.url + 'workspaces/' + workspace + '/styles/' + styleName + '.json';
|
|
264
|
+
} else {
|
|
265
|
+
url = this.url + 'styles/' + styleName + '.json';
|
|
266
|
+
}
|
|
269
267
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
const response = await fetch(url, {
|
|
269
|
+
credentials: 'include',
|
|
270
|
+
method: 'GET',
|
|
271
|
+
headers: {
|
|
272
|
+
Authorization: this.auth
|
|
275
273
|
}
|
|
274
|
+
});
|
|
276
275
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
if (response.status === 200) {
|
|
286
|
-
return await response.json();
|
|
276
|
+
if (!response.ok) {
|
|
277
|
+
const grc = new AboutClient(this.url, this.auth);
|
|
278
|
+
if (await grc.exists()) {
|
|
279
|
+
// GeoServer exists, but requested item does not exist, we return empty
|
|
280
|
+
return;
|
|
287
281
|
} else {
|
|
288
|
-
|
|
289
|
-
|
|
282
|
+
// There was a general problem with GeoServer
|
|
283
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
284
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
290
285
|
}
|
|
291
|
-
} catch (error) {
|
|
292
|
-
return false;
|
|
293
286
|
}
|
|
287
|
+
return response.json();
|
|
294
288
|
}
|
|
295
289
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions and classes
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Return the GeoServer response text if available.
|
|
7
|
+
*
|
|
8
|
+
* @param {Response} response The response of the GeoServer
|
|
9
|
+
*
|
|
10
|
+
* @returns {String} The response text if available
|
|
11
|
+
*/
|
|
12
|
+
async function getGeoServerResponseText (response) {
|
|
13
|
+
try {
|
|
14
|
+
return response.text()
|
|
15
|
+
} catch (e) {
|
|
16
|
+
// return nothing
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generic GeoServer error
|
|
22
|
+
*/
|
|
23
|
+
class GeoServerResponseError extends Error {
|
|
24
|
+
/**
|
|
25
|
+
* @param {String} [message=GeoServer Response Error] The error message
|
|
26
|
+
* @param {String} [geoServerOutput] The error output from GeoServer (useful for debugging)
|
|
27
|
+
*/
|
|
28
|
+
constructor (message, geoServerOutput) {
|
|
29
|
+
super(message)
|
|
30
|
+
this.name = 'GeoServerResponseError';
|
|
31
|
+
this.message = message || 'GeoServer Response Error'
|
|
32
|
+
|
|
33
|
+
// custom property as explained here: https://xjamundx.medium.com/custom-javascript-errors-in-es6-aa891b173f87
|
|
34
|
+
this.geoServerOutput = geoServerOutput;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
getGeoServerResponseText,
|
|
40
|
+
GeoServerResponseError
|
|
41
|
+
}
|