From 6b258caf15764d8402b410debbfabd1af92018b5 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Tue, 9 Jul 2024 17:02:34 +0200 Subject: [PATCH] add OpenAPI doc --- _data/openapi.yml | 380 +++++++++++++++++++++++++++++++++++++ en/doc/guides/api.md | 18 +- en/doc/references/api.html | 106 +++++++++++ en/doc/references/api.md | 145 -------------- fr/doc/guides/api.md | 12 +- fr/doc/references/api.md | 143 -------------- 6 files changed, 495 insertions(+), 309 deletions(-) create mode 100644 _data/openapi.yml create mode 100644 en/doc/references/api.html delete mode 100644 en/doc/references/api.md delete mode 100644 fr/doc/references/api.md diff --git a/_data/openapi.yml b/_data/openapi.yml new file mode 100644 index 00000000..f4761806 --- /dev/null +++ b/_data/openapi.yml @@ -0,0 +1,380 @@ +openapi: '3.1.0' +info: + title: eCorpus + version: '1.0.0' + summary: HTTP API for eCorpus + description: | + This HTTP API provides all necessary routes to access and edit scenes stored on an eCorpus instance under the `/scenes` path. + Additionally it provides a number of namespaced utilities + for **users** management (`/users`), + **authentication** and ACL edition (`/auth`), + changes **history** management (`/history`) + or gathering scenes under **collections** (`/tags`). + + It provides some webDAV utility routes for the `/scenes` resources + but is far from [Class 1](http://www.webdav.org/specs/rfc4918.html#rfc.section.18.1) Compliance: + Only routes that are necessary for proper [Voyager](https://smithsonian.github.io/dpo-voyager/) support are implemented. + WebDAV-specific methods are defined as an extension with a `x-` prefix to prevent breaking openAPI tooling + + Other namespaces tends to adhere to a stricter REST philosophy where possible. + contact: + name: eCorpus Support + url: https://github.com/Holusion/eCorpus + email: contact@holusion.com + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +servers: + - url: https://ecorpus.holusion.com + +tags: + - name: admin + description: Administrative tasks routes + - name: auth + description: Authentication, access control querying and edition routes. + - name: history + description: | + history management utilities for the `/scenes` namespace. + Scene names in `/history` directly and uniquely maps to scenes in `/scenes`. + - name: scenes + description: | + Where all the actual data is stored + API design for the `/scenes/*` makes use of the liberal definition of + [GET for collections](https://datatracker.ietf.org/doc/html/rfc2518#section-8.4) in the webDAV specification + to return well-defined JSON documents for those queries, allowing most use cases to bypass cumbersome PROPFIND queries + - name: tags + description: | + collections (tags) management routes. + - name: users + description: Users management + +paths: + /scenes: + summary: Collection of the scenes stored on this service + get: + tags: [scenes] + operationId: getScenes + description: | + get a list of scenes with optional search parameters. Similar to PROPFIND but will return JSON. + Provides advanced search and pagination semantics + responses: + '200': + description: a list of scenes matching this query + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Scene" + post: + tags: [scenes] + operationId: postScenes + description: import an archive of scenes to be extracted into the `scenes/` folder + x-propfind: + tags: [scenes] + operationId: propfindScenes + description: fetch all readable content in `scenes/` + /scenes/{scene}: + parameters: + - $ref: '#/components/parameters/scene' + get: + tags: [scenes] + operationId: getScene + description: get a scene's metadata. + x-mkcol: + tags: [scenes] + operationId: mkScene + description: creates a new empty scene. This scene will essentially be invisible until populated + x-propfind: + tags: [scenes] + operationId: propfindScene + description: fetch the scene's content + delete: + tags: [scenes] + operationId: deleteScene + description: Archives a scene + post: + tags: [scenes] + operationId: postScene + description: creates a new scene using attached data + requestBody: + description: "scene initialization data" + required: true + content: + model/gltf-binary: + schema: + type: string + format: binary + description: A `.glb` model file + + patch: + tags: [scenes] + operationId: patchScene + description: Edit scene's metadata + requestBody: + description: Scene patch data + required: true + content: + application/json: + schema: + type: object + /scenes/{scene}/{file}: + parameters: + - $ref: '#/components/parameters/scene' + - $ref: '#/components/parameters/file' + get: + tags: [scenes] + operationId: getFile + description: get a file in scene + put: + tags: [scenes] + operationId: putFile + description: overwrite the file with new content + x-copy: + tags: [scenes] + operationId: copyFile + description: copy a file to another location in the same scene + x-move: + tags: [scenes] + operationId: moveFile + description: move a file to another location in the same scene + delete: + tags: [scenes] + operationId: deleteFile + description: archives a file. It is still accessible through the history API + x-mkcol: + tags: [scenes] + operationId: mkFolder + description: creates a folder in a scene + x-propfind: + tags: [scenes] + operationId: propfindFile + description: get a file's properties + /history/{scene}: + parameters: + - $ref: '#/components/parameters/scene' + get: + tags: [history] + operationId: getHistory + description: get a full history of a scene's modifications + post: + tags: [history] + operationId: postHistory + description: edit a scene's history + /history/{scene}/files: + parameters: + - $ref: '#/components/parameters/scene' + get: + tags: [history] + operationId: getFileHistory + description: list all files in the scenes in their current state + /tags: + get: + tags: [tags] + operationId: getTags + description: get a list of tags on this server + /tags/{tag}: + parameters: + - name: tag + in: path + required: true + schema: {type: "string"} + description: name of a tag + get: + tags: [tags] + operationId: getTag + description: get all scenes associated with this tag + /users: + get: + tags: [users] + operationId: getUsers + description: get a list of registered users + responses: + '200': + description: An array of all users registered on this server + content: + application/json: + schema: + type: array + items: { $ref: "#/components/schemas/User"} + '401': + $ref: "#/components/responses/HTTPError" + post: + tags: [users] + operationId: postUser + description: create a new user + /users/{uid}: + parameters: + - name: uid + in: path + required: true + schema: {type: "string", pattern: '^\d+$'} + description: unique ID of an user (stays stable through user renames) + delete: + tags: [users] + operationId: deleteUser + description: delete a user + patch: + tags: [users] + operationId: patchUser + description: change a user's data + /auth: + get: + tags: [auth] + operationId: getAuth + description: get login data + post: + tags: [auth] + operationId: postAuth + description: log-in to the server + /auth/login/{username}/link: + parameters: + - name: username + in: path + required: true + schema: {type: "string"} + description: human-readable unique name of an user + get: + tags: [auth] + operationId: getAuthLink + description: get a login link for this user + post: + tags: [auth] + operationId: postAuthLink + description: generate and send a login link for this user + /auth/logout: + post: + tags: [auth] + operationId: postLogout + description: delete this request's credentials + /auth/access/{scene}: + parameters: + - $ref: '#/components/parameters/scene' + get: + tags: [auth] + operationId: getAccess + description: get a scene's access rights + responses: + '200': + description: Access map defined for this scene + content: + application/json: + schema: + type: array + items: + type: object + required: ["uid", "username", "access"] + properties: + uid: { $ref: "#/components/schemas/Uid"} + username: {type: string} + access: { $ref: "#/components/schemas/AccessType" } + '401': + $ref: "#/components/responses/HTTPError" + patch: + tags: [auth] + operationId: patchAccess + description: edit a scene's access rights +# Administrative data. Might contain server configuration routes in the future + /admin/stats: + get: + tags: [admin] + operationId: getAdminStats + description: get server stats + /admin/mailtest: + post: + tags: [admin] + operationId: postAdminMailtest + description: sends a test email + +components: + parameters: + scene: + name: scene + in: path + required: true + schema: {type: string } + description: unique name of a scene + example: foo + file: + name: file + in: path + required: true + schema: {type: "string"} + description: | + relative path to a scene's file. + Might contain slashs, though openAPI spec won't allow them in test queries + examples: + folder: + summary: a file in a nested folder + value: models/foo.glb + thumbnail: + summary: a thumbnail for this scene + value: "scene-image-thumb.jpg" + document: + summary: a voyager scene document file + value: scene.svx.json + responses: + 'HTTPError': + description: Generic HTTP error response whose content depends on the request's "Accept" header + content: + application/json: + schema: + type: object + required: ["code", "message"] + properties: + code: + description: | + [HTTP Status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) code + type: number + format: int32 + minimum: 100 + maximum: 599 + message: + type: string + text/plain: + schema: + type: "string" + example: "Bad Request" + text/html: + schema: + type: "string" + + schemas: + Scene: + type: object + required: ["ctime", "mtime", "author_id", "author", "id", "access"] + properties: + ctime: {type: "string", format: "date-time"} + mtime: {type: "string", format: "date-time"} + author_id: {$ref:"#/components/schemas/Uid"} + author: {type: "string"} + id: {$ref:"#/components/schemas/Uid"} + name: {type: "string"} + thumb: {type: "string", desciption: "URI to the scene's thumbnail representation if it exists"} + access: { + type: object, + required: ["any", "default"], + properties: { + default: {$ref:"#/components/schemas/AccessType"}, + any: {$ref:"#/components/schemas/AccessType"}, + user: {$ref:"#/components/schemas/AccessType"}, + } + } + User: + type: object + required: ["uid", "username", "isAdministrator"] + properties: + uid: {$ref: "#/components/schemas/Uid"} + username: {type: "string", example: "alice" } + isAdministrator: {type: "boolean"} + Uid: + type: "string" + pattern: '^\d+$' + description: + string representation of unique IDs. + Applicable for users or scenes, but uids are not expected to be unique across namespaces + UIDs are often stringified to prevent rounding errors on large intergers in the javascript engine + AccessType: + type: string + enum: ["none", "read", "write", "admin"] diff --git a/en/doc/guides/api.md b/en/doc/guides/api.md index f290d0f0..c36ab23d 100644 --- a/en/doc/guides/api.md +++ b/en/doc/guides/api.md @@ -4,10 +4,7 @@ title: Using the API ## Using the API -eCorpus provides a two-part API: - - - webDAV on `/scenes/**` to access scene files. - - REST on `/api/v1/**` for administrative management. +eCorpus provides a comprehensive API that build on DPO-Voyager's requirements. ### Authentication @@ -19,7 +16,9 @@ Header encoding is handled automatically by most utilities. Example with curl: curl -XGET -u ":" https://ecorpus.holusion.com/[...] ``` -### API webDAV +Get the full [API reference](/en/doc/references/api.md) + +### /scenes API File organization: @@ -46,11 +45,4 @@ So to retrieve a: curl -XGET -u ":" https://ecorpus.holusion.com//scenes/foo/models/foo.glb ``` -Les verbes `GET` `PUT` `MOVE` `COPY` `DELETE` `MKCOL` et `PROPFIND` sont supportés, avec un comportement se conformant généralement à la [spécification](http://www.webdav.org/specs/rfc4918.html){:target="_blank"}. - - -### API REST - -The REST API can be accessed at `/api/v1/`. It uses standard HTTP verbs. - -See the [route reference](/en/doc/references/api) for details. +`GET` `PUT` `MOVE` `COPY` `DELETE` `MKCOL` and `PROPFIND` methods are supported, with a behaviour that should conform to [RFC4918](http://www.webdav.org/specs/rfc4918.html){:target="_blank"}, but don't expect Class 2 or even Class 1 compliance. diff --git a/en/doc/references/api.html b/en/doc/references/api.html new file mode 100644 index 00000000..bbb719e7 --- /dev/null +++ b/en/doc/references/api.html @@ -0,0 +1,106 @@ +--- +title: API eCorpus +--- + +

eCorpus HTTP API

+ +{% assign api = site.data.openapi %} + + +{{ api.info.description | markdownify }} + + +{% for tag in api.tags %} +

{{tag.name}}

+ + {{tag.description | markdownify }} + {% for path in api.paths %} + {% for operation in path[1] %} + {% if operation[0] == "summary" or operation[0] == "parameters" %} + {% continue %} + {%endif %} + {% assign method = operation[0] | replace_first: "x-", "" %} +

+ + {{ method }} + + {{ path[0] }} +

+ {% if path[1].parameters %} +
+ {% for param in path[1].parameters %} + {% if param["$ref"] %} + {% assign parts = param["$ref"]|replace_first: "#", ""| split: "/" %} + {% assign p = api %} + {% for part in parts %} + {% if part == empty %} {% continue %} {% endif %} + {% assign p = p[part] %} + {% endfor %} + {% else %} + {% assign p = param %} + {% endif %} +

+ {% if part == empty %} {% continue %} {% endif %} + {{p.name}} ({{p.in}}): {{p.description}} +

+ {% endfor %} +
+ {% endif %} +

+ {{operation[1].description | markdownify }} +

+ {% endfor %} + + {% endfor %} + +{% endfor %} + + + \ No newline at end of file diff --git a/en/doc/references/api.md b/en/doc/references/api.md deleted file mode 100644 index 69ed4643..00000000 --- a/en/doc/references/api.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: API eCorpus ---- - -## API eCorpus - -See [API user guide](/en/doc/guides/api). - -All routes must be prefixed with `/api/v1/`. - -Some routes require administration rights. - -### /login - -#### GET /login - -#### POST /login - -Authenticates a user. - -#### GET /login/:username/link - -Returns a login link for the user concerned in `text/plain` format. - -Example content: -```text -https://irhis.ecorpus.holusion.com/api/v1/login?payload=[...]&redirect=%2F -``` - -#### GET /users - -Returns the list of users in JSON format according to the following scheme: - -```json -[ - { - "uid": 280255476455992, - "isAdministrator": false, - "username": "jdupont", - "email": "jean.dupont@example.com" - } -] -``` - -#### POST /users - -Create a user - -The request body must be in `application/json` format. Example with curl: - -```bash -curl -XPOST -H "Content-Type: application/json" -d "{\"username\":\"jdupont\", \"password\":\"some_secret_string\", \"isAdministrator\":false, \"email\":\"jean.dupont@example.com\"}" https://ecorpus.example.com/api/v1/users -``` - -the `username` property must satisfy the following regular expression: `/^[\w]{3,40}$/`. - -#### DELETE /users/:uid - -Deletes a user using its `uid`. - -Requires administration rights. - -#### PATCH /users/:uid - -Changes one or more properties of a user using its `uid`. - -Request body must be in `application/json` format. Same format as for user creation. - -#### GET /scenes - -The behavior differs according to the expected format (header `Accept`). - -##### application/json - -Retrieves the list of scenes in JSON format. More efficient than `PROPFIND /scenes`. - -##### application/zip - -Retrieves a zip of all the scenes in the instance. - -#### POST /scenes - > postScenes - -```json -[ - { - "name": "test", - "author_id": 280255476455992, - "author": "jdupont", - "id": 36943841590670, - "access": { - "any": null, - "default": "none" - }, - "ctime": "2023-10-04T12:26:10.000Z", - "mtime": "2023-10-04T12:26:11.000Z" - } -] -``` - - - -#### POST /scenes/:scene - -Create a scene. Wait for data in `multipart/form-data` format. The `scene` field must contain a file [glb](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#glb-file-format-specification). - - -#### PATCH /scenes/:scene - -Rename a scene by sending a `name` field in the request body. - -#### GET /scenes/:scene/history - -Recovers the complete history of a scene. - -#### POST /scenes/:scene/history - -Modifies the history of a scene. - -#### GET /scenes/:scene - -The behavior differs according to the expected format (header `Accept`). - -##### Application/json - -Scene data in JSON format. - -##### Application/zip - -All the scene sources in their latest version in zip format. - -#### GET /scenes/:scene/files - -Lists the files in the scene. - -#### GET /scenes/:scene/permissions - -Lists scene permissions. - -#### PATCH /scenes/:scene/permissions - -Modifies scene permissions. - - - diff --git a/fr/doc/guides/api.md b/fr/doc/guides/api.md index a314cdfd..efce934d 100644 --- a/fr/doc/guides/api.md +++ b/fr/doc/guides/api.md @@ -4,10 +4,8 @@ title: Utiliser l'API ## Utiliser l'API -eCorpus fournit une API en deux parties : +eCorpus fournit une API complète qui couvre les besoins de DPO Voyager en y ajoutant des interfaces de gestion des utilisateurs, contrôle des droits d'accès, organisation des scènes en collections, etc... - - webDAV sur `/scenes/**` pour accéder aux fichiers des scènes. - - REST sur `/api/v1/**` pour la gestion administrative. ### Authentification @@ -19,7 +17,7 @@ L'encodage du header est géré automatiquement par la plupart des utilitaires. curl -XGET -u ":" https://ecorpus.holusion.com/[...] ``` -### API webDAV +### Organisation des scenes Organisation des fichiers : @@ -46,11 +44,9 @@ Ainsi pour récupérer un modèle : curl -XGET -u ":" https://ecorpus.holusion.com//scenes/foo/models/foo.glb ``` -Les verbes `GET` `PUT` `MOVE` `COPY` `DELETE` `MKCOL` et `PROPFIND` sont supportés, avec un comportement se conformant généralement à la [spécification](http://www.webdav.org/specs/rfc4918.html){:target="_blank"}. +Les verbes `GET` `PUT` `MOVE` `COPY` `DELETE` `MKCOL` et `PROPFIND` sont supportés, avec un comportement se conformant généralement à la [spécification](http://www.webdav.org/specs/rfc4918.html){:target="_blank"}. Attention tout de même : Il s'agit d'une implémentation partielle de la spécification. ### API REST -L'API REST est accessible sur `/api/v1/`. Elle utilise les verbes standard HTTP. - -Voir la [référence des routes](/fr/doc/references/api) pour plus de détails. +L'API REST est documentée via un schéma [OpenAPI v3.1.0](https://spec.openapis.org/oas/v3.1.0), téléchargeable ici : [openapi.yml](https://raw.githubusercontent.com/Holusion/eCorpus/gh_pages//_data/openapi.yml). L'API est présentée sous forme lisible en anglais uniquement sur ce site à cette page : [https://ecorpus.eu/en/doc/references/api](/en/doc/references/api). diff --git a/fr/doc/references/api.md b/fr/doc/references/api.md deleted file mode 100644 index d5a0c19f..00000000 --- a/fr/doc/references/api.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: API eCorpus ---- - -## API eCorpus - -Voir le [guide d'utilisation de l'API](/fr/doc/guides/api). - -Toutes les routes doivent être préfixées de `/api/v1/`. - -Certaines routes requièrent des droits d'administration. - -### /login - -#### GET /login - -#### POST /login - -Authentifie un utilisateur. - -#### GET /login/:username/link - -Retourne un lien de connexion pour l'utilisateur concerné au format `text/plain`. - -Exemple de contenu : -```text -https://irhis.ecorpus.holusion.com/api/v1/login?payload=[...]&redirect=%2F -``` - -#### GET /users - -Retourne la liste des utilisateurs au format JSON suivant le schéma suivant : - -```json -[ - { - "uid": 280255476455992, - "isAdministrator": false, - "username": "jdupont", - "email": "jean.dupont@example.com" - } -] -``` - -#### POST /users - -Crée un utilisateur - -Le corps de la requête doit être au format `application/json`. Exemple avec curl : - -```bash -curl -XPOST -H "Content-Type: application/json" -d "{\"username\":\"jdupont\", \"password\":\"some_secret_string\", \"isAdministrator\":false, \"email\":\"jean.dupont@example.com\"}" https://ecorpus.example.com/api/v1/users -``` - -la propriété `username` doit satisfaire l'expression régulière suivante : `/^[\w]{3,40}$/`. - -#### DELETE /users/:uid - -Supprime un utilisateur en utilisant son `uid`. - -Requiers un droit d'administration. - -#### PATCH /users/:uid - -Change une ou plusieurs propriétés d'un utilisateur en utilisant son `uid`. - -Le corps de la requête doit être au format `application/json`. Même format que pour la création d'utilisateur. - -#### GET /scenes - -Le comportement diffère selon le format attendu (header `Accept`). - -##### application/json - -Récupère la liste des scènes au format JSON. Plus efficace que `PROPFIND /scenes`. - -##### application/zip - -Récupère un zip de l'ensemble des scènes de l'instance. - - -#### POST /scenes - > postScenes - -```json -[ - { - "name": "test", - "author_id": 280255476455992, - "author": "jdupont", - "id": 36943841590670, - "access": { - "any": null, - "default": "none" - }, - "ctime": "2023-10-04T12:26:10.000Z", - "mtime": "2023-10-04T12:26:11.000Z" - } -] -``` - - - -#### POST /scenes/:scene - -Crée une scène. Attends des données en format `multipart/form-data`. Le champ `scene` doit contenir un fichier [glb](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#glb-file-format-specification). - - -#### PATCH /scenes/:scene - -Permet de renommer une scène en envoyant un champ `name` dans le corps de la requête. - -#### GET /scenes/:scene/history - -Récupère l'historique complet d'une scène. - -#### POST /scenes/:scene/history - -Modifie l'historique d'une scène. - -#### GET /scenes/:scene - -Le comportement diffère selon le format attendu (header `Accept`). - -##### Application/json - -Données de la scène au format JSON. - -##### Application/zip - -Ensemble des sources de la scène dans leur dernière version au format zip. - -#### GET /scenes/:scene/files - -Liste les fichiers de la scène. - -#### GET /scenes/:scene/permissions - -Liste les permissions de la scène. - -#### PATCH /scenes/:scene/permissions - -Modifie les permissions de la scène. \ No newline at end of file