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/LICENSE +25 -0
- package/README.md +81 -9
- 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 +28 -10
- 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 +200 -147
- 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/DOCS_HOME.md +0 -24
- 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 -491
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,184 +48,242 @@ 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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
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
|
+
}
|
|
89
|
+
|
|
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);
|
|
103
94
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
if (wsStyles.styles.style) {
|
|
96
|
+
wsStyles.styles.style.forEach(wsStyle => {
|
|
97
|
+
allStyles.push(wsStyle);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
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
|
/**
|
|
129
128
|
* Publishes a new SLD style.
|
|
130
129
|
*
|
|
131
|
-
* @param {String} workspace The workspace to publish style in
|
|
130
|
+
* @param {String} workspace The workspace to publish the style in
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
});
|
|
146
|
+
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
149
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Deletes a style.
|
|
155
|
+
*
|
|
156
|
+
* @param {String} workspace The name of the workspace, can be undefined if style is not assigned to a workspace
|
|
157
|
+
* @param {String} name The name of the style to delete
|
|
158
|
+
* @param {Boolean} [recurse=false] If references to the specified style in existing layers should be deleted
|
|
159
|
+
* @param {Boolean} [purge=false] Whether the underlying file containing the style should be deleted on disk
|
|
160
|
+
*/
|
|
161
|
+
async delete (workspace, name, recurse, purge) {
|
|
162
|
+
let paramPurge = false;
|
|
163
|
+
let paramRecurse = false;
|
|
164
|
+
|
|
165
|
+
if (purge === true) {
|
|
166
|
+
paramPurge = true;
|
|
167
|
+
}
|
|
168
|
+
if (recurse === true) {
|
|
169
|
+
paramRecurse = true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let endpoint;
|
|
173
|
+
|
|
174
|
+
if (workspace) {
|
|
175
|
+
// delete style inside workspace
|
|
176
|
+
endpoint = this.url + 'workspaces/' + workspace + '/styles/' + name +
|
|
177
|
+
'?' + 'purge=' + paramPurge + '&' + 'recurse=' + paramRecurse;
|
|
178
|
+
} else {
|
|
179
|
+
// delete style without workspace
|
|
180
|
+
endpoint = this.url + 'styles/' + name +
|
|
181
|
+
'?' + 'purge=' + paramPurge + '&' + 'recurse=' + paramRecurse;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const response = await fetch(endpoint, {
|
|
185
|
+
credentials: 'include',
|
|
186
|
+
method: 'DELETE',
|
|
187
|
+
headers: {
|
|
188
|
+
Authorization: this.auth
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
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);
|
|
155
202
|
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return false;
|
|
158
203
|
}
|
|
159
204
|
}
|
|
160
205
|
|
|
161
206
|
/**
|
|
162
207
|
* Assigns a style to a layer.
|
|
163
208
|
*
|
|
164
|
-
* @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
|
|
165
212
|
* @param {String} styleName The name of the style
|
|
166
|
-
* @param {String} [workspaceStyle] The workspace of the style
|
|
167
213
|
* @param {Boolean} [isDefaultStyle=true] If the style should be the default style of the layer
|
|
168
214
|
*
|
|
169
|
-
* @
|
|
215
|
+
* @throws Error if request fails
|
|
170
216
|
*/
|
|
171
|
-
async assignStyleToLayer (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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);
|
|
225
|
+
|
|
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
|
+
}
|
|
233
|
+
|
|
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
|
+
});
|
|
243
|
+
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
246
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
195
247
|
}
|
|
196
248
|
}
|
|
197
249
|
|
|
198
250
|
/**
|
|
199
251
|
* Get information about a style.
|
|
200
252
|
*
|
|
253
|
+
* @param {String} workspace The name of the workspace, can be undefined
|
|
201
254
|
* @param {String} styleName The name of the style
|
|
202
|
-
* @param {String} [workspace] The name of the workspace
|
|
203
255
|
*
|
|
204
|
-
* @
|
|
256
|
+
* @throws Error if request fails
|
|
257
|
+
*
|
|
258
|
+
* @returns {Object} An object about the style or undefined if it cannot be found
|
|
205
259
|
*/
|
|
206
|
-
async getStyleInformation (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
url = this.url + 'workspaces/' + workspace + '/styles/' + styleName + '.json';
|
|
214
|
-
} else {
|
|
215
|
-
url = this.url + 'styles/' + styleName + '.json';
|
|
216
|
-
}
|
|
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
|
+
}
|
|
217
267
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
268
|
+
const response = await fetch(url, {
|
|
269
|
+
credentials: 'include',
|
|
270
|
+
method: 'GET',
|
|
271
|
+
headers: {
|
|
272
|
+
Authorization: this.auth
|
|
273
|
+
}
|
|
274
|
+
});
|
|
225
275
|
|
|
226
|
-
|
|
227
|
-
|
|
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;
|
|
228
281
|
} else {
|
|
229
|
-
|
|
230
|
-
|
|
282
|
+
// There was a general problem with GeoServer
|
|
283
|
+
const geoServerResponse = await getGeoServerResponseText(response);
|
|
284
|
+
throw new GeoServerResponseError(null, geoServerResponse);
|
|
231
285
|
}
|
|
232
|
-
} catch (error) {
|
|
233
|
-
return false;
|
|
234
286
|
}
|
|
287
|
+
return response.json();
|
|
235
288
|
}
|
|
236
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
|
+
}
|