jskos-server 2.4.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.
Files changed (112) hide show
  1. package/.dockerignore +20 -0
  2. package/.editorconfig +9 -0
  3. package/.github/workflows/docker.yml +59 -0
  4. package/.github/workflows/gh-pages.yml +23 -0
  5. package/.github/workflows/gh-release.yml +19 -0
  6. package/.github/workflows/test.yml +39 -0
  7. package/.husky/pre-commit +1 -0
  8. package/CHANGELOG.md +18 -0
  9. package/LICENSE +21 -0
  10. package/README.md +2710 -0
  11. package/bin/extra.js +81 -0
  12. package/bin/import.js +438 -0
  13. package/bin/mongodb.js +21 -0
  14. package/bin/reset.js +257 -0
  15. package/bin/upgrade.js +34 -0
  16. package/config/config.default.json +88 -0
  17. package/config/config.schema.json +877 -0
  18. package/config/config.test.json +107 -0
  19. package/config/index.js +77 -0
  20. package/config/setup.js +212 -0
  21. package/depdendencies.png +0 -0
  22. package/docker/.env +1 -0
  23. package/docker/Dockerfile +20 -0
  24. package/docker/README.md +175 -0
  25. package/docker/docker-compose.yml +29 -0
  26. package/docker/docker-entrypoint.sh +8 -0
  27. package/docker/mongo-initdb.d/mongo_setup.sh +22 -0
  28. package/ecosystem.example.json +7 -0
  29. package/errors/index.js +94 -0
  30. package/eslint.config.js +17 -0
  31. package/index.js +10 -0
  32. package/models/annotations.js +13 -0
  33. package/models/concepts.js +12 -0
  34. package/models/concordances.js +12 -0
  35. package/models/index.js +33 -0
  36. package/models/mappings.js +20 -0
  37. package/models/meta.js +21 -0
  38. package/models/registries.js +12 -0
  39. package/models/schemes.js +12 -0
  40. package/package.json +91 -0
  41. package/routes/annotations.js +83 -0
  42. package/routes/common.js +86 -0
  43. package/routes/concepts.js +64 -0
  44. package/routes/concordances.js +86 -0
  45. package/routes/data.js +19 -0
  46. package/routes/mappings.js +108 -0
  47. package/routes/registries.js +24 -0
  48. package/routes/schemes.js +72 -0
  49. package/routes/validate.js +37 -0
  50. package/server.js +190 -0
  51. package/services/abstract.js +328 -0
  52. package/services/annotations.js +237 -0
  53. package/services/concepts.js +459 -0
  54. package/services/concordances.js +264 -0
  55. package/services/data.js +30 -0
  56. package/services/index.js +34 -0
  57. package/services/mappings.js +978 -0
  58. package/services/registries.js +319 -0
  59. package/services/schemes.js +318 -0
  60. package/services/validate.js +39 -0
  61. package/status.schema.json +145 -0
  62. package/test/abstract-service.js +36 -0
  63. package/test/annotations/annotation.json +13 -0
  64. package/test/api.js +2481 -0
  65. package/test/chai.js +14 -0
  66. package/test/changes.js +179 -0
  67. package/test/concepts/conceptNoFileEnding +4 -0
  68. package/test/concepts/concepts-ddc-6-60-61-62.json +123 -0
  69. package/test/concordances/concordances.ndjson +2 -0
  70. package/test/config.js +26 -0
  71. package/test/configs/complex-config.json +90 -0
  72. package/test/configs/empty-object.json +1 -0
  73. package/test/configs/fail-array.json +1 -0
  74. package/test/configs/fail-empty.json +0 -0
  75. package/test/configs/fail-mapping-only-props1.json +5 -0
  76. package/test/configs/fail-mapping-only-props2.json +5 -0
  77. package/test/configs/fail-mapping-only-props3.json +5 -0
  78. package/test/configs/fail-mapping-only-props4.json +5 -0
  79. package/test/configs/fail-nonexisting-prop.json +3 -0
  80. package/test/configs/fail-port-string.json +3 -0
  81. package/test/configs/fail-registry-types.json +16 -0
  82. package/test/configs/registry-types.json +16 -0
  83. package/test/data-write.js +784 -0
  84. package/test/eslint.js +22 -0
  85. package/test/import-reset.js +287 -0
  86. package/test/infer-mappings.js +340 -0
  87. package/test/ipcheck.js +287 -0
  88. package/test/mappings/README.md +1 -0
  89. package/test/mappings/ddc-gnd-1.mapping.json +33 -0
  90. package/test/mappings/ddc-gnd-2.mapping.json +67 -0
  91. package/test/mappings/mapping-ddc-gnd-noScheme.json +145 -0
  92. package/test/mappings/mapping-ddc-gnd.json +175 -0
  93. package/test/mappings/mappings-ddc.json +214 -0
  94. package/test/registries/registries.ndjson +2 -0
  95. package/test/services.js +557 -0
  96. package/test/terminologies/terminologies.json +94 -0
  97. package/test/test-utils.js +182 -0
  98. package/test/utils.js +425 -0
  99. package/test/validate.js +226 -0
  100. package/utils/adjust.js +206 -0
  101. package/utils/auth.js +154 -0
  102. package/utils/changes.js +88 -0
  103. package/utils/db.js +106 -0
  104. package/utils/ipcheck.js +76 -0
  105. package/utils/middleware.js +636 -0
  106. package/utils/searchHelper.js +153 -0
  107. package/utils/status.js +77 -0
  108. package/utils/users.js +7 -0
  109. package/utils/utils.js +114 -0
  110. package/utils/uuid.js +6 -0
  111. package/utils/version.js +324 -0
  112. package/views/base.ejs +172 -0
package/README.md ADDED
@@ -0,0 +1,2710 @@
1
+ # JSKOS Server
2
+
3
+ [![GitHub release](https://img.shields.io/github/release/gbv/jskos-server.svg)](https://github.com/gbv/jskos-server/releases/latest)
4
+ [![API Status](https://coli-conc-status.fly.dev/api/badge/2/status?label=API)](https://coli-conc.gbv.de/api/)
5
+ [![License](https://img.shields.io/github/license/gbv/jskos-server.svg)](https://github.com/gbv/jskos-server/blob/main/LICENSE)
6
+ [![Docker](https://img.shields.io/badge/Docker-ghcr.io%2Fgbv%2Fjskos--server-informational)](https://github.com/gbv/jskos-server/blob/main/docker/README.md)
7
+ [![Test](https://github.com/gbv/jskos-server/actions/workflows/test.yml/badge.svg)](https://github.com/gbv/jskos-server/actions/workflows/test.yml)
8
+ [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg)](https://github.com/RichardLitt/standard-readme)
9
+
10
+ > Web service to access [JSKOS] data.
11
+
12
+ JSKOS Server implements the JSKOS API web service and storage for [JSKOS] data such as controlled vocabularies, concepts, and concept mappings.
13
+
14
+ ## Table of Contents <!-- omit in toc -->
15
+ - [Install](#install)
16
+ - [Requirements](#requirements)
17
+ - [Docker](#docker)
18
+ - [Configuration](#configuration)
19
+ - [User accounts](#user-accounts)
20
+ - [Access control](#access-control)
21
+ - [Authentication](#authentication)
22
+ - [Data Import](#data-import)
23
+ - [Usage](#usage)
24
+ - [Run Server](#run-server)
25
+ - [Supplemental Scripts](#supplemental-scripts)
26
+ - [Use as Module](#use-as-module)
27
+ - [Development and Testing](#development-and-testing)
28
+ - [API](#api)
29
+ - [General](#general)
30
+ - [GET /status](#get-status)
31
+ - [GET /checkAuth](#get-checkauth)
32
+ - [POST /validate](#post-validate)
33
+ - [GET /validate](#get-validate)
34
+ - [GET /data](#get-data)
35
+ - [GET /concordances](#get-concordances)
36
+ - [GET /concordances/:\_id](#get-concordances_id)
37
+ - [POST /concordances](#post-concordances)
38
+ - [PUT /concordances/:\_id](#put-concordances_id)
39
+ - [PATCH /concordances/:\_id](#patch-concordances_id)
40
+ - [DELETE /concordances/:\_id](#delete-concordances_id)
41
+ - [GET /mappings](#get-mappings)
42
+ - [GET /mappings/suggest](#get-mappingssuggest)
43
+ - [GET /mappings/voc](#get-mappingsvoc)
44
+ - [GET /mappings/infer](#get-mappingsinfer)
45
+ - [GET /mappings/:\_id](#get-mappings_id)
46
+ - [POST /mappings](#post-mappings)
47
+ - [PUT /mappings/:\_id](#put-mappings_id)
48
+ - [PATCH /mappings/:\_id](#patch-mappings_id)
49
+ - [DELETE /mappings/:\_id](#delete-mappings_id)
50
+ - [GET /voc](#get-voc)
51
+ - [POST /voc](#post-voc)
52
+ - [PUT /voc](#put-voc)
53
+ - [DELETE /voc](#delete-voc)
54
+ - [GET /voc/top](#get-voctop)
55
+ - [GET /voc/concepts](#get-vocconcepts)
56
+ - [DELETE /voc/concepts](#delete-vocconcepts)
57
+ - [GET /voc/suggest](#get-vocsuggest)
58
+ - [GET /voc/search](#get-vocsearch)
59
+ - [GET /concepts](#get-concepts)
60
+ - [POST /concepts](#post-concepts)
61
+ - [PUT /concepts](#put-concepts)
62
+ - [DELETE /concepts](#delete-concepts)
63
+ - [GET /concepts/narrower](#get-conceptsnarrower)
64
+ - [GET /concepts/ancestors](#get-conceptsancestors)
65
+ - [GET /concepts/suggest](#get-conceptssuggest)
66
+ - [GET /concepts/search](#get-conceptssearch)
67
+ - [GET /registries](#get-registries)
68
+ - [GET /registries/suggest](#get-registriessuggest)
69
+ - [POST /registries](#post-registries)
70
+ - [PUT /registries](#put-registries)
71
+ - [DELETE /registries](#delete-registries)
72
+ - [GET /annotations](#get-annotations)
73
+ - [GET /annotations/:\_id](#get-annotations_id)
74
+ - [POST /annotations](#post-annotations)
75
+ - [PUT /annotations/:\_id](#put-annotations_id)
76
+ - [PATCH /annotations/:\_id](#patch-annotations_id)
77
+ - [DELETE /annotations/:\_id](#delete-annotations_id)
78
+ - [Change Stream Endpoints](#change-stream-endpoints)
79
+ - [Errors](#errors)
80
+ - [Deployment](#deployment)
81
+ - [Notes about depolyment on Ubuntu](#notes-about-depolyment-on-ubuntu)
82
+ - [Update an instances deployed with PM2](#update-an-instances-deployed-with-pm2)
83
+ - [Daily Import](#daily-import)
84
+ - [Running Behind a Reverse Proxy](#running-behind-a-reverse-proxy)
85
+ - [Data flow](#data-flow)
86
+ - [Related works](#related-works)
87
+ - [Maintainers](#maintainers)
88
+ - [Contribute](#contribute)
89
+ - [Publish](#publish)
90
+ - [License](#license)
91
+
92
+ ## Install
93
+
94
+ ### Requirements
95
+
96
+ You need Node.js 22 or higher and access to a [MongoDB database](https://docs.mongodb.com/manual/installation/) (minimun v4; v6 or v7 recommended).
97
+
98
+ To enable optional [Change Stream endpoints](#change-stream-endpoints) the MongoDB database must be configured as a replica set. When using Docker please refer to [our Docker documentation](docker/README.md) for instructions on setting up a replica set. For a non‐Docker setup, start `mongod` with the `--replSet` flag, then once connect with the [MongoDB Shell](https://www.mongodb.com/docs/mongodb-shell/) and execute:
99
+
100
+ ```js
101
+ rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:27017" }] });
102
+ ```
103
+
104
+ If the replica set is initialized, JSKOS Server will detect it at startup (the `replSetGetStatus` command is retried up to `changes.retries` times). If Change Streams [are configured](#change-streams-configuration) but no replica set was detected, JSKOS Server will log an error during startup but continue running with Change Streams disabled.
105
+
106
+ ### Docker
107
+
108
+ The easiest way to install and use JSKOS Server as stand-alone application is with Docker and Docker Compose. Please refer to [our Docker documentation](docker/README.md) for more information and instructions.
109
+
110
+ ### Configuration
111
+
112
+ You can customize the application settings via a configuration file. By default, this configuration file resides in `config/config.json`. However, it is possible to adjust this path via the `CONFIG_FILE` environment variable. Note that the given path has to be either absolute (i.e. starting with `/`) or relative to the `config/` folder (i.e. it defaults to `./config.json`). **Note** that the path to the configuration file needs to be valid and writable because a `namespace` key will be generated and written to the file if it doesn't currently exist. **Note** that if the file exists and contains invalid JSON data, JSKOS Server will refuse to start.
113
+
114
+ Currently, there are only two environment variables:
115
+ - `NODE_ENV` - either `development` (default) or `production`; currently, the only difference is that in `production`, HTTPS URIs are forced for entities created on POST requests.
116
+ - `CONFIG_FILE` - alternate path to a configuration file, relative to the `config/` folder; defaults to `./config.json`.
117
+
118
+ You can either provide the environment variables during the command to start the server, or in a `.env` file in the root folder.
119
+
120
+ It is also possible to have more specific configuration based on the environment. These are set in `config/config.development.json` or `config/config.production.json`. Values from these files have precedent over the user configuration.
121
+
122
+ #### Validation of configuration
123
+
124
+ The provided configuration files (user config and environment config) will be validated with the provided [JSON Schema](https://json-schema.org) file under `config/config.schema.json` (public URI: https://gbv.github.io/jskos-server/status.schema.json). If validation fails, **JSON Server will refuse to start!** Please check whether your configuration is correct after each change. If there is something wrong, the console output will try to provide you with enough detail to fix the issue.
125
+
126
+ Function `validateConfig` is exported for [used as module](#use-as-module):
127
+
128
+ ~~~js
129
+ import { validateConfig } from "jskos-server"
130
+
131
+ try {
132
+ validateConfig(config)
133
+ } catch(error) {
134
+ console.error(`Invalid configuration: ${error}`)
135
+ }
136
+ ~~~
137
+
138
+ #### Default configuration
139
+
140
+ All missing keys will be defaulted from `config/config.default.json`. See [endpoint configuration](#endpoint-configuration) below for additional settings being merged into the configuration.
141
+
142
+ ```json
143
+ {
144
+ "verbosity": "warn",
145
+ "baseUrl": null,
146
+ "env": "development",
147
+ "title": "JSKOS Server",
148
+ "version": null,
149
+ "closedWorldAssumption": true,
150
+ "port": 3000,
151
+ "proxies": [],
152
+ "mongo": {
153
+ "user": "",
154
+ "pass": "",
155
+ "host": "127.0.0.1",
156
+ "port": 27017,
157
+ "db": "jskos-server",
158
+ "options": {
159
+ "connectTimeoutMS": 360000,
160
+ "socketTimeoutMS": 360000,
161
+ "heartbeatFrequencyMS": 10000
162
+ }
163
+ },
164
+ "auth": {
165
+ "algorithm": "RS256",
166
+ "key": null
167
+ },
168
+ "schemes": true,
169
+ "concepts": true,
170
+ "mappings": {
171
+ "read": {
172
+ "auth": false
173
+ },
174
+ "create": {
175
+ "auth": true
176
+ },
177
+ "update": {
178
+ "auth": true,
179
+ "crossUser": false
180
+ },
181
+ "delete": {
182
+ "auth": true,
183
+ "crossUser": false
184
+ },
185
+ "fromSchemeWhitelist": null,
186
+ "toSchemeWhitelist": null,
187
+ "cardinality": "1-to-n"
188
+ },
189
+ "concordances": true,
190
+ "registries": {
191
+ "read": {
192
+ "auth": false
193
+ },
194
+ "create": {
195
+ "auth": true
196
+ },
197
+ "update": {
198
+ "auth": true,
199
+ "crossUser": false
200
+ },
201
+ "delete": {
202
+ "auth": true,
203
+ "crossUser": false
204
+ },
205
+ "mixedTypes": false
206
+ },
207
+ "annotations": {
208
+ "read": {
209
+ "auth": false
210
+ },
211
+ "create": {
212
+ "auth": true
213
+ },
214
+ "update": {
215
+ "auth": true,
216
+ "crossUser": false
217
+ },
218
+ "delete": {
219
+ "auth": true,
220
+ "crossUser": false
221
+ },
222
+ "moderatingIdentities": [],
223
+ "mismatchTagVocabulary": null
224
+ },
225
+ "changes": false,
226
+ "anonymous": false,
227
+ "identityProviders": null,
228
+ "identityGroups": {},
229
+ "identities": null,
230
+ "ips": null
231
+ }
232
+ ```
233
+
234
+ #### Server configuration
235
+
236
+ If you are [running jskos-server behind a reverse proxy](#running-behind-a-reverse-proxy), it is necessary to provide the `baseUrl` key as well as the `proxies` key in your configuration. For example:
237
+
238
+ ```json
239
+ {
240
+ "baseUrl": "https://coli-conc.gbv.de/api/",
241
+ "proxies": ["123.456.789.101", "234.567.891.011"]
242
+ }
243
+ ```
244
+
245
+ #### Endpoint Configuration
246
+
247
+ With the keys `schemes`, `concepts`, `mappings`, `concordances`, `registries`, and `annotations`, you can configure whether endpoints related to the specific functionality should be available. A minimal configuration file to just server read-only vocabulary and concept information could look like this:
248
+
249
+ ```json
250
+ {
251
+ "mappings": false,
252
+ "annotations": false,
253
+ "concordances": false
254
+ }
255
+ ```
256
+
257
+ Available actions for each of these endpoints are `read`, `create`, `update`, and `delete`. By default, all types can be read, while `mappings`, `annotations`, and `registries` can be created, updated, and deleted with authentication.
258
+
259
+ Explanations for additional options:
260
+
261
+ - **`auth`**: Boolean. Can be defined only on actions. Defines whether access will require [authentication via JWT](#authentication). By default `false` for `read`, and `true` for all other actions.
262
+
263
+ - **`crossUser`**: Boolean or list of URI strings. Can be defined only on `update` and `delete` actions when `auth` is `true`. Defines whether it is possible to edit an entity from a different user than the authenticated one (`true` = allowed for all users, list = allowed for specified user URIs). `false` by default.
264
+
265
+ - **`anonymous`**: Boolean. Can be defined on any level (deeper levels will take the values from higher levels if necessary\*). If set, no creator and contributor is saved. `false` by default.
266
+
267
+ - **`cardinality`**: String. Can be defined only on type `mappings`. Currently possible values: `1-to-n` (default), `1-to-1`. If `1-to-1` is configured, mappings with multiple concepts in `to` will be rejected.
268
+
269
+ - **`identities`**: List of URI strings. Can be defined on any level (deeper levels will take the values from higher levels if necessary\*). If set, an action with `auth` set to `true` can only be used by users with an URI given in the list. `null` by default (no restrictions).
270
+
271
+ - **`identityProviders`**: List of strings. Can be defined on any level (deeper levels will take the values from higher levels if necessary\*). If set, an action can only be used by users who have that identity associated with them. `null` by default (no restrictions).
272
+
273
+ - **`identityGroups`**: Object mapping URIs to objects with only field `identities`. Keys of this option can be used in field `identities` elsewhere in the configuration to refer to a group of identities.
274
+
275
+ - **`ips`**: List of strings. Strings can be IPv4 addresses (e.g. `127.0.0.1`, `123.234.123.234`) or CIDR ranges (e.g. `192.168.0.1/24`). Can be defined on any level (deeper levels will take the values from higher levels if necessary\*). If set, an action can only be used by clients with a whitelisted IP address. `null` by default (no restrictions). Note: An empty array will allow all IPs. Note: This property will be removed for security reasons when accessing [GET /status](#get-status) (meaning that clients will not be able to see the whitelisted IP addresses).
276
+
277
+ - **`fromSchemeWhitelist`/`toSchemeWhitelist`**: Can be defined only on type `mappings`. List of scheme objects that are allowed for `fromScheme`/`toScheme` respectively. `null` allows all schemes.
278
+
279
+ - **`mismatchTagVocabulary`**: Can be defined only on type `annotations`. A [JSKOS Concept Schemes] object with required property `uri`. When configured, concept URIs belonging to this vocabulary can be used to tag mapping mismatches in mapping annotations. See [below](#mapping-mismatch-tagging-for-negative-assessment-annotations) for detailed information about configuration and usage of this feature.
280
+
281
+ \* Only applies to actions `create`, `update`, and `delete`.
282
+
283
+ Note that any properties not mentioned here are not allowed!
284
+
285
+ #### Origin of URIs
286
+
287
+ **This fields are hardcoded in the current version so they don't affect configuration yet!**
288
+
289
+ The `create` field of configuration can have two field that control where URIs of newly created URIs come from:
290
+
291
+ - **`uriBase`**: a string or Boolean (false by default). Value true is replaced by the baseUrl of the server. URIs of newly created items must start with this string.
292
+ - **`uriOrigin`**: where URIs of new items orgin from. Default value `external` requires clients to provide an URI. Value `uuid` can be used when `uriBase` is set to generate URIs based on UUIDs.
293
+
294
+ #### Registries configuration
295
+
296
+ Endpoint configuration key `registries` can further contain key **`types`** to control object types collected in registries. By default it is set to `true` for every type with endpoint enabled in [endpoint configuration](#endpoint configuration). Setting a type to `false` will disallow creation and import of [registry](https://gbv.github.io/jskos/#registry) having this field. By default, a registry can only have one type of members. Registry configuration key **`mixedTypes`** can be set to true to allow registries to have multiple member types.
297
+
298
+ Member types can further the configured with three Boolean keys:
299
+
300
+ - **`uriRequired`** (default `true`) whether members must have a valid field `uri`
301
+ - **`mustExist`** (default `false`) whether members must exist in the database (and have the right type)
302
+ - **`skipInvalid`** (default `false`) to filter out members that don't fulfill requirement or `uriRequired` or `mustExist`
303
+
304
+ Setting `mustExist` to true and `uriRequired` to false results in an invalid configuration because URIs are required to check whether an item exists.
305
+
306
+ **Example**:
307
+ ~~~json
308
+ {
309
+ "types": {
310
+ "schemes": true,
311
+ "concepts": {
312
+ "uriRequired": true,
313
+ "mustExist": false,
314
+ "skipInvalid": false
315
+ },
316
+ },
317
+ "mixedTypes": true
318
+ }
319
+ ~~~
320
+
321
+ #### Change Streams Configuration
322
+
323
+ [Change Stream Endpoints](#change-stream-endpoints) are only enabled if `changes` is set to `true` or to an object with the following optional keys:
324
+
325
+ - **`retries`** (integer, default `20`)
326
+ How many times to retry the `replSetGetStatus` command while waiting for the replica set to initialise before giving up.
327
+
328
+ - **`interval`** (integer, default `5000`)
329
+ Milliseconds to wait between each retry attempt when checking replica-set status.
330
+
331
+ Only once the replica set is confirmed will the `/…/changes` endpoints become active, unless MongoDB does is not running with replica set.
332
+
333
+ #### Mapping Mismatch Tagging for Negative Assessment Annotations
334
+
335
+ To differentiate why a mapping was annotated with a negative assessment, a mismatch tagging vocabulary can now be configured under `annotations.mismatchTagVocabulary`. In theory, any vocabulary can be used, but [our instance](https://coli-conc.gbv.de/api/) will use a very small "mismatch" vocabulary available in https://github.com/gbv/jskos-data/tree/master/mismatch.
336
+
337
+ To set up mapping mismatch tagging, add the vocabulary to the configuration:
338
+
339
+ ```json
340
+ {
341
+ "annotations": {
342
+ "mismatchTagVocabulary": {
343
+ "uri": "https://uri.gbv.de/terminology/mismatch/"
344
+ }
345
+ }
346
+ }
347
+ ```
348
+
349
+ Currently, the vocabulary and its concepts are required to be imported in the same JSKOS Server instance:
350
+
351
+ ```bash
352
+ # Import vocabulary metadata
353
+ npm run import schemes https://raw.githubusercontent.com/gbv/jskos-data/master/mismatch/mismatch-scheme.json
354
+ # Reset existing concepts (e.g. if old version has been imported previously)
355
+ npm run reset -- -t concepts -s "https://uri.gbv.de/terminology/mismatch/"
356
+ # Import vocabulary concepts
357
+ npm run import concepts -- --set-api https://raw.githubusercontent.com/gbv/jskos-data/master/mismatch/mismatch-concepts.json
358
+ ```
359
+
360
+ After restarting JSKOS Server, mapping mismatch tagging is available for annotations. To add such a tag to an annotation, add a `body` field like this:
361
+
362
+ ```json
363
+ {
364
+ "motivation": "assessing",
365
+ "bodyValue": "-1",
366
+ "body": [
367
+ {
368
+ "type": "SpecificResource",
369
+ "value": "https://uri.gbv.de/terminology/mismatch/scope",
370
+ "purpose": "tagging"
371
+ }
372
+ ]
373
+ }
374
+ ```
375
+
376
+ Currently, this is the only supported format, i.e. `body` as an array containing an object with `type` of "SpecificResource", `purpose` of "tagging", and the tag concept's URI as `value`.
377
+
378
+ To identify whether a JSKOS Server instance supports this kind of tagging, check the `/status` endpoint for the `config.annotations.mismatchTagVocabulary` key.
379
+
380
+ ### User accounts
381
+
382
+ jskos-server does not store user accounts but refers to external identity providers and JSON Web Tokens (JWT) for [authentication](#authentication). Users are identified from field `user` of a valid JWT passed to jskos-server with a request, having the following subfields:
383
+
384
+ - **`uri`** primary identity of the user.
385
+ - **`name`** optional name of the user for display (must be a string)
386
+ - **`identities`** optional object mapping names of identity providers to identities, each having field
387
+ - **`uri`** additional identities of the user
388
+ - **`name`** optional name of the user for display
389
+ - optional arbitrary fields
390
+ - optional arbitrary fields
391
+
392
+ Optional arbitrary fields don't have semantics in jskos-server and their values are never written into the database but they can be used for extended access control.
393
+
394
+ So a user can have multiple identities, each being an URI. For example, the following user has ORCID `https://orcid.org/0000-0002-2771-9344` and the fictitious GitHub account `https://github.com/account`. Both can be used interchangeably for [access control](#access-control), but the ORCID is stored (as part of field `creator` or `contributor`) when entities are written into the database.
395
+
396
+ ~~~json
397
+ {
398
+ "uri": "https://orcid.org/0000-0002-2771-9344",
399
+ "name": "Sofia",
400
+ "affiliation": "http://example.org/university",
401
+ "identities": {
402
+ "github": {
403
+ "uri": "https://github.com/account",
404
+ "name": "Sofia Coding"
405
+ }
406
+ ]
407
+ }
408
+ ~~~
409
+
410
+ User names are not unique and not mandatory. Identity and user name can also be passed with query parameters `identity` and `identityName`, respectively. The latter can be set to any string, including the empty string to avoid any user name being written to the database. Query parameter `identity` is ignored if authentication is enabled and its value does not match any of the identities listed in the JWT used for authentication.
411
+
412
+ User groups are not fully supported yet (see [this issue](https://github.com/gbv/jskos-server/issues/232)) but
413
+
414
+ - identities can be grouped in configuration of access control with `identityGroups`.
415
+ - access control can be limited to identity providers with `identityProviders`.
416
+
417
+ ### Access control
418
+
419
+ The rights to `read`, `create`, `update` and `delete` entities via API can be controlled via several configuration settings described above ([data import](#data-import) is not limited by these restrictions):
420
+
421
+ * Restricted access via `ips` is always applied *in addition* to other settings
422
+
423
+ * Without [authentication](#authentication) (`auth` set to `false`) the server does not know about user accounts. In this case the `creator` and `contributor` fields of an object can be set without limitations (default) or they are ignored when `anonymous` is set to `true`.
424
+
425
+ * With authentication an action can be limited to accounts listed in `identities` (if set). Rights to `create`, `update`, and `delete` entities can further depend on two controls:
426
+
427
+ 1. value of `creator` and `contributor` of a superordinated object. Concepts always belong to vocabularies via `inScheme` or `topConceptOf` and mappings can belong to concordances via `partOf`.
428
+ 2. settings of `crossUser` together with value of `creator` and `contributor` of the object
429
+
430
+ The first control is only checked if it has a superordinated object with `contributor` and/or `creator`. This can only be the case for mappings and concepts. The connection to a superordinated object is checked on both the stored object and its modified value, so moving a mapping from one concordance to another is only allowed if access is granted for both. The authenticated user must be listed as `creator` or `contributor` of the superordinated object to pass this control.
431
+
432
+ The second control is only checked when the first control cannot be applied and only on authenticated actions `update` or `delete` where `anonymous` is set to `false` (this is the default). With `crossUser` set to `false`, the authenticated user must be listed as `creator` of the stored object. With `crossUser` set to `true` any authenticated user (optionally limited to those listed in `identities`) can `update` or `delete` the object.
433
+
434
+ For authenticated actions with `anonymous` being `false` creation of a new object will always set its initial `creator` to the autenticated user and `update` of an object will always add the user to `contributor` unless it is already included as `creator` or `contributor`. Further modification of `creator` and `contributor` (removal and addition of entries) is limited to vocabularies and concordance by authenticated users listed as `creator` of the object.
435
+
436
+ Here are some helpful example presets for configuration of "concordances, "mappings", "annotations", or "registries".
437
+
438
+ **Read-only access (does not make sense for annotations):**
439
+ ```json
440
+ {
441
+ "read": {
442
+ "auth": false
443
+ }
444
+ }
445
+ ```
446
+
447
+ **Anyone can create, but only logged-in users can update and delete (and only their own items):**
448
+ ```json
449
+ {
450
+ "read": {
451
+ "auth": false
452
+ },
453
+ "create": {
454
+ "auth": false
455
+ },
456
+ "update": {
457
+ "auth": true,
458
+ "crossUser": false
459
+ },
460
+ "delete": {
461
+ "auth": true,
462
+ "crossUser": false
463
+ }
464
+ }
465
+ ```
466
+
467
+ **Anyone can create, logged-in users can update (independent of creator), logged-in users can delete their own items:**
468
+ ```json
469
+ {
470
+ "read": {
471
+ "auth": false
472
+ },
473
+ "create": {
474
+ "auth": false
475
+ },
476
+ "update": {
477
+ "auth": true,
478
+ "crossUser": true
479
+ },
480
+ "delete": {
481
+ "auth": true,
482
+ "crossUser": false
483
+ }
484
+ }
485
+ ```
486
+
487
+ **Anyone can create, as well as update and delete, independent of creator:**
488
+ ```json
489
+ {
490
+ "read": {
491
+ "auth": false
492
+ },
493
+ "create": {
494
+ "auth": false
495
+ },
496
+ "update": {
497
+ "auth": false,
498
+ "crossUser": true
499
+ },
500
+ "delete": {
501
+ "auth": false,
502
+ "crossUser": true
503
+ }
504
+ }
505
+ ```
506
+
507
+ If write access for concept schemes and/or concepts is necessary, it is recommended that they are secured by only allowing certain users (via `identities`) or only allowing certain IP addresses (via `ips`):
508
+
509
+ **Only user with URI `https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619` can write:**
510
+ ```json
511
+ {
512
+ "read": {
513
+ "auth": false
514
+ },
515
+ "create": {
516
+ "auth": true,
517
+ "identities": ["https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619"]
518
+ },
519
+ "update": {
520
+ "auth": true,
521
+ "identities": ["https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619"]
522
+ },
523
+ "delete": {
524
+ "auth": true,
525
+ "identities": ["https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619"]
526
+ }
527
+ }
528
+ ```
529
+
530
+ **Only localhost can write:**
531
+
532
+ ```json
533
+ {
534
+ "read": {
535
+ "auth": false
536
+ },
537
+ "create": {
538
+ "auth": false,
539
+ "ips": ["127.0.0.1"]
540
+ },
541
+ "update": {
542
+ "auth": false,
543
+ "ips": ["127.0.0.1"]
544
+ },
545
+ "delete": {
546
+ "auth": false,
547
+ "ips": ["127.0.0.1"]
548
+ }
549
+ }
550
+ ```
551
+ Note that `auth` is set to `false` because it refers to authentication via JWT. The IP filter is separate from that. An even more secure way would be to use both JWT authentication with an `identities` filter as well as an IP filter.
552
+
553
+ **Only user with URI `https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619` can create, but others can update/delete if they are creator/contributor of an entity:**
554
+ ```json
555
+ {
556
+ "read": {
557
+ "auth": false
558
+ },
559
+ "create": {
560
+ "auth": true,
561
+ "identities": ["https://coli-conc.gbv.de/login/users/c0c1914a-f9d6-4b92-a624-bf44118b6619"]
562
+ },
563
+ "update": {
564
+ "auth": true
565
+ },
566
+ "delete": {
567
+ "auth": true
568
+ }
569
+ }
570
+ ```
571
+ A configuration like this will be used to handle concordances in Cocoda. Only selected accounts will be able to create new concordances, but they will be able to add other accounts as creator/contributor so that those accounts will be able to assign mappings to the concordance and edit mappings that belong to the concordance.
572
+
573
+ ### Authentication
574
+ It is possible to limit certain actions to authenticated users, indicated by the `auth` option (see [example configurations above](#access-control)). Authorization is performed via JWTs ([JSON Web Tokens](https://jwt.io/)). To configure authentication, you need to provide the JWT algorithm and the key/secret in the configuration file, like this:
575
+
576
+ ```json
577
+ "auth": {
578
+ "algorithm": "RS256",
579
+ "key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA57ZWRoOjXYTQ9yujxAu7\ne3k4+JRBAqGdDVIRRq5vXB2D5nJBIhQjVjylumn+QnTX/MdZx8qn7X96npUwHwIh\nylCgUmsYXcjP08X/AXEcP5bPOkgBBCKjWmcm+p01RQSOM0nSptyxpyXzr2ppWe1b\nuYdRYDWj+JV7vm+jJA4NiFv4UnAhoG5lRATADzu0/6wpMK3dVMBL7L0jQoV5xBAb\nLADOy5hD9XEII3VPkUqDGIKM+Z24flkCIf0lQ7FjsoZ2mmM1SZJ5vPDcjMKreFkX\ncWlcwGHN0PUWZWLhb7c8yYa1rauMcwFwv0d2XyOEfgkqEJdCh8mVT/5jR48D2PNG\ncwIDAQAB\n-----END PUBLIC KEY-----\n"
580
+ }
581
+ ```
582
+
583
+ The JWT has to be provided as a Bearer token in the authorization header, e.g. `Authorization: Bearer <token>`. The authentication is designed to be used together with an instance of [login-server], but it is also possible to use your own JWTs.
584
+
585
+ #### JWT Example
586
+ The recommended Node.js library for creating JWTs is [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken). Note that for simplicity, we are using the HS256 algorithm which is symmetrical. In most cases, it would be better to use RS256 with a libarary like [node-rsa](https://github.com/rzcoder/node-rsa) instead.
587
+
588
+ Simple config, restricting the `/mappings` endpoint with authentication:
589
+ ```json
590
+ {
591
+ "auth": {
592
+ "algorithm": "HS256",
593
+ "key": "yoursecret"
594
+ },
595
+ "mappings": {
596
+ "read": {
597
+ "auth": true
598
+ }
599
+ }
600
+ }
601
+ ```
602
+
603
+ Creating a JWT:
604
+ ```js
605
+ const jwt = require("jsonwebtoken")
606
+ // Payload is an object containing the user object with an URI:
607
+ const data = {
608
+ user: { uri: "urn:test:hallo" }
609
+ }
610
+ // Sign the token with our secret
611
+ const token = jwt.sign(data, "yoursecret", {
612
+ algorithm: "HS256",
613
+ expiresIn: "7d" // valid for 7 days
614
+ })
615
+ ```
616
+
617
+ Using the token in a request (using curl):
618
+ ```bash
619
+ # Request without header should return ForbiddenAccessError (code 403)
620
+ curl localhost:3000/mappings
621
+ # Request with header should return JSON data (insert your own token and jskos-server URL of course)
622
+ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVyaSI6InRlc3Q6aGFsbG8ifSwiaWF0IjoxNTg5NTMyNDU3LCJleHAiOjE1OTAxMzcyNTd9.fXIxgS0QyFk9Lvz7Z-fkb4tAueMTSNZ4zAuB6iwePq4" localhost:3000/mappings
623
+ ```
624
+
625
+ If you are the only user that is supposed to be authenticated for your instance of jskos-server, you could in theory use something like this to create a token with a long lifetime and use it for all your requests. Please consider the security implications before doing this though.
626
+
627
+ #### Login Server Example
628
+ If you have multiple users using your instance of jskos-server, it is recommended to use [login-server] for authentication. login-server uses the asymmetrical RS256 algorithm by default and will create a public/private key pair on first launch. The public key will be in `./public.key` and you will need that for the configuration:
629
+
630
+ ```json
631
+ {
632
+ "auth": {
633
+ "algorith": "RS256",
634
+ "key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA57ZWRoOjXYTQ9yujxAu7\ne3k4+JRBAqGdDVIRRq5vXB2D5nJBIhQjVjylumn+QnTX/MdZx8qn7X96npUwHwIh\nylCgUmsYXcjP08X/AXEcP5bPOkgBBCKjWmcm+p01RQSOM0nSptyxpyXzr2ppWe1b\nuYdRYDWj+JV7vm+jJA4NiFv4UnAhoG5lRATADzu0/6wpMK3dVMBL7L0jQoV5xBAb\nLADOy5hD9XEII3VPkUqDGIKM+Z24flkCIf0lQ7FjsoZ2mmM1SZJ5vPDcjMKreFkX\ncWlcwGHN0PUWZWLhb7c8yYa1rauMcwFwv0d2XyOEfgkqEJdCh8mVT/5jR48D2PNG\ncwIDAQAB\n-----END PUBLIC KEY-----\n"
635
+ }
636
+ }
637
+ ```
638
+
639
+ After that, you can use [login-client](https://github.com/gbv/login-client) to interact with your login-server instance and receive JWTs. When using WebSockets, login-server will periodically send a new JWT before the previous one expires. You can then use that to authenticate your requests to jskos-server. (An example on how to use login-client can be found in the [source code of login-server](https://github.com/gbv/login-server/blob/master/views/api.ejs).)
640
+
641
+ For testing your authentication without a full-fledged solution using login-client, you can use http://localhost:3004/token (where `localhost:3004` is your instance of login-server) to request a JWT.
642
+
643
+ ### Data Import
644
+ JSKOS Server provides scripts to import JSKOS data into the database or delete data from the database. Right now, mappings, terminologies (concept schemes), concepts, concordances, and annotations, in JSON (object or array of objects) or [NDJSON](http://ndjson.org) format are supported.
645
+
646
+ #### Import Script
647
+ By default the import script has enabled **bulk import** so invalid entities are filtered out and reported only.
648
+
649
+ Examples of using the import script:
650
+ ```bash
651
+
652
+ # Create indexes for all types
653
+ npm run import -- --indexes
654
+ # Import RVK scheme (from coli-conc API)
655
+ npm run import -- schemes https://coli-conc.gbv.de/rvk/api/voc
656
+ # Import RVK concepts (this will take a while)
657
+ npm run import -- concepts https://coli-conc.gbv.de/rvk/data/2019_1/rvko_2019_1.ndjson
658
+ # Import coli-conc concordances
659
+ npm run import -- concordances https://coli-conc.gbv.de/api/concordances
660
+
661
+ # Batch import multiple files or URLs
662
+ npm run import-batch -- mappings files.txt
663
+ # files.txt should contain one file or URL per line with the full path and no escaping.
664
+ # You can, for example, store these batch import files in folder `imports` which is ignored in git.
665
+ ```
666
+
667
+ **Note: If you have concepts in your database, make sure to run `npm run import -- --indexes` at least once. This will make sure all necessary indexes are created. Without this step, the `/concepts/suggest` and `/concepts/search` endpoints will not work.**
668
+
669
+ For more information about the import script, run `npm run import -- --help`.
670
+
671
+ #### Reset Script
672
+ It is also possible to delete entities from the server via the command line. Running the command will first determine what exactly will be deleted and ask you for confirmation:
673
+ ```bash
674
+ # Will delete everything from database
675
+ npm run reset
676
+ # Will delete mappings from database
677
+ npm run reset -- -t mappings
678
+ # Will delete all concepts that belong to a certain concept scheme URI
679
+ npm run reset -- -s http://uri.gbv.de/terminology/rvk/
680
+ # Will delete all mappings that belong to a certain concordance URI
681
+ npm run reset -- -c https://gbv.github.io/jskos/context.json
682
+ # Will delete entities with certain URIs
683
+ npm run reset -- http://rvk.uni-regensburg.de/nt/A http://rvk.uni-regensburg.de/nt/B
684
+ # Will show help for more information
685
+ npm run reset -- --help
686
+ ```
687
+
688
+ For scripting, you can use the `yes` command to skip confirmation. **Make sure you know what you're doing!** Example: `yes | npm run reset -- urn:test:uri`.
689
+
690
+ #### Specifics of importing concepts
691
+ Only the `broader` field will be used during import of concepts: both `ancestors` and `narrower` will be removed and the respective endpoints ([GET /concepts/ancestors](#get-conceptsancestors) and [GET /concepts/narrower](#get-conceptsnarrower)) will dynamically rebuild these properties. That means that when converting your data, please normalize it so that the hierarchy is expressed via the `broader` field in JSKOS.
692
+
693
+ Example scheme (as JSON object) with concepts in a hierarchy (as NDJSON):
694
+ ```json
695
+ {
696
+ "uri": "urn:test:scheme",
697
+ "notation": [
698
+ "TEST"
699
+ ],
700
+ "uriPattern": "^urn:test:concept-(.+)$"
701
+ }
702
+ ```
703
+ ```json
704
+ { "topConceptOf": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-a" }
705
+ { "inScheme": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-a.1", "broader": [{ "uri": "urn:test:concept-a" }] }
706
+ { "inScheme": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-a.2", "broader": [{ "uri": "urn:test:concept-a" }] }
707
+ { "topConceptOf": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-b" }
708
+ { "inScheme": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-b.1", "broader": [{ "uri": "urn:test:concept-b" }] }
709
+ { "inScheme": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-b.1.1", "broader": [{ "uri": "urn:test:concept-b.1" }] }
710
+ { "inScheme": [{ "uri": "urn:test:scheme" }], "uri": "urn:test:concept-b.1.2", "broader": [{ "uri": "urn:test:concept-b.1" }] }
711
+ ```
712
+
713
+ (Note that a notation for the concepts can be omitted because we have defined `uriPattern` on the concept scheme. Also, we don't need to define `inScheme` for concepts with `topConceptOf`.)
714
+
715
+ #### Specifics of importing concept schemes
716
+ The import script uses the bulk write endpoints to import data. For concept schemes, this means that any existing data for imported schemes will be **overwritten** and replaced with the new data. This includes especially the `created` property which might not exist in your source data and will be set on import if necessary. If you need a consistent `created` date, make sure that your source data already includes this field.
717
+
718
+
719
+ ## Usage
720
+
721
+ ### Run Server
722
+
723
+ ```bash
724
+ # Development server with hot reload and auto reconnect at localhost:3000 (default)
725
+ npm run start
726
+
727
+ # To run the server in production, run this:
728
+ NODE_ENV=production node ./server.js
729
+ ```
730
+
731
+ ### Supplemental Scripts
732
+
733
+ In addition to [data import](#data-import) there are some supplemental scripts that were added to deal with specific sitatuations. These can be called with `npm run extra name-of-script`. The following scripts are available:
734
+
735
+ - `supplementNotationsInMappings`: This will look for mappings where the field `notation` is missing for any of the concepts, and it will attempt to supplement those notations. This only works for vocabularies which are also imported into the same jskos-server instance and where either `uriPattern` or `namespace` are given.
736
+
737
+ ### Use as Module
738
+
739
+ *Use as module is experimental. Authentication is ignored on direct access to services!*
740
+
741
+ ~~~js
742
+ import { validateConfig, createServices } from "jskos-server"
743
+
744
+ try {
745
+ validateConfig(config)
746
+ } catch(error) {
747
+ console.error(`Invalid configuration: ${error}`)
748
+ }
749
+
750
+ const services = createServices(config)
751
+
752
+ const scheme = await services.scheme.getScheme(schemeUri)
753
+ ~~~
754
+
755
+ ### Development and Testing
756
+
757
+ Tests use an ephemeral, in-memory MongoDB server powered by [mongodb-memory-server](https://www.npmjs.com/package/mongodb-memory-server).
758
+
759
+ ```bash
760
+ npm test
761
+ ```
762
+
763
+ This will:
764
+
765
+ 1. **Start** a MongoDB (sometimes also a replica-set) entirely in memory.
766
+ 2. **Connect** Mongoose to that in-memory server.
767
+ 3. **Create** all JSKOS collections & indexes via services.
768
+ 4. **Drop** the database before and after each test suite, ensuring full isolation.
769
+ 5. **Tear down** the in-memory server when the suite completes.
770
+
771
+ Code coverage can be calculated with `npm run coverage` but numbers should be taken with a grain of salt. By the way, lines of code can be calculated with `cloc $(git ls-files)`.
772
+
773
+ You can also start an in-memory MongoDB with local configuration:
774
+
775
+ ```bash
776
+ npm run mongodb # not verbose
777
+ npm run mongodb -- --debug # very verbose
778
+ ```
779
+
780
+ And then start jskos-server:
781
+
782
+ ```bash
783
+ npm run start
784
+ ```
785
+
786
+ ## API
787
+
788
+ ### General
789
+
790
+ All API methods stick to the following rules, unless otherwise specified.
791
+
792
+ #### Requests
793
+ - All URL parameters are optional.
794
+ - `POST`/`PUT`/`PATCH` requests require a JSON body.
795
+ - Alternatively, `POST` can also receive the following inputs:
796
+ - any kind of JSON stream
797
+ - mutlipart/form-data with the file in `data`
798
+ - a URL with JSON data as `url` in the request params
799
+ - Note: The `type` request param might be required (either `json`, `ndjson`, or `multipart`)
800
+ - All `GET` endpoints returning a certain type of JSKOS data offer the `properties=[list]` parameter, with `[list]` being a comma-separated list of properties.
801
+ - All JSKOS types allow removing properties by prefixing the property with `-`. All following properties in the list will also be removed.
802
+ - For concepts and mappings, the property `annotations` can be specified to add all annotations in the database for a certain item.
803
+ - For concepts, the properties `narrower` and `ancestors` can be specified to add narrower/ancestor concepts to a certain concept.
804
+ - Specifying a `*` adds all available properties.
805
+ - Example: `properties=*,-narrower,notation` will add properties `annotations` and `ancestors`, and remove the `notation` property from all return items.
806
+ - Properties can be explicitly re-added by prefixing them with `+`, e.g. `properties=-from,to,+from` will only remove the `to` property.
807
+ - Note that the `+` sign has to be properly encoded as `%2B`, otherwise it will be interpreted as a space.
808
+ - All `GET` endpoints (except for `/status` and those with `:_id`) offer pagination via `limit=[number]` (default: 100) and `offset=[number]` (default: 0) parameters. In the response, there will be a `Link` header like described in the [GitHub API documentation](https://developer.github.com/v3/#pagination), as well as a `X-Total-Count` header containing the total number of results.
809
+
810
+ #### Write access
811
+ - `POST`/`PUT`/`PATCH`/`DELETE` requests require [authentication](#authentication) via a JWT from [login-server](https://github.com/gbv/login-server) in the header. Exception: Authentication for certain actions on certain endpoints can be disabled (see [configuration](#configuration)).
812
+ - `PUT`/`PATCH`/`DELETE` requests are required to come from the owner of the entity that is being modified.
813
+ - `POST`/`PUT`/`PATCH` endpoints will override `creator` and `contributor` of submitted objects (see [this comment](https://github.com/gbv/jskos-server/issues/122#issuecomment-723029967) for more details)
814
+ - `PATCH` request bodies are merged on the top level, so it's enough to include object properties to be modified. To remove a top-level property, set it to `null`.
815
+
816
+ #### Responses
817
+ - `GET` requests will return code 200 on success.
818
+ - `POST` requests will return code 201 on success.
819
+ - `DELETE` requests will return code 204 on success.
820
+ - For possible error responses, see [Errors](#errors).
821
+
822
+ ### GET /status
823
+ Returns a status object.
824
+
825
+ There is a [JSON Schema](https://json-schema.org) for the format of this endpoint. It is available under `/status.schema.json` for every jskos-server installation (starting from version 1.0.0). The most recent schema can be accessed here: https://gbv.github.io/jskos-server/status.schema.json
826
+
827
+ Note that certain properties from the actual configuration will not be shown in the result for `/status`:
828
+ - `verbosity`
829
+ - `port`
830
+ - `mongo`
831
+ - `namespace`
832
+ - `proxies`
833
+ - `ips` (including inside of actions)
834
+ - `auth.key` if a symmetrical algorithm is used (HS256, HS384, HS512)
835
+
836
+ * **Success Response**
837
+
838
+ ```json
839
+ {
840
+ "config": {
841
+ "env": "development",
842
+ "baseUrl": "http://localhost:3000/",
843
+ "version": "1.1",
844
+ "auth": {
845
+ "algorithm": "RS256",
846
+ "key": null
847
+ },
848
+ "schemes": {
849
+ "read": {
850
+ "auth": false
851
+ }
852
+ },
853
+ "concepts": {
854
+ "read": {
855
+ "auth": false
856
+ }
857
+ },
858
+ "mappings": {
859
+ "read": {
860
+ "auth": false
861
+ },
862
+ "create": {
863
+ "auth": true
864
+ },
865
+ "update": {
866
+ "auth": true,
867
+ "crossUser": false
868
+ },
869
+ "delete": {
870
+ "auth": true,
871
+ "crossUser": false
872
+ },
873
+ "fromSchemeWhitelist": null,
874
+ "toSchemeWhitelist": null,
875
+ "anonymous": false,
876
+ "cardinality": "1-to-n"
877
+ },
878
+ "concordances": {
879
+ "read": {
880
+ "auth": false
881
+ }
882
+ },
883
+ "annotations": {
884
+ "read": {
885
+ "auth": false
886
+ },
887
+ "create": {
888
+ "auth": true
889
+ },
890
+ "update": {
891
+ "auth": true,
892
+ "crossUser": false
893
+ },
894
+ "delete": {
895
+ "auth": true,
896
+ "crossUser": false
897
+ },
898
+ "registries": {
899
+ "read": {
900
+ "auth": false
901
+ },
902
+ "create": {
903
+ "auth": true
904
+ },
905
+ "update": {
906
+ "auth": true,
907
+ "crossUser": false
908
+ },
909
+ "delete": {
910
+ "auth": true,
911
+ "crossUser": false
912
+ },
913
+ "mismatchTagVocabulary": {
914
+ "uri": "https://uri.gbv.de/terminology/mismatch/",
915
+ "API": [
916
+ {
917
+ "type": "http://bartoc.org/api-type/jskos",
918
+ "url": "http://localhost:3000/"
919
+ }
920
+ ]
921
+ }
922
+ },
923
+ "identityProviders": null,
924
+ "identities": null
925
+ },
926
+ "data": "http://localhost:3000/data",
927
+ "schemes": "http://localhost:3000/voc",
928
+ "top": "http://localhost:3000/voc/top",
929
+ "voc-search": "http://localhost:3000/voc/search",
930
+ "voc-suggest": "http://localhost:3000/voc/suggest",
931
+ "voc-concepts": "http://localhost:3000/voc/concepts",
932
+ "concepts": "http://localhost:3000/concepts",
933
+ "narrower": "http://localhost:3000/concepts/narrower",
934
+ "ancestors": "http://localhost:3000/concepts/ancestors",
935
+ "search": "http://localhost:3000/concepts/search",
936
+ "suggest": "http://localhost:3000/concepts/suggest",
937
+ "mappings": "http://localhost:3000/mappings",
938
+ "concordances": "http://localhost:3000/concordances",
939
+ "annotations": "http://localhost:3000/annotations",
940
+ "registries": "http://localhost:3000/registries",
941
+ "types": null,
942
+ "validate": "http://localhost:3000/validate",
943
+ "ok": 1
944
+ }
945
+ ```
946
+
947
+ * **Error Response**
948
+
949
+ In case of an error, for instance a failed database connection, the value of response property `ok` is set to `0`.
950
+
951
+ ### GET /checkAuth
952
+
953
+ Endpoint to check whether a user is authorized (see [user accounts](#user-accounts) and [access control](#access-control)). If `type` or `action` are not set, it will use `identities`, `identityProviders`, and `identityGroups` that are defined directly under config.
954
+
955
+ * **URL Params**
956
+
957
+ `type=[type]` one of "schemes", "concepts", "mappings", "concordances, "registries", "annotations" (optional)
958
+
959
+ `action=[action]` one of "read", "create", "update", "delete" (optional)
960
+
961
+ ### POST /validate
962
+
963
+ Endpoint to validate JSKOS objects via [jskos-validate].
964
+
965
+ * **URL Params**
966
+
967
+ `type=[type]` a [JSKOS object type](https://gbv.github.io/jskos/#object-types) that all objects must have (optional)
968
+
969
+ `unknownFields=[boolean]` with `1` or `true` to allow unknown fields inside objects (by default, unknown fields do not pass validation)
970
+
971
+ `knownSchemes=[boolean]` with `1` or `true` to use concept schemes available in this jskos-server instance for validation of concepts. Implies `type=concept` and all concept must reference a known concept scheme via `inScheme`.
972
+
973
+ If neither `type` nor `knownSchemes` are specified, concept schemes in the data to be validated can be used to validate following concepts in the same request array (see last example below).
974
+
975
+ * **Success Response**
976
+
977
+ Array with the JSON response provided by [jskos-validate]. The indices of the array correspond to the order of the given data. An element is `true` when the object passed validation, or an array of errors when the object failed validation. Data format of error objects may change in future versions but there is always at least field `message`.
978
+
979
+ * **Sample Call**
980
+
981
+ In the following example, an empty object is validated. Since no type is specified, it is validated as a Resource which does not have required field names and therefore passes validation.
982
+
983
+ ```bash
984
+ curl -X POST "https://coli-conc.gbv.de/dev-api/validate" -H 'Content-Type: application/json' -d '{}'
985
+ ```
986
+
987
+ ```json
988
+ [
989
+ true
990
+ ]
991
+ ```
992
+
993
+ In the following example, the same call is given, but the parameter `type` is set to `mapping`. Mappings require the fields `from` and `to`, therefore the empty object fails validation and errors are returned.
994
+
995
+ ```bash
996
+ curl -X POST "https://coli-conc.gbv.de/dev-api/validate?type=mapping" -H 'Content-Type: application/json' -d '{}'
997
+ ```
998
+
999
+ ```json
1000
+ [
1001
+ [
1002
+ {
1003
+ "instancePath": "",
1004
+ "schemaPath": "#/required",
1005
+ "keyword": "required",
1006
+ "params": {
1007
+ "missingProperty": "from"
1008
+ },
1009
+ "message": "must have required property 'from'"
1010
+ },
1011
+ {
1012
+ "instancePath": "",
1013
+ "schemaPath": "#/required",
1014
+ "keyword": "required",
1015
+ "params": {
1016
+ "missingProperty": "to"
1017
+ },
1018
+ "message": "must have required property 'to'"
1019
+ }
1020
+ ]
1021
+
1022
+ ]
1023
+ ```
1024
+
1025
+ In this example, an array of mixed typed objects is validated (given in file `example.json`):
1026
+
1027
+ ```json
1028
+ [
1029
+ {
1030
+ "type": [ "http://www.w3.org/2004/02/skos/core#ConceptScheme" ],
1031
+ "uri": "http://example.org/voc",
1032
+ "notationPattern": "[a-z]+"
1033
+ },
1034
+ {
1035
+ "type": [ "http://www.w3.org/2004/02/skos/core#Concept" ],
1036
+ "uri": "http://example.org/1",
1037
+ "notation": [ "abc" ],
1038
+ "inScheme": [ { "uri": "http://example.org/voc" } ]
1039
+ },
1040
+ {
1041
+ "type": [ "http://www.w3.org/2004/02/skos/core#Concept" ],
1042
+ "uri": "http://example.org/2",
1043
+ "notation": [ "123" ],
1044
+ "inScheme": [ { "uri": "http://example.org/voc" } ]
1045
+ }
1046
+ ]
1047
+ ```
1048
+
1049
+ The first object is a concept scheme with `notationPattern`. Since the other two elements are concepts of that concept scheme (see `inScheme`), the concepts must additionally pass tests related to URI or notation patterns of the given schemes. Since the last concept has a notation that does not match the pattern, it fails the validation. Note that only object with appropriate `type` field are included in this additional part of validation.
1050
+
1051
+ ```bash
1052
+ curl -X POST "https://coli-conc.gbv.de/dev-api/validate" -H 'Content-Type: application/json' -d @example.json
1053
+ ```
1054
+
1055
+ ```json
1056
+ [
1057
+ true,
1058
+ true,
1059
+ [
1060
+ {
1061
+ "message": "concept notation 123 does not match [a-z]+"
1062
+ }
1063
+ ]
1064
+ ]
1065
+ ```
1066
+
1067
+ ### GET /validate
1068
+ Same as [POST /validate](#post-validate) but JSKOS data to be validated is passed via URL.
1069
+
1070
+ * **URL Params**
1071
+
1072
+ `url=[url]` URL to load JSKOS data from
1073
+
1074
+ `type=[type]` see [POST /validate](#post-validate)
1075
+
1076
+ `unknownFields=[boolean]` see [POST /validate](#post-validate)
1077
+
1078
+ `knownSchemes=[boolean]` see [POST /validate](#post-validate)
1079
+
1080
+ ### GET /data
1081
+ Returns data for a certain URI or URIs. Can return concept schemes, concepts, concordances, mappings, annotations, and registries. This endpoint does not offer pagination via `limit` and `offset`. It will always return all results. Furthermore, there is no certain order to the result set (but it should be consistent across requests). If a certain type of data requires authentication and the user is not authenticated, that type of data will simply not be returned.
1082
+
1083
+ **Note:** As of version 2.0, this endpoint was adjusted to return all types of items that are available in the database, instead of just concepts and concept schemes. The additional parameters, apart from `uri`, were also removed. For the previous behavior (only without returning concept schemes), see [GET /concepts](#get-concepts).
1084
+
1085
+ * **URL Params**
1086
+
1087
+ `uri=[uri]` URIs for JSKOS items separated by `|` (annotations, despite using `id` instead of `uri`, can also be queried here)
1088
+
1089
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors`, `narrower`, and `annotations`)
1090
+
1091
+ * **Success Response**
1092
+
1093
+ JSON array of [JSKOS Items]
1094
+
1095
+ ### GET /concordances
1096
+ Lists all concordances for mappings.
1097
+
1098
+ * **URL Params**
1099
+
1100
+ `uri=[uri]` URIs for concordances separated by `|`
1101
+
1102
+ `fromScheme=[uri|notation]` only show concordances from concept scheme (URI or notation) (separated by `|`)
1103
+
1104
+ `toScheme=[uri|notation]` only show concordances to concept scheme (URI or notation) (separated by `|`)
1105
+
1106
+ `creator=[creator]` only show concordances from creator (separated by `|`)
1107
+
1108
+ `mode=[mode]` specify the mode for the parameters above, one of `and` (default) and `or`
1109
+
1110
+ `download=[type]` returns the whole result as a download (available types are `json` and `ndjson`), ignores `limit` and `offset`
1111
+
1112
+ * **Success Response**
1113
+
1114
+ JSON array of [JSKOS Concordances](https://gbv.github.io/jskos/#concordances)
1115
+
1116
+ * **Sample Call**
1117
+
1118
+ ```bash
1119
+ curl https://coli-conc.gbv.de/api/concordances?limit=1
1120
+ ```
1121
+
1122
+ ```json
1123
+ [
1124
+ {
1125
+ "@context": "https://gbv.github.io/jskos/context.json",
1126
+ "creator": [
1127
+ {
1128
+ "prefLabel": {
1129
+ "de": "VZG"
1130
+ }
1131
+ }
1132
+ ],
1133
+ "distributions": [
1134
+ {
1135
+ "download": "https://coli-conc.gbv.de/api/mappings?partOf=http://coli-conc.gbv.de/concordances/ddc_rvk_recht&download=ndjson",
1136
+ "format": "http://format.gbv.de/jskos",
1137
+ "mimetype": "application/x-ndjson; charset=utf-8"
1138
+ }
1139
+ ],
1140
+ "extent": "2267",
1141
+ "fromScheme": {
1142
+ "notation": [
1143
+ "DDC"
1144
+ ],
1145
+ "uri": "http://bartoc.org/en/node/241"
1146
+ },
1147
+ "notation": [
1148
+ "ddc_rvk_recht"
1149
+ ],
1150
+ "scopeNote": {
1151
+ "de": [
1152
+ "Recht"
1153
+ ]
1154
+ },
1155
+ "toScheme": {
1156
+ "notation": [
1157
+ "RVK"
1158
+ ],
1159
+ "uri": "http://bartoc.org/en/node/533"
1160
+ },
1161
+ "type": [
1162
+ "http://rdfs.org/ns/void#Linkset"
1163
+ ],
1164
+ "uri": "http://coli-conc.gbv.de/concordances/ddc_rvk_recht"
1165
+ }
1166
+ ]
1167
+ ```
1168
+
1169
+ ### GET /concordances/:_id
1170
+ Returns a specific concordance.
1171
+
1172
+ * **URL Params**
1173
+
1174
+ None
1175
+
1176
+ * **Success Response**
1177
+
1178
+ JSKOS object for concordance.
1179
+
1180
+ * **Error Response**
1181
+
1182
+ If no concordance with `_id` could be found, it will return a 404 not found error.
1183
+
1184
+ ### POST /concordances
1185
+ Saves one or more concordances in the database. Note that `fromScheme` and `toScheme` must be supported by the jskos-server instance.
1186
+
1187
+ * **URL Params**
1188
+
1189
+ None
1190
+
1191
+ * **Success Reponse**
1192
+
1193
+ JSKOS Concordance object(s) as were saved in the database.
1194
+
1195
+ * **Error Response**
1196
+
1197
+ When a single concordance is provided, an error can be returned if there's something wrong with it (see [errors](#errors)). When multiple concordances are provided, the first error will be returned.
1198
+
1199
+ ### PUT /concordances/:_id
1200
+ Overwrites a concordance in the database.
1201
+
1202
+ * **Success Reponse**
1203
+
1204
+ JSKOS Concordance object as it was saved in the database.
1205
+
1206
+ Note that any changes to the `uri`, `notation`, `fromScheme`, `toScheme`, `extent`, `distributions`, and `created` properties will be ignored. (No error will be thrown in this case.)
1207
+
1208
+ ### PATCH /concordances/:_id
1209
+ Adjusts a concordance in the database.
1210
+
1211
+ * **Success Reponse**
1212
+
1213
+ JSKOS Concordance object as it was saved in the database.
1214
+
1215
+ Note that changes to the properties `uri`, `notation`, `fromScheme`, `toScheme`, `created`, `extent`, and `distributions` are currently not allowed and will result in an [InvalidBodyError](#InvalidBodyError).
1216
+
1217
+ ### DELETE /concordances/:_id
1218
+ Deletes a concordance from the database.
1219
+
1220
+ * **Success Reponse**
1221
+
1222
+ Status 204, no content.
1223
+
1224
+ **Note that only concordances which have no mappings associated can be deleted.**
1225
+
1226
+ ### GET /mappings
1227
+ Returns an array of mappings. Each mapping has a property `uri` under which the specific mapping can be accessed.
1228
+
1229
+ * **URL Params**
1230
+
1231
+ `identifier=[identifier1|identifier2|...]` specify mapping identifiers separated by `|`
1232
+
1233
+ `from=[uriOrNotation1|uriOrNotation2|...]` specify the source URI or notation (truncated search possible by appending a `*`, multiple URIs/notations separated by `|`)
1234
+
1235
+ `fromScheme=[uriOrNotation1|uriOrNotation2|...]` only show mappings from concept scheme (URI or notation, multiple URIs/notations separated by `|`)
1236
+
1237
+ `to=[uriOrNotation1|uriOrNotation2|...]` specify the target URI or notation (truncated search possible by appending a `*`, multiple URIs/notations separated by `|`)
1238
+
1239
+ `toScheme=[uriOrNotation1|uriOrNotation2|...]` only show mappings to concept scheme (URI or notation, multiple URIs/notations separated by `|`)
1240
+
1241
+ `mode=[mode]` specify the mode for `from`/`fromScheme`, `to`/`toScheme`, and `identifier`, one of `and` (default) and `or`; note that 1) multiple values given for a single parameter are always connected via "or", and 2) `from` and `fromScheme` / `to` and `toScheme` are always connected via "and"
1242
+
1243
+ `direction=[direction]` specify the direction of the mapping. Available values are: `forward` (default), `backward` (essentially swaps `from` and `to`), `both` (combines forward and backward).
1244
+
1245
+ `type=[uri1|uri2|...]` only show mappings that conform to a certain type or types (see [JSKOS Concept Mappings]) (URIs separated by `|`)
1246
+
1247
+ `partOf=[uri1|uri2|...]` only show mappings that are part of certain concordances (URIs separated by `|`); value `none` returns mappings that are not part of a concordance, value `any` returns mappings that are part of any concordance
1248
+
1249
+ `creator=[string1|string2|...]` only show mappings that have a certain creator (separated by `|`)
1250
+
1251
+ `annotatedBy=[uri1|uri2|...]` has annotations by user with URI(s)
1252
+
1253
+ `annotatedFor=[motivation]` has annotations with a certain motivation (e.g. `assessing`); value `none` returns mappings that have no annotations at all, value `any` returns mappings that have any kind of annotation, values starting with `!` (e.g. `!assessing`) filter out annotations with that motivation. Note that to mitigate performance issues with negative assertions (`none` or `!xyz`), jskos-server will return the number 9999999 in the `X-Total-Count` header (see [this](https://github.com/gbv/jskos-server/issues/176#issuecomment-1167188606)).
1254
+
1255
+ `annotatedWith=[body]` has annotations with a certain body value (e.g. `+1`) OR has a sum of assessment annotations that conforms to the given comparison operation; for the latter, either `from` or `to` must be given, `annotatedFor` must be either not set or set to `assessing`, and the value of this parameter needs to consist of a comparison operator (`=`, `<`, `>`, `<=`, or `>=`) followed by a number. Example: `annotatedWith=>0` returns mappings with a positive assessment sum (equivalent to `annotatedWith=>=1`).
1256
+
1257
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting only `annotations` for mappings)
1258
+
1259
+ `download=[type]` returns the whole result as a download (available types are `json`, `ndjson`, `csv`, and `tsv`), ignores `limit` and `offset`; **note**: `csv` and `tsv` are restricted (and fixed) to 5 target concepts, meaning that if the data set includes a mapping with more than 5 target concepts, only the first 5 will appear in the export
1260
+
1261
+ `sort=[sort]` sorts by a specific field. Available are `created`, `modified`, and `mappingRelevance` (default). Results will always be additionally sorted by `from.memberSet.uri` and `_id` in order to create a stable and sensible sort.
1262
+
1263
+ `order=[order]` order to use for sorting. Available are `asc` and `desc` (default).
1264
+
1265
+ `cardinality=[cardinality]` cardinality of the mapping. Available are `1-to-n` (default) and `1-to-1`.
1266
+
1267
+ * **Success Response**
1268
+
1269
+ JSON array of [JSKOS Concept Mappings]
1270
+
1271
+ * **Sample Call**
1272
+
1273
+ ```bash
1274
+ curl https://coli-conc.gbv.de/api/mappings?from=http://dewey.info/class/612.116/e23/
1275
+ ```
1276
+
1277
+ ```json
1278
+ [
1279
+ {
1280
+ "from": {
1281
+ "memberSet": [
1282
+ {
1283
+ "uri": "http://dewey.info/class/612.116/e23/",
1284
+ "notation": [
1285
+ "612.116"
1286
+ ]
1287
+ }
1288
+ ]
1289
+ },
1290
+ "to": {
1291
+ "memberSet": [
1292
+ {
1293
+ "uri": "http://rvk.uni-regensburg.de/nt/WW_8800-WW_8839",
1294
+ "notation": [
1295
+ "WW 8800-WW 8839"
1296
+ ]
1297
+ }
1298
+ ]
1299
+ },
1300
+ "fromScheme": {
1301
+ "uri": "http://bartoc.org/en/node/241",
1302
+ "notation": [
1303
+ "DDC"
1304
+ ]
1305
+ },
1306
+ "toScheme": {
1307
+ "uri": "http://bartoc.org/en/node/533",
1308
+ "notation": [
1309
+ "RVK"
1310
+ ]
1311
+ },
1312
+ "identifier": [
1313
+ "urn:jskos:mapping:content:fb92cbed7466764dd2ca5fdf054bf55e65ec6b87",
1314
+ "urn:jskos:mapping:members:5aa92285bba839954baccdadc7df5ef4558860ed"
1315
+ ],
1316
+ "@context": "https://gbv.github.io/jskos/context.json"
1317
+ }
1318
+ ]
1319
+ ```
1320
+
1321
+ ### GET /mappings/suggest
1322
+ Suggests notations used in mappings.
1323
+
1324
+ * **URL Params**
1325
+
1326
+ `search=[notation]` specifies the notation (prefix) to search for
1327
+
1328
+ * **Success Response**
1329
+
1330
+ JSON array of suggestions in [OpenSearch Suggest Format](http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.1#Response_format).
1331
+
1332
+ * **Sample Call**
1333
+
1334
+ ```bash
1335
+ curl https://coli-conc.gbv.de/api/mappings/suggest?search=A&limit=5
1336
+ ```
1337
+
1338
+ ```json
1339
+ [
1340
+ "A",
1341
+ [
1342
+ "AN 74800",
1343
+ "AN 78950",
1344
+ "AN 70000",
1345
+ "AN 71000",
1346
+ "AN 96900"
1347
+ ],
1348
+ [
1349
+ 42,
1350
+ 25,
1351
+ 19,
1352
+ 18,
1353
+ 17
1354
+ ],
1355
+ []
1356
+ ]
1357
+ ```
1358
+
1359
+ ### GET /mappings/voc
1360
+ Lists all concept schemes used in mappings.
1361
+
1362
+ * **URL Params**
1363
+
1364
+ `from=[uri|notation]` restrict mappings to those from a concept
1365
+
1366
+ `to=[uri|notation]` restrict mappings to those to a concept
1367
+
1368
+ `mode=[mode]` specify the mode for `from` and `to`, one of `and` and `or` (default)
1369
+
1370
+ * **Success Response**
1371
+
1372
+ JSON array of [JSKOS Concept Schemes]
1373
+
1374
+ * **Sample Call**
1375
+
1376
+ ```bash
1377
+ curl https://coli-conc.gbv.de/api/mappings/voc?from=612.112&to=612.112
1378
+ ```
1379
+
1380
+ ```json
1381
+ [
1382
+ {
1383
+ "uri": "http://bartoc.org/en/node/430",
1384
+ "notation": [
1385
+ "GND"
1386
+ ],
1387
+ "fromCount": 2
1388
+ },
1389
+ {
1390
+ "uri": "http://bartoc.org/en/node/241",
1391
+ "notation": [
1392
+ "DDC"
1393
+ ],
1394
+ "fromCount": 2,
1395
+ "toCount": 2
1396
+ },
1397
+ {
1398
+ "uri": "http://bartoc.org/en/node/533",
1399
+ "notation": [
1400
+ "RVK"
1401
+ ],
1402
+ "toCount": 2
1403
+ }
1404
+ ]
1405
+ ```
1406
+
1407
+ ### GET /mappings/infer
1408
+ Returns mappings based on stored mappings and mappings derived by inference. If a request to [GET /mappings](#get-mappings) results in stored mappings, only those are returned. If no stored mappings match the request, the following algorithm is applied to infer virtual mappings (this is experimental and not all source schemes are supported):
1409
+
1410
+ - Ancestors of the requested concept (`from`) are traversed from narrower to broader until matching mapping(s) from one of the ancestor concepts are found.
1411
+
1412
+ - The resulting mappings are filtered and transformed based on their mapping type:
1413
+
1414
+ - `exactMatch` and `narrowMatch` result in `narrowMatch` (for instance *Optics < Sciences* when no mappings from *Optics* are stored but e.g. *Physics* is ancestor of *Optics* and mapped to *Sciences*)
1415
+
1416
+ - `closeMatch` results in `narrowMatch` unless query parameter `strict` is set to a true value. In this case mappings of this type are ignored (for instance *Optics* < *Alchemy* when *Physics* is ancestor of *Optics* and mapped to *Alchemy* but this may lead to doubtful mappings such as *Computational Physics* < *Alchemy*)
1417
+
1418
+ - `relatedMatch` and `mappingRelation` are not changed.
1419
+
1420
+ Inferred mappings don't have fields such as `uri`, `identifier`, `creator`, `created`... but `uri` of the mapping used for inference is included in `source`.
1421
+
1422
+ * **URL Params**
1423
+
1424
+ This endpoint takes the same parameters as [GET /mappings](#get-mappings), except that `to`, `download`, and `cardinality` (fixed to "1-to-1") are not supported. Parameter `direction` only supports the default value "forward". Parameters `from` and `fromScheme` are mandatory to get a non-empty result.
1425
+
1426
+ `strict=[boolean]` values `1` or `true` disallow mapping type "closeMatch" for inferred mappings (default `false`)
1427
+
1428
+ `depth=[number]` a non-negative number of the depth used to infer mappings (not set by default); `0` means no inference, `1` means only the next ancestor concept (= broader) is used for inference, etc.
1429
+
1430
+ * **Success Response**
1431
+
1432
+ JSON array of [JSKOS Concept Mappings]
1433
+
1434
+ * **Sample Call**
1435
+
1436
+ ```bash
1437
+ curl https://coli-conc.gbv.de/api/mappings/infer?from=http%3A%2F%2Frvk.uni-regensburg.de%2Fnt%2FWI%25203130&fromScheme=http%3A%2F%2Fbartoc.org%2Fen%2Fnode%2F533&toScheme=http%3A%2F%2Fbartoc.org%2Fen%2Fnode%2F18785
1438
+ ```
1439
+
1440
+ ```json
1441
+ [
1442
+ {
1443
+ "from": {
1444
+ "memberSet": [
1445
+ {
1446
+ "uri": "http://rvk.uni-regensburg.de/nt/WI%203130",
1447
+ "notation": [
1448
+ "WI 3130"
1449
+ ]
1450
+ }
1451
+ ]
1452
+ },
1453
+ "to": {
1454
+ "memberSet": [
1455
+ {
1456
+ "uri": "http://uri.gbv.de/terminology/bk/42.42",
1457
+ "notation": [
1458
+ "42.42"
1459
+ ]
1460
+ }
1461
+ ]
1462
+ },
1463
+ "fromScheme": {
1464
+ "uri": "http://bartoc.org/en/node/533",
1465
+ "notation": [
1466
+ "RVK"
1467
+ ]
1468
+ },
1469
+ "toScheme": {
1470
+ "uri": "http://bartoc.org/en/node/18785",
1471
+ "notation": [
1472
+ "BK"
1473
+ ]
1474
+ },
1475
+ "type": [
1476
+ "http://www.w3.org/2004/02/skos/core#narrowMatch"
1477
+ ],
1478
+ "source": [
1479
+ {
1480
+ "uri": "https://coli-conc.gbv.de/api/mappings/ef121206-a42d-4c3c-9ef3-b597c000acb4"
1481
+ }
1482
+ ],
1483
+ "identifier": [
1484
+ "urn:jskos:mapping:content:1b0fb2343795db4de7e1f8c7207b94a789614a15",
1485
+ "urn:jskos:mapping:members:2d22b62a0295959d587487d228d51836d05b1c50"
1486
+ ],
1487
+ "@context": "https://gbv.github.io/jskos/context.json"
1488
+ },
1489
+ {
1490
+ "from": {
1491
+ "memberSet": [
1492
+ {
1493
+ "uri": "http://rvk.uni-regensburg.de/nt/WI%203130",
1494
+ "notation": [
1495
+ "WI 3130"
1496
+ ]
1497
+ }
1498
+ ]
1499
+ },
1500
+ "to": {
1501
+ "memberSet": [
1502
+ {
1503
+ "uri": "http://uri.gbv.de/terminology/bk/42.44",
1504
+ "notation": [
1505
+ "42.44"
1506
+ ]
1507
+ }
1508
+ ]
1509
+ },
1510
+ "fromScheme": {
1511
+ "uri": "http://bartoc.org/en/node/533",
1512
+ "notation": [
1513
+ "RVK"
1514
+ ]
1515
+ },
1516
+ "toScheme": {
1517
+ "uri": "http://bartoc.org/en/node/18785",
1518
+ "notation": [
1519
+ "BK"
1520
+ ]
1521
+ },
1522
+ "type": [
1523
+ "http://www.w3.org/2004/02/skos/core#narrowMatch"
1524
+ ],
1525
+ "source": [
1526
+ {
1527
+ "uri": "https://coli-conc.gbv.de/api/mappings/6b920456-db5d-49b1-a197-b851df6f9dbd",
1528
+ }
1529
+ ],
1530
+ "identifier": [
1531
+ "urn:jskos:mapping:content:8bb72e1605f9c25b0c97889439e6dde952e0cbd0",
1532
+ "urn:jskos:mapping:members:5870d87ec08c9a9a5ccba182bd96b92ad2f9d688"
1533
+ ],
1534
+ "@context": "https://gbv.github.io/jskos/context.json"
1535
+ }
1536
+ ]
1537
+ ```
1538
+
1539
+ ### GET /mappings/:_id
1540
+ Returns a specific mapping.
1541
+
1542
+ * **URL Params**
1543
+
1544
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting only `annotations` for mappings)
1545
+
1546
+ * **Success Response**
1547
+
1548
+ JSKOS object for mapping.
1549
+
1550
+ * **Error Response**
1551
+
1552
+ If no mapping with `_id` could be found, it will return a 404 not found error.
1553
+
1554
+ * **Sample Call**
1555
+
1556
+ ```bash
1557
+ curl https://coli-conc.gbv.de/api/mappings/5c450ba1a32a4a82d0f3fbf3
1558
+ ```
1559
+
1560
+ ```json
1561
+ {
1562
+ "from": {
1563
+ "memberSet": [
1564
+ {
1565
+ "uri": "http://rvk.uni-regensburg.de/nt/TA-TD",
1566
+ "notation": [
1567
+ "TA - TD"
1568
+ ]
1569
+ }
1570
+ ]
1571
+ },
1572
+ "toScheme": {
1573
+ "template": "http://dewey.info/class/(.+)/e23/",
1574
+ "pattern": "[0-9][0-9]?|[0-9]{3}(-[0-9]{3})?|[0-9]{3}\\.[0-9]+(-[0-9]{3}\\.[0-9]+)?|[1-9][A-Z]?--[0-9]+|[1-9][A-Z]?--[0-9]+(-[1-9][A-Z]?--[0-9]+)?",
1575
+ "uri": "http://bartoc.org/en/node/241",
1576
+ "notation": [
1577
+ "DDC"
1578
+ ]
1579
+ },
1580
+ "fromScheme": {
1581
+ "notation": [
1582
+ "RVK"
1583
+ ],
1584
+ "uri": "http://bartoc.org/en/node/533"
1585
+ },
1586
+ "to": {
1587
+ "memberSet": [
1588
+ {
1589
+ "uri": "http://dewey.info/class/500/e23/",
1590
+ "notation": [
1591
+ "500"
1592
+ ]
1593
+ }
1594
+ ]
1595
+ },
1596
+ "identifier": [
1597
+ "urn:jskos:mapping:content:d37d117b5e3d811447bc332b184ac6e5ac4bde6b",
1598
+ "urn:jskos:mapping:members:4c480744ea32e7e71ba39fae6cc8d8e4e0382912"
1599
+ ],
1600
+ "partOf": [
1601
+ {
1602
+ "uri": "http://coli-conc.gbv.de/concordances/rvk_ddc_ta-td"
1603
+ }
1604
+ ],
1605
+ "creator": [
1606
+ {
1607
+ "prefLabel": {
1608
+ "de": "GESIS"
1609
+ }
1610
+ }
1611
+ ],
1612
+ "url": "https://coli-conc.gbv.de/api/mappings/5c450ba1a32a4a82d0f3fbf3",
1613
+ "@context": "https://gbv.github.io/jskos/context.json"
1614
+ }
1615
+ ```
1616
+
1617
+ ### POST /mappings
1618
+ Saves a mapping or multiple mappings in the database.
1619
+
1620
+ * **URL Params**
1621
+
1622
+ `bulk=[boolean]` `1` or `true` enable bulk mode for importing multiple mappings into the database. Errors for individual mappings will be ignored and existing mappings will be overridden. The resulting set will only include the `id` for each mapping that was written into the database.
1623
+
1624
+ * **Success Reponse**
1625
+
1626
+ JSKOS Mapping object as it was saved in the database, or array of mapping objects with only a `uri` if bulk mode was used..
1627
+
1628
+ * **Error Response**
1629
+
1630
+ When a single mapping is provided, an error can be returned if there's something wrong with it (see [errors](#errors)). When multiple mappings are provided, the first error will be returned, except if bulk mode is enabled in which errors for individual mappings are ignored.
1631
+
1632
+ Note that the `partOf` property is currently not allowed. Associating a mapping with a concordances has to be done in a separate [PUT](#put-mappings_id) or [PATCH](#patch-mappings_id) request.
1633
+
1634
+ ### PUT /mappings/:_id
1635
+ Overwrites a mapping in the database.
1636
+
1637
+ * **Success Reponse**
1638
+
1639
+ JSKOS Mapping object as it was saved in the database.
1640
+
1641
+ Note that any changes to the `created` property will be ignored. Note that changes to `partOf` (i.e. association with a concordance) are only possible if 1) `fromScheme` and `toScheme` are equal between the mapping and the concordance, 2) the authenticated user is creator of the mapping OR if the mapping is already part of a concordance, the user is creator/contributor of that concordance, and 3) the user is creator/contributor of the target concordance (if given).
1642
+
1643
+ ### PATCH /mappings/:_id
1644
+ Adjusts a mapping in the database.
1645
+
1646
+ * **Success Reponse**
1647
+
1648
+ JSKOS Mapping object as it was saved in the database.
1649
+
1650
+ Note that any changes to the `created` property will be ignored. Note that changes to `partOf` (i.e. association with a concordance) are only possible if 1) `fromScheme` and `toScheme` are equal between the mapping and the concordance, 2) the authenticated user is creator of the mapping OR if the mapping is already part of a concordance, the user is creator/contributor of that concordance, and 3) the user is creator/contributor of the target concordance (if given).
1651
+
1652
+ ### DELETE /mappings/:_id
1653
+ Deletes a mapping from the database.
1654
+
1655
+ * **Success Reponse**
1656
+
1657
+ Status 204, no content.
1658
+
1659
+ ### GET /voc
1660
+ Lists supported terminologies (concept schemes).
1661
+
1662
+ * **URL Params**
1663
+
1664
+ `uri=[uri]` URIs for concept schemes separated by `|`. If `uri` is not given, all supported concept schemes are returned.
1665
+
1666
+ `type=URI` type URI to filter schemes
1667
+
1668
+ `languages=tag` language codes to filter schemes, separated by `,` (exact values). *Not to be confused with query parameter `language` at other endpoints!*
1669
+
1670
+ // Note: The `language` parameter at other endpoints means "give me labels in these languages". That's why it should have a different name here. Until then, it is removed.
1671
+
1672
+ `subject=URIs` subject URI(s) to filter schemes, separated by `|`
1673
+
1674
+ `license=URIs` license URI(s) to filter schemes, separated by `|`
1675
+
1676
+ `publisher=URI|label` publisher URI or label to filter schemes (only exact matches)
1677
+
1678
+ `partOf=URIs` filter by registry URI that is listed in `partOf` field of the scheme, separated by `|`
1679
+
1680
+ `sort=[property]` sort the results by a certain property. Possible values: `label` (preferred or alternative label in English or other languages), `notation` (string), `created` (timestamp), `modified` (timestamp), `counter` (number after last `/` in URI)
1681
+
1682
+ `order=[order]` order to use for sorting. Available are `asc` (default) and `desc`.
1683
+
1684
+ `notation` Notations for concept schemes separated by `|`. You can filter by one or more notations, i.e. `voc?notation=ASB|EuroVoc`
1685
+
1686
+ * **Success Response**
1687
+
1688
+ JSON array of [JSKOS Concept Schemes]
1689
+
1690
+ * **Sample Call**
1691
+
1692
+ ```bash
1693
+ curl https://coli-conc.gbv.de/api/voc?limit=1
1694
+ ```
1695
+
1696
+ ```json
1697
+ [
1698
+ {
1699
+ "uri": "http://dewey.info/scheme/edition/e23/",
1700
+ "prefLabel": {
1701
+ "de": "Dewey-Dezimalklassifikation",
1702
+ "en": "Dewey Decimal Classification"
1703
+ },
1704
+ "notation": [
1705
+ "DDC"
1706
+ ],
1707
+ "identifier": [
1708
+ "http://bartoc.org/en/node/241"
1709
+ ],
1710
+ "license": [
1711
+ {
1712
+ "uri": "http://creativecommons.org/licenses/by-nc-nd/3.0/"
1713
+ }
1714
+ ],
1715
+ "publisher": [
1716
+ {
1717
+ "uri": "http://d-nb.info/gnd/1086052218",
1718
+ "prefLabel": {
1719
+ "de": "OCLC"
1720
+ },
1721
+ "altLabel": {
1722
+ "de": [
1723
+ "OCLC Online Computer Library Center"
1724
+ ]
1725
+ },
1726
+ "url": "https://www.oclc.org/"
1727
+ }
1728
+ ],
1729
+ "@context": "https://gbv.github.io/jskos/context.json"
1730
+ }
1731
+ ]
1732
+ ```
1733
+
1734
+ ### POST /voc
1735
+ Saves a concept scheme or multiple concept schemes in the database. Each concept scheme has to have a unique `uri`.
1736
+
1737
+ * **URL Params**
1738
+
1739
+ `bulk=[boolean]` `1` or `true` enable bulk mode for importing multiple concept schemes into the database. Errors for individual concept schemes will be ignored and existing concept schemes will be overridden. The resulting set will only include the `id` for each concept scheme that was written into the database.
1740
+
1741
+ * **Success Reponse**
1742
+
1743
+ JSKOS Concept Scheme object or array as was saved in the database, or array of concept scheme objects with only a `uri` if bulk mode was used.
1744
+
1745
+ * **Error Response**
1746
+
1747
+ When a single concept scheme is provided, an error can be returned if there's something wrong with it (see [errors](#errors)). When multiple concept schemes are provided, the first error will be returned, except if bulk mode is enabled in which errors for individual concept schemes are ignored.
1748
+
1749
+ ### PUT /voc
1750
+ Overwrites a concept scheme in the database. Is identified via its `uri` field.
1751
+
1752
+ * **Success Reponse**
1753
+
1754
+ JSKOS Concept Scheme object as it was saved in the database.
1755
+
1756
+ Note that any changes to the `created` property will be ignored.
1757
+
1758
+ ### DELETE /voc
1759
+ Deletes a concept scheme from the database.
1760
+
1761
+ * **URL Params**
1762
+
1763
+ `uri=URI` URI for concept scheme to be deleted.
1764
+
1765
+ * **Success Reponse**
1766
+
1767
+ Status 204, no content.
1768
+
1769
+ ### GET /voc/top
1770
+ Lists top concepts for a concept scheme.
1771
+
1772
+ * **URL Params**
1773
+
1774
+ `uri=[uri]` URI for a concept scheme
1775
+
1776
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors` and `narrower`)
1777
+
1778
+ * **Success Response**
1779
+
1780
+ JSON array of [JSKOS Concepts]
1781
+
1782
+ * **Sample Call**
1783
+
1784
+ ```bash
1785
+ curl https://coli-conc.gbv.de/api/voc/top?uri=http://dewey.info/scheme/edition/e23/
1786
+ ```
1787
+
1788
+ ### GET /voc/concepts
1789
+ Lists concepts for a concept scheme.
1790
+
1791
+ * **URL Params**
1792
+
1793
+ `uri=[uri]` URI for a concept scheme (required)
1794
+
1795
+ `near=[latitude,longitude]` filters concepts by distance to a location (JSKOS field `location`), with `latitude` being a floating point value between -90 and 90 and `longitude` being a floating point value between -180 and 180
1796
+
1797
+ `distance=[distance]` value in kilometers which sets the radius for the `near` parameter if specified (default: 1)
1798
+
1799
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors`, `narrower`, and `annotations`); not supported for download
1800
+
1801
+ `download=[type]` returns the whole result as a download (available types are `json` and `ndjson`), ignores `limit` and `offset`
1802
+
1803
+ * **Success Response**
1804
+
1805
+ JSON array of [JSKOS Concepts]
1806
+
1807
+ * **Sample Call**
1808
+
1809
+ ```bash
1810
+ curl https://coli-conc.gbv.de/api/voc/concepts?uri=http://dewey.info/scheme/edition/e23/
1811
+ ```
1812
+
1813
+ ### DELETE /voc/concepts
1814
+ Deletes all concepts of a certain concept scheme from the database.
1815
+
1816
+ * **URL Params**
1817
+
1818
+ `uri=URI` URI for a concept scheme
1819
+
1820
+ * **Success Reponse**
1821
+
1822
+ Status 204, no content.
1823
+
1824
+ ### GET /voc/suggest
1825
+ Returns concept scheme suggestions.
1826
+
1827
+ * **URL Params**
1828
+
1829
+ `search=[keyword|notation]` specifies the keyword or notation (prefix) to search for
1830
+
1831
+ `language=[string]` comma-separated priority list of languages for labels in results
1832
+
1833
+ `format=[string]` return format for suggestions: `jskos` or [`opensearch`]((http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.1#Response_format)) (default)
1834
+
1835
+ * **Success Response**
1836
+
1837
+ JSON array of suggestions.
1838
+
1839
+ ### GET /voc/search
1840
+ Currently the same as `/voc/suggest` with parameter `format=jskos`.
1841
+
1842
+ ### GET /concepts
1843
+ Returns detailed data for concepts. Note that there is no certain order to the result set (but it should be consistent across requests). Note that no data is returned if no filtering parameter is given (one of `uri`, `notation`, `voc`, or `near`).
1844
+
1845
+ * **URL Params**
1846
+
1847
+ `uri=[uri]` URIs for concepts separated by `|`
1848
+
1849
+ `notation=[notation]` notations for concepts separated by `|`
1850
+
1851
+ `voc=[uri]` filter by concept scheme URI
1852
+
1853
+ `near=[latitude,longitude]` filters concepts by distance to a location (JSKOS field `location`), with `latitude` being a floating point value between -90 and 90 and `longitude` being a floating point value between -180 and 180
1854
+
1855
+ `distance=[distance]` value in kilometers which sets the radius for the `near` parameter if specified (default: 1)
1856
+
1857
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors`, `narrower`, and `annotations`); not supported for download
1858
+
1859
+ `download=[type]` returns the whole result as a download (available types are `json` and `ndjson`), ignores `limit` and `offset`
1860
+
1861
+ * **Success Response**
1862
+
1863
+ JSON array of [JSKOS Concepts]
1864
+
1865
+ * **Sample Call**
1866
+
1867
+ ```bash
1868
+ curl https://coli-conc.gbv.de/api/concepts?uri=http://dewey.info/class/612.112/e23/
1869
+ ```
1870
+
1871
+ ```json
1872
+ [
1873
+ {
1874
+ "@context": "https://gbv.github.io/jskos/context.json",
1875
+ "broader": [
1876
+ {
1877
+ "uri": "http://dewey.info/class/612.11/e23/"
1878
+ }
1879
+ ],
1880
+ "created": "2000-02-02",
1881
+ "identifier": [
1882
+ "16d595ff-ec01-3e55-b425-016cf92bb950"
1883
+ ],
1884
+ "inScheme": [
1885
+ {
1886
+ "uri": "http://dewey.info/scheme/edition/e23/"
1887
+ }
1888
+ ],
1889
+ "modified": "2013-12-04",
1890
+ "notation": [
1891
+ "612.112"
1892
+ ],
1893
+ "prefLabel": {
1894
+ "de": "Leukozyten (Weiße Blutkörperchen)"
1895
+ },
1896
+ "type": [
1897
+ "http://www.w3.org/2004/02/skos/core#Concept"
1898
+ ],
1899
+ "uri": "http://dewey.info/class/612.112/e23/",
1900
+ "narrower": [
1901
+ null
1902
+ ]
1903
+ }
1904
+ ]
1905
+ ```
1906
+
1907
+ ### POST /concepts
1908
+ Saves a concept or multiple concepts in the database. Each concept has to have a unique `uri` as well as a concept scheme that is available on the server in the `inScheme` or `topConceptOf` field.
1909
+
1910
+ * **URL Params**
1911
+
1912
+ `bulk=[boolean]` `1` or `true` enable bulk mode for importing multiple concepts into the database. Errors for individual concepts will be ignored and existing concepts will be overridden. The resulting set will only include the URI for each concept that was written into the database.
1913
+
1914
+ * **Success Reponse**
1915
+
1916
+ JSKOS Concept object or array as was saved in the database, or array of concept objects with only a URI if bulk mode was used.
1917
+
1918
+ * **Error Response**
1919
+
1920
+ When a single concept is provided, an error can be returned if there's something wrong with it (see [errors](#errors)). When multiple concepts are provided, the first error will be returned, except if bulk mode is enabled in which errors for individual concepts are ignored.
1921
+
1922
+ ### PUT /concepts
1923
+ Overwrites a concept in the database. Is identified via its `uri` field.
1924
+
1925
+ * **Success Reponse**
1926
+
1927
+ JSKOS Concept object as it was saved in the database.
1928
+
1929
+ ### DELETE /concepts
1930
+ Deletes a concept from the database.
1931
+
1932
+ * **URL Params**
1933
+
1934
+ `uri=URI` URI for concept to be deleted.
1935
+
1936
+ * **Success Reponse**
1937
+
1938
+ Status 204, no content.
1939
+
1940
+ ### GET /concepts/narrower
1941
+ Returns narrower concepts for a concept.
1942
+
1943
+ **Note:** The old `/narrower` endpoint is deprecated as of version 2.0 and will be removed in version 3.0.
1944
+
1945
+ * **URL Params**
1946
+
1947
+ `uri=[uri]` URI for a concept
1948
+
1949
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors` and `narrower`)
1950
+
1951
+ * **Success Response**
1952
+
1953
+ JSON array of [JSKOS Concepts]
1954
+
1955
+ * **Sample Call**
1956
+
1957
+ ```bash
1958
+ curl https://coli-conc.gbv.de/api/concepts/narrower?uri=http://dewey.info/class/612.112/e23/
1959
+ ```
1960
+
1961
+ ```json
1962
+ [
1963
+ {
1964
+ "@context": "https://gbv.github.io/jskos/context.json",
1965
+ "broader": [
1966
+ {
1967
+ "uri": "http://dewey.info/class/612.112/e23/"
1968
+ }
1969
+ ],
1970
+ "created": "2000-02-02",
1971
+ "identifier": [
1972
+ "cf6faa73-e5e7-3856-9429-611a8a39d253"
1973
+ ],
1974
+ "inScheme": [
1975
+ {
1976
+ "uri": "http://dewey.info/scheme/edition/e23/"
1977
+ }
1978
+ ],
1979
+ "modified": "2005-11-02",
1980
+ "notation": [
1981
+ "612.1121"
1982
+ ],
1983
+ "prefLabel": {
1984
+ "de": "Biochemie"
1985
+ },
1986
+ "type": [
1987
+ "http://www.w3.org/2004/02/skos/core#Concept"
1988
+ ],
1989
+ "uri": "http://dewey.info/class/612.1121/e23/",
1990
+ "narrower": []
1991
+ },
1992
+ {
1993
+ "@context": "https://gbv.github.io/jskos/context.json",
1994
+ "broader": [
1995
+ {
1996
+ "uri": "http://dewey.info/class/612.112/e23/"
1997
+ }
1998
+ ],
1999
+ "created": "2000-02-02",
2000
+ "http://www.w3.org/2002/07/owl#deprecated": true,
2001
+ "identifier": [
2002
+ "23519115-b023-3812-a2c1-6fc99e169ae3"
2003
+ ],
2004
+ "inScheme": [
2005
+ {
2006
+ "uri": "http://dewey.info/scheme/edition/e23/"
2007
+ }
2008
+ ],
2009
+ "modified": "2005-11-02",
2010
+ "notation": [
2011
+ "612.1122"
2012
+ ],
2013
+ "prefLabel": {
2014
+ "de": "Biophysik"
2015
+ },
2016
+ "type": [
2017
+ "http://www.w3.org/2004/02/skos/core#Concept"
2018
+ ],
2019
+ "uri": "http://dewey.info/class/612.1122/e23/",
2020
+ "narrower": []
2021
+ },
2022
+ {
2023
+ "@context": "https://gbv.github.io/jskos/context.json",
2024
+ "broader": [
2025
+ {
2026
+ "uri": "http://dewey.info/class/612.112/e23/"
2027
+ }
2028
+ ],
2029
+ "created": "2000-02-02",
2030
+ "identifier": [
2031
+ "4a070e77-094c-3638-9067-2b3625d612e9"
2032
+ ],
2033
+ "inScheme": [
2034
+ {
2035
+ "uri": "http://dewey.info/scheme/edition/e23/"
2036
+ }
2037
+ ],
2038
+ "modified": "2005-11-02",
2039
+ "notation": [
2040
+ "612.1127"
2041
+ ],
2042
+ "prefLabel": {
2043
+ "de": "Anzahl und Auszählung"
2044
+ },
2045
+ "type": [
2046
+ "http://www.w3.org/2004/02/skos/core#Concept"
2047
+ ],
2048
+ "uri": "http://dewey.info/class/612.1127/e23/",
2049
+ "narrower": []
2050
+ }
2051
+ ]
2052
+ ```
2053
+
2054
+ ### GET /concepts/ancestors
2055
+ Returns ancestor concepts for a concept.
2056
+
2057
+ **Note:** The old `/ancestors` endpoint is deprecated as of version 2.0 and will be removed in version 3.0.
2058
+
2059
+ * **URL Params**
2060
+
2061
+ `uri=[uri]` URI for a concept
2062
+
2063
+ `properties=[list]` with `[list]` being a comma-separated list of properties (currently supporting `ancestors` and `narrower`)
2064
+
2065
+ * **Success Response**
2066
+
2067
+ JSON array of [JSKOS Concepts]
2068
+
2069
+ * **Sample Call**
2070
+
2071
+ ```bash
2072
+ curl https://coli-conc.gbv.de/api/concepts/ancestors?uri=http://dewey.info/class/61/e23/
2073
+ ```
2074
+
2075
+ ```json
2076
+ [
2077
+ {
2078
+ "@context": "https://gbv.github.io/jskos/context.json",
2079
+ "created": "2000-02-02",
2080
+ "identifier": [
2081
+ "856c92e9-8b1f-3131-bfbe-f2d2266527d3"
2082
+ ],
2083
+ "modified": "2005-11-02",
2084
+ "notation": [
2085
+ "6"
2086
+ ],
2087
+ "prefLabel": {
2088
+ "de": "Technik, Medizin, angewandte Wissenschaften"
2089
+ },
2090
+ "topConceptOf": [
2091
+ {
2092
+ "uri": "http://dewey.info/scheme/edition/e23/"
2093
+ }
2094
+ ],
2095
+ "type": [
2096
+ "http://www.w3.org/2004/02/skos/core#Concept"
2097
+ ],
2098
+ "uri": "http://dewey.info/class/6/e23/",
2099
+ "inScheme": [
2100
+ {
2101
+ "uri": "http://dewey.info/scheme/edition/e23/"
2102
+ }
2103
+ ],
2104
+ "narrower": [
2105
+ null
2106
+ ]
2107
+ }
2108
+ ]
2109
+ ```
2110
+
2111
+ ### GET /concepts/suggest
2112
+ Returns concept suggestions.
2113
+
2114
+ **Note:** The old `/suggest` endpoint is deprecated as of version 2.0 and will be removed in version 3.0.
2115
+
2116
+ * **URL Params**
2117
+
2118
+ `search=[keyword|notation]` specifies the keyword or notation (prefix) to search for
2119
+
2120
+ `language=[string]` comma-separated priority list of languages for labels in results
2121
+
2122
+ `format=[string]` return format for suggestions: `jskos` or [`opensearch`]((http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.1#Response_format)) (default)
2123
+
2124
+ * **Success Response**
2125
+
2126
+ JSON array of suggestions.
2127
+
2128
+ * **Sample Calls**
2129
+
2130
+ ```bash
2131
+ curl https://coli-conc.gbv.de/api/concepts/suggest?search=Krebs&limit=5
2132
+ ```
2133
+
2134
+ ```json
2135
+ [
2136
+ "Krebs",
2137
+ [
2138
+ "133.5265 Krebs",
2139
+ "639.5 Krebstierfang",
2140
+ "639.6 Krebstierzucht",
2141
+ "616.994 Krebserkrankungen",
2142
+ "641.695 Krebstiere"
2143
+ ],
2144
+ [
2145
+ "",
2146
+ "",
2147
+ "",
2148
+ "",
2149
+ ""
2150
+ ],
2151
+ [
2152
+ "http://dewey.info/class/133.5265/e23/",
2153
+ "http://dewey.info/class/639.5/e23/",
2154
+ "http://dewey.info/class/639.6/e23/",
2155
+ "http://dewey.info/class/616.994/e23/",
2156
+ "http://dewey.info/class/641.695/e23/"
2157
+ ]
2158
+ ]
2159
+ ```
2160
+
2161
+ ```bash
2162
+ curl https://coli-conc.gbv.de/api/concepts/suggest?search=Krebs&limit=2&format=jskos
2163
+ ```
2164
+
2165
+ ```json
2166
+ [
2167
+ {
2168
+ "_id": "http://dewey.info/class/133.5265/e23/",
2169
+ "@context": "https://gbv.github.io/jskos/context.json",
2170
+ "broader": [
2171
+ {
2172
+ "uri": "http://dewey.info/class/133.526/e23/"
2173
+ }
2174
+ ],
2175
+ "created": "2000-02-02",
2176
+ "identifier": [
2177
+ "57e89e64-9de0-35c1-88da-856529d547c8"
2178
+ ],
2179
+ "inScheme": [
2180
+ {
2181
+ "uri": "http://dewey.info/scheme/edition/e23/"
2182
+ }
2183
+ ],
2184
+ "modified": "2005-11-02",
2185
+ "notation": [
2186
+ "133.5265"
2187
+ ],
2188
+ "prefLabel": {
2189
+ "de": "Krebs"
2190
+ },
2191
+ "type": [
2192
+ "http://www.w3.org/2004/02/skos/core#Concept"
2193
+ ],
2194
+ "uri": "http://dewey.info/class/133.5265/e23/",
2195
+ "narrower": [],
2196
+ "priority": 292
2197
+ },
2198
+ {
2199
+ "_id": "http://dewey.info/class/639.5/e23/",
2200
+ "@context": "https://gbv.github.io/jskos/context.json",
2201
+ "broader": [
2202
+ {
2203
+ "uri": "http://dewey.info/class/639/e23/"
2204
+ }
2205
+ ],
2206
+ "created": "2000-02-02",
2207
+ "identifier": [
2208
+ "8b1dc20e-5d1e-34f4-8478-3fa022ba6fe0"
2209
+ ],
2210
+ "inScheme": [
2211
+ {
2212
+ "uri": "http://dewey.info/scheme/edition/e23/"
2213
+ }
2214
+ ],
2215
+ "modified": "2005-11-02",
2216
+ "notation": [
2217
+ "639.5"
2218
+ ],
2219
+ "prefLabel": {
2220
+ "de": "Krebstierfang"
2221
+ },
2222
+ "type": [
2223
+ "http://www.w3.org/2004/02/skos/core#Concept"
2224
+ ],
2225
+ "uri": "http://dewey.info/class/639.5/e23/",
2226
+ "narrower": [
2227
+ null
2228
+ ],
2229
+ "priority": 195
2230
+ }
2231
+ ]
2232
+ ```
2233
+
2234
+ ### GET /concepts/search
2235
+ Currently the same as `/concepts/suggest` with parameter `format=jskos`. Additionally, search supports the parameter `properties=[list]` as in the other concept methods.
2236
+
2237
+ **Note:** The old `/search` endpoint is deprecated as of version 2.0 and will be removed in version 3.0.
2238
+
2239
+ ### GET /registries
2240
+ Returns an array of registries. Each registry has a property `id` under which the specific registry can be accessed.
2241
+
2242
+ * **URL Params**
2243
+
2244
+ `id=[id]` specify a registry ID
2245
+
2246
+ * **Success Response**
2247
+
2248
+ Array of registries in [JSKOS Registry] format
2249
+
2250
+ * **Sample Call**
2251
+
2252
+ ```bash
2253
+ curl https://coli-conc.gbv.de/api/registries?limit=1
2254
+ ```
2255
+
2256
+ ```json
2257
+ [
2258
+ {
2259
+ "API": [
2260
+ {
2261
+ "type": "http://bartoc.org/api-type/jskos",
2262
+ "url": "https://api.dante.gbv.de/"
2263
+ }
2264
+ ],
2265
+ "startDate": "2017",
2266
+ "definition": {
2267
+ "en": [
2268
+ "DANTE (Datendrehscheibe für Normdaten und Terminologien) is a vocabulary server hosted by VZG based on easyDB. Its vocabularies are mainly from museums and related organizations."
2269
+ ]
2270
+ },
2271
+ "prefLabel": {
2272
+ "en": "DANTE"
2273
+ },
2274
+ "type": [
2275
+ "http://www.w3.org/ns/dcat#Catalog",
2276
+ "http://bartoc.org/full-repository"
2277
+ ],
2278
+ "uri": "http://bartoc.org/en/node/19999",
2279
+ "url": "https://api.dante.gbv.de/"
2280
+ }
2281
+ ]
2282
+ ```
2283
+
2284
+ ### GET /registries/suggest
2285
+ Returns registry suggestions.
2286
+
2287
+ * **URL Params**
2288
+
2289
+ `search=[keyword|notation]` specifies the keyword or notation (prefix) to search for
2290
+
2291
+ * **Success Response**
2292
+
2293
+ JSON array of suggestions.
2294
+
2295
+ * **Sample Calls**
2296
+
2297
+ ```bash
2298
+ curl https://coli-conc.gbv.de/api/registries/suggest?search=Stanford
2299
+ ```
2300
+
2301
+ ```json
2302
+ [
2303
+ "Stanford",
2304
+ [
2305
+ "ERMS VEST Registry"
2306
+ ],
2307
+ [
2308
+ "",
2309
+ "",
2310
+ ""
2311
+ ],
2312
+ [
2313
+ "http://bartoc.org/en/node/18927"
2314
+ ]
2315
+ ]
2316
+ ```
2317
+
2318
+ ```bash
2319
+ curl https://coli-conc.gbv.de/api/concepts/suggest?search=Krebs&limit=2&format=jskos
2320
+ ```
2321
+
2322
+ ### POST /registries
2323
+ Saves one registry or multiple registries in the database.
2324
+
2325
+ * **URL Params**
2326
+
2327
+ `bulk=[boolean]` `1` or `true` enable bulk mode for importing multiple registries into the database. Existing registries will be overridden. The resulting set will only include the `id` for each registry that was written into the database.
2328
+
2329
+ * **Success Response**
2330
+
2331
+ Registry object or array of object as was saved in the database in [JSKOS Registry] format, or array of registry objects with only a `id` if bulk mode was used.
2332
+
2333
+ * **Error Response**
2334
+
2335
+ Bulk mode: invalid registries are skipped.
2336
+ Non-bulk mode: the first error is thrown (see [errors](#errors)).
2337
+
2338
+ ### PUT /registries
2339
+ Overwrites a registry in the database, identfied by its `uri` fiel.
2340
+
2341
+ * **Success Response**
2342
+
2343
+ Registry object as it was saved in the database in [JSKOS Registry] format.
2344
+
2345
+ ### DELETE /registries
2346
+ Deletes a registry from the database.
2347
+
2348
+ * **URL Params**
2349
+
2350
+ `uri=URI` URI for registry to be deleted.
2351
+
2352
+ * **Success Response**
2353
+
2354
+ Status 204, no content.
2355
+
2356
+ ### GET /annotations
2357
+ Returns an array of annotations. Each annotation has a property `id` under which the specific annotation can be accessed.
2358
+
2359
+ * **URL Params**
2360
+
2361
+ `id=[id]` specify an annotation ID
2362
+
2363
+ `creator=[uriOrName]` only return annotations that have a certain creator (name or URI) (separated by `|`)
2364
+
2365
+ `target=[target]` only return annotations with a specific target URI (e.g. a mapping URI)
2366
+
2367
+ `bodyValue=[bodyValue]` only return annotations with a specific bodyValue (e.g. `+1`, `-1`)
2368
+
2369
+ `motivation=[motivation]` only return annotations with a specific motivation (e.g. `assessing`, `moderating`, `tagging`)
2370
+
2371
+ * **Success Response**
2372
+
2373
+ Array of annotations in [Web Annotation Data Model] format
2374
+
2375
+ * **Sample Call**
2376
+
2377
+ ```bash
2378
+ curl https://coli-conc.gbv.de/api/annotations?bodyValue=+1&limit=1
2379
+ ```
2380
+
2381
+ ```json
2382
+ [
2383
+ {
2384
+ "target": {
2385
+ "id": "https://coli-conc.gbv.de/api/mappings/f8eff4e2-a6df-4d2c-8382-523072c59af7"
2386
+ },
2387
+ "motivation": "assessing",
2388
+ "bodyValue": "+1",
2389
+ "creator": "https://orcid.org/0000-0002-4087-8227",
2390
+ "created": "2019-01-31T09:44:12.699Z",
2391
+ "id": "https://coli-conc.gbv.de/api/annotations/2575e276-29c6-4d36-8477-b21be1790e64",
2392
+ "@context": "http://www.w3.org/ns/anno.jsonld",
2393
+ "type": "Annotation"
2394
+ }
2395
+ ]
2396
+ ```
2397
+
2398
+ ### GET /annotations/:_id
2399
+ Returns a specific annotation.
2400
+
2401
+ * **Success Response**
2402
+
2403
+ Object for annotation in [Web Annotation Data Model] format.
2404
+
2405
+ * **Error Response**
2406
+
2407
+ If no annotation with `_id` could be found, it will return a 404 not found error.
2408
+
2409
+ * **Sample Call**
2410
+
2411
+ ```bash
2412
+ curl https://coli-conc.gbv.de/api/annotations/5f23368f-a63b-4b69-acd6-b403110df97c
2413
+ ```
2414
+
2415
+ ```json
2416
+ {
2417
+ "target": {
2418
+ "id": "https://coli-conc.gbv.de/api/mappings/f0cc5f65-5712-4820-9638-e662c0c4314e"
2419
+ },
2420
+ "motivation": "assessing",
2421
+ "bodyValue": "+1",
2422
+ "creator": {
2423
+ "id": "https://coli-conc.gbv.de/login/users/722cc9c5-2ce3-4ca0-b4fb-fef1f62236af",
2424
+ "name": "Jakob Voß"
2425
+ },
2426
+ "created": "2019-03-11T09:11:10.665Z",
2427
+ "id": "https://coli-conc.gbv.de/api/annotations/5f23368f-a63b-4b69-acd6-b403110df97c",
2428
+ "@context": "http://www.w3.org/ns/anno.jsonld",
2429
+ "type": "Annotation"
2430
+ }
2431
+ ```
2432
+
2433
+ ### POST /annotations
2434
+ Saves an annotation or multiple annotations in the database.
2435
+
2436
+ * **URL Params**
2437
+
2438
+ `bulk=[boolean]` `1` or `true` enable bulk mode for importing multiple annotations into the database. Errors for individual annotations will be ignored and existing annotations will be overridden. The resulting set will only include the `id` for each annotation that was written into the database.
2439
+
2440
+ * **Success Reponse**
2441
+
2442
+ Annotation object or array of object as was saved in the database in [Web Annotation Data Model] format, or array of annotation objects with only a `id` if bulk mode was used.
2443
+
2444
+ * **Error Response**
2445
+
2446
+ When a single annotation is provided, an error can be returned if there's something wrong with it (see [errors](#errors)). When multiple annotations are provided, the first error will be returned, except if bulk mode is enabled in which errors for individual annotations are ignored.
2447
+
2448
+ ### PUT /annotations/:_id
2449
+ Overwrites an annotation in the database.
2450
+
2451
+ * **Success Reponse**
2452
+
2453
+ Annotation object as it was saved in the database in [Web Annotation Data Model] format.
2454
+
2455
+ Note that any changes to the `created` property will be ignored.
2456
+
2457
+ ### PATCH /annotations/:_id
2458
+ Adjusts an annotation in the database.
2459
+
2460
+ * **Success Reponse**
2461
+
2462
+ Annotation object as it was saved in the database in [Web Annotation Data Model] format.
2463
+
2464
+ Note that any changes to the `created` property will be ignored.
2465
+
2466
+ ### DELETE /annotations/:_id
2467
+ Deletes an annotation from the database.
2468
+
2469
+ * **Success Reponse**
2470
+ Status 204, no content.
2471
+
2472
+
2473
+ ### Change Stream Endpoints
2474
+
2475
+ JSKOS-Server provides WebSocket endpoints that push live notifications whenever data changes. Available routes:
2476
+
2477
+ * **`/voc/changes`** — broadcasts events for **ConceptSchemes**
2478
+ * **`/concepts/changes`** — broadcasts events for **Concepts**
2479
+ * **`/mappings/changes`** — broadcasts events for **Mappings**
2480
+ * **`/concordances/changes`** — broadcasts events for **Concordances**
2481
+ * **`/annotations/changes`** — broadcasts events for **Annotations**
2482
+ * **`/registries/changes`** — broadcasts events for **Registries**
2483
+
2484
+ #### Connection to websocket
2485
+
2486
+ ```shell
2487
+ # Example for ConceptSchemes
2488
+ wscat -c ws://<host>:<port>/voc/changes
2489
+ ```
2490
+
2491
+ #### Messages
2492
+
2493
+ Each message is a JSON object with the following fields:
2494
+
2495
+ | Field | Type | Description |
2496
+ | ------------ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
2497
+ | `objectType` | `string` | The JSKOS object type. One of: `ConceptScheme`, `Concept`, `ConceptMapping`, `Concordance`, `Annotation`, `Registry`. |
2498
+ | `type` | `string` | Change type, derived from the MongoDB operation:<br>• `insert` → `create`<br>• `update` / `replace` → `update`<br>• `delete` → `delete` |
2499
+ | `id` | `string` or `ObjectId` | The `_id` of the changed MongoDB document. |
2500
+ | `timestamp` | `string` | The ISO 8601 timestamp of the change event, derived from the MongoDB change stream `clusterTime` (available since MongoDB 3.6). |
2501
+ | `document` | `object` *(optional)* | The full JSKOS record as stored in MongoDB. Present only for `create` and `update`. |
2502
+
2503
+ <details>
2504
+ <summary>Example: <code>create</code> event</summary>
2505
+
2506
+ ```json
2507
+ {
2508
+ "objectType": "ConceptScheme",
2509
+ "type": "create",
2510
+ "id": "650b1a5f3c9e2f001234abcd",
2511
+ "document": {
2512
+ "_id": "650b1a5f3c9e2f001234abcd",
2513
+ "uri": "http://example.org/voc/123",
2514
+ "type": ["http://www.w3.org/2004/02/skos/core#ConceptScheme"],
2515
+ "prefLabel": { "en": ["Example Scheme"] }
2516
+ // … other JSKOS fields …
2517
+ }
2518
+ }
2519
+ ```
2520
+
2521
+ </details>
2522
+
2523
+ <details>
2524
+ <summary>Example: <code>delete</code> event</summary>
2525
+
2526
+ ```json
2527
+ {
2528
+ "objectType": "ConceptScheme",
2529
+ "type": "delete",
2530
+ "id": "650b1a5f3c9e2f001234abcd"
2531
+ }
2532
+ ```
2533
+
2534
+ </details>
2535
+
2536
+ ### Errors
2537
+ If possible, errors will be returned as a JSON object in the following format (example):
2538
+
2539
+ ```json
2540
+ {
2541
+ "error": "EntityNotFoundError",
2542
+ "status": 404,
2543
+ "message": "The requested entity ABC could not be found.",
2544
+ }
2545
+ ```
2546
+
2547
+ Validation errors reported from [/validate endpoint](#post-validate) are no API errors (unless validation could not be executed for some reason).
2548
+
2549
+ The following errors are currently caught and returned as JSON:
2550
+
2551
+ #### EntityNotFoundError
2552
+ Status code 404. Will be returned if `GET /mappings/:_id` or `GET /annotations/:_id` are requested with an unknown ID.
2553
+
2554
+ #### MalformedBodyError
2555
+ Status code 400. Will be returned for `POST`/`PUT`/`PATCH` if the body was not JSON or missing.
2556
+
2557
+ #### MalformedRequestError
2558
+ Status code 400. Will be returned if a required parameter is missing (currently implemented in `GET /.../:_id` endpoints, but should not be possible to reach).
2559
+
2560
+ #### DuplicateEntityError
2561
+ Status code 422. Will be returned for `POST` if an entity with the same ID/URI already exists in the database.
2562
+
2563
+ #### InvalidBodyError
2564
+ Status code 422. Will be returned for `POST`/`PUT`/`PATCH` if the body was valid JSON, but could not be validated (e.g. does not pass the JSKOS Schema).
2565
+
2566
+ #### CreatorDoesNotMatchError
2567
+ Status code 403. Will be returned by `PUT`/`PATCH`/`DELETE` endpoints if the authenticated creator does not match the creator of the entity that is being edited.
2568
+
2569
+ #### BackendError
2570
+ Status code 500. Will be returned if there's a backend error not related to the database or configuration.
2571
+
2572
+ #### DatabaseAccessError
2573
+ Status code 500. Will be returned if the database is not available or if the current database request failed with an unknown error.
2574
+
2575
+ #### DatabaseInconsistencyError
2576
+ Status code 500. Will be returned if there is an inconsistency issue with our database. Please [contact us](https://coli-conc.gbv.de/contact/) with the full error message if this occurs!
2577
+
2578
+ #### ConfigurationError
2579
+ Status code 500. Will be returned if there is an error in the configuration that prevents the application from working correctly.
2580
+
2581
+ #### ForbiddenAccessError
2582
+ Status code 403. Will be returned if the user is not allow access (i.e. when not on the whitelist or when an identity provider is missing).
2583
+
2584
+
2585
+ ## Deployment
2586
+ The application is currently deployed at http://coli-conc.gbv.de/api/. At the moment, there is no automatic deployment of new versions.
2587
+
2588
+ ### Notes about depolyment on Ubuntu
2589
+ It is recommended to use a [newer version of Node.js](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions). Installing the dependencies might also require installing nodejs-legacy: `sudo apt-get install nodejs-legacy` ([more info here](https://stackoverflow.com/questions/21168141/cannot-install-packages-using-node-package-manager-in-ubuntu)). One possibility for running the application in production on Ubuntu 16.04 is described [here](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04). (Information about restarting pm2-based services on system reboot [here](https://pm2.keymetrics.io/docs/usage/startup/).)
2590
+
2591
+ ### Update an instances deployed with PM2
2592
+ ```
2593
+ # get updates from repository
2594
+ git pull
2595
+
2596
+ # install dependencies
2597
+ npm ci
2598
+
2599
+ # restart the process (adjust process name if needed)
2600
+ pm2 restart jskos-server
2601
+ ```
2602
+
2603
+ ### Daily Import
2604
+ If you'd like to run the import script daily to refresh current mappings, you can for example use a cronjob:
2605
+
2606
+ ```bash
2607
+ # Runs import script for jskos-server in /srv/cocoda/jskos-server at 1 AM each day.
2608
+ 00 01 * * * cd /srv/cocoda/jskos-server; ./scripts/import.sh
2609
+ ```
2610
+
2611
+ [JSKOS]: https://gbv.github.io/jskos/
2612
+ [JSKOS Concept Mappings]: https://gbv.github.io/jskos/#concept-mappings
2613
+ [JSKOS Concept Schemes]: https://gbv.github.io/jskos/#concept-schemes
2614
+ [JSKOS Concepts]: https://gbv.github.io/jskos/#concept
2615
+ [JSKOS Items]: https://gbv.github.io/jskos/#item
2616
+ [JSKOS Registry]: https://gbv.github.io/jskos/#registry
2617
+ [Web Annotation Data Model]: https://www.w3.org/TR/annotation-model/
2618
+
2619
+
2620
+ ### Running Behind a Reverse Proxy
2621
+ There are certain things to consider when running `jskos-server` behind a reverse proxy:
2622
+
2623
+ 1. Make sure the base URL is configured correctly in `config.json` so that correct URIs will be generated. Test this by creating a new mapping and making sure the URI of that mapping is correct and accessible.
2624
+
2625
+ 1. Provide a list of trusted proxy IPs or ranges in the `proxies` key in `config.json`. E.g. `"proxies": ["123.456.789.101", "234.567.891.011"]`. See also: [Express behind proxies](https://expressjs.com/en/guide/behind-proxies.html).
2626
+
2627
+ 1. The reverse proxy should be configured so that the base URL has a trailing slash: ~~`https://example.com/api`~~ ❌ - `https://example.com/api/` ✅ (Note: Not implementing this has no further consequences except that `/api` will not be accessible.)
2628
+
2629
+ 1. The reverse proxy should also be configured so that any URL **except** the base URL has **no** trailing slash: ~~`https://example.com/api/status/`~~ ❌ - `https://example.com/api/status` ✅
2630
+
2631
+ 1. Make sure the target parameter (i.e. the actual IP and port where `jskos-server` is running) has a trailing slash.
2632
+
2633
+ 1. Make sure the proxy is configured to correctly set the `X-Forwarded-For` header.
2634
+
2635
+ The following would be an example for 2./3./4. with an Apache reverse proxy:
2636
+
2637
+ ```apacheconf
2638
+ <VirtualHost *:8099>
2639
+ Define API_PATH /api
2640
+ ServerName example.com
2641
+
2642
+ RewriteEngine on
2643
+ # Remove trailing slash from everything EXCEPT the base URL
2644
+ RewriteCond %{REQUEST_URI} !^${API_PATH}/$
2645
+ RewriteRule ^(.*)/+$ $1 [R=301,L]
2646
+ # Force trailing slash for base URL only
2647
+ RewriteCond %{REQUEST_URI} ^${API_PATH}$
2648
+ RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
2649
+
2650
+ # Forward to jskos-server
2651
+ ProxyPass ${API_PATH}/ http://127.0.0.1:3000/
2652
+ ProxyPassReverse ${API_PATH}/ http://127.0.0.1:3000/
2653
+
2654
+ # ...
2655
+ </VirtualHost>
2656
+ ```
2657
+
2658
+ <!-- TODO: Add example for nginx. -->
2659
+
2660
+ ## Data flow
2661
+
2662
+ JSKOS data is internally stored in a MongoDB database. The data can be read and written via [JSKOS API](#API) and imported via local command line import script. In additional there are helper scripts not shown in the diagram.
2663
+
2664
+ ```mermaid
2665
+ graph TD
2666
+ jskos(JSKOS<br>schemes, concepts, mappings, concordances, annotations)
2667
+ mongodb(MongoDB)
2668
+ server <--> mongodb
2669
+ scripts --> mongodb
2670
+ server <-- JSKOS API --> jskos
2671
+ jskos --CLI --> scripts
2672
+ subgraph jskos-server [ ]
2673
+ server[**server**]
2674
+ scripts[**import**]
2675
+ end
2676
+ ```
2677
+
2678
+ ## Related works
2679
+
2680
+ jskos-server is developed together with the [cocoda](https://coli-conc.gbv.de/cocoda/) mapping application.
2681
+
2682
+ Alternative open source applications for hosting concept schemes are listed at <https://bartoc.org/software>.
2683
+
2684
+ See [cocoda-sdk](https://github.com/gbv/cocoda-sdk) for efforts to provide uniform access to vocabulary information from different applications and sources.
2685
+
2686
+ ## Maintainers
2687
+
2688
+ - [@nichtich](https://github.com/nichtich)
2689
+
2690
+ ## Contribute
2691
+
2692
+ PRs accepted against the `dev` branch.
2693
+
2694
+ Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
2695
+
2696
+ ### Publish
2697
+ **For maintainers only**
2698
+
2699
+ Never work on the main branch directly. Always make changes on a feature branch for specific issues or on the `dev` branch for small fixes and then run the release script:
2700
+
2701
+ ```bash
2702
+ npm run release:patch # or minor or major
2703
+ ```
2704
+
2705
+ ## License
2706
+
2707
+ MIT © 2018 Verbundzentrale des GBV (VZG)
2708
+
2709
+ [login-server]: https://github.com/gbv/login-server
2710
+ [jskos-validate]: https://github.com/gbv/jskos-validate