Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delegation journey documentation #5025

Merged
merged 6 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"@context" : [
"https://bluebrain.github.io/nexus/contexts/files.json",
"https://bluebrain.github.io/nexus/contexts/metadata.json"
],
"@id" : "http://delta:8080/v1/resources/fcp5xcw67hittxm/loeu5kgu48i8tw7/_/1205b629-2a73-4891-abff-140a64e9c391",
"@type" : "File",
"description" : "a description of the file",
"name" : "My File",
"_bytes" : 29625,
"_constrainedBy" : "https://bluebrain.github.io/nexus/schemas/files.json",
"_createdAt" : "2024-06-14T12:53:38.516222Z",
"_createdBy" : "http://delta:8080/v1/realms/test-pmcfwjobxkuvebro/users/fwhbqlnnhqncpsqk",
"_deprecated" : false,
"_digest" : {
"_algorithm" : "SHA-256",
"_value" : "05bf442810213b9e5fecd5242eefeff1f3d207913861c96658c75ccf58997e87"
},
"_filename" : "myfile.png",
"_incoming" : "http://delta:8080/v1/files/fcp5xcw67hittxm/loeu5kgu48i8tw7/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Ffcp5xcw67hittxm%2Floeu5kgu48i8tw7%2F_%2F1205b629-2a73-4891-abff-140a64e9c391/incoming",
"_keywords" : {
"key1" : "value1",
"key2" : "value2"
},
"_location" : "myprefix/fcp5xcw67hittxm/loeu5kgu48i8tw7/files/f/f/9/5/3/4/c/2/ngbeydtjyibvcanj",
"_mediaType" : "image/png",
"_origin" : "External",
"_outgoing" : "http://delta:8080/v1/files/fcp5xcw67hittxm/loeu5kgu48i8tw7/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Ffcp5xcw67hittxm%2Floeu5kgu48i8tw7%2F_%2F1205b629-2a73-4891-abff-140a64e9c391/outgoing",
"_project" : "http://delta:8080/v1/projects/fcp5xcw67hittxm/loeu5kgu48i8tw7",
"_rev" : 1,
"_self" : "http://delta:8080/v1/files/fcp5xcw67hittxm/loeu5kgu48i8tw7/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Ffcp5xcw67hittxm%2Floeu5kgu48i8tw7%2F_%2F1205b629-2a73-4891-abff-140a64e9c391",
"_storage" : {
"@id" : "https://bluebrain.github.io/nexus/vocabulary/mys3storage",
"@type" : "S3Storage",
"_rev" : 3
},
"_updatedAt" : "2024-06-14T12:53:38.516222Z",
"_updatedBy" : "http://delta:8080/v1/realms/test-pmcfwjobxkuvebro/users/fwhbqlnnhqncpsqk",
"_uuid" : "c96a229c-8d1d-46a5-8f47-08555fd98cb3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
curl -X POST \
-H "Content-Type: application/json" \
"http://localhost:8080/v1/delegate/files/myorg/myproject?storage=mys3storage" -d \
'{
"protected" : "eyJleHAiOjE3MTg2Mjg1NDUsImFsZyI6IlJTMjU2In0",
"payload" : "eyJidWNrZXQiOiJqNDc4M2NjNWFkY2F1a3UiLCJwYXRoIjoibXlwcmVmaXgvYTE0bTYxZWgzajVuNzVjLzhrbXlpb2QyMzM1MnhpZC9maWxlcy9iLzIvOS80LzMvYy9jLzYvaG5qeXR3b2x0ZnVyc2JlaCIsIm1lZGlhVHlwZSI6ImltYWdlL2RhbiIsIm1ldGFkYXRhIjp7ImRlc2NyaXB0aW9uIjoicnByZndzdWpveGJpaXllaSIsImtleXdvcmRzIjp7ImtvZXZvd3Bsc3Jld2NlZGIiOiJ2dnNlaW9wa3Z5Y3d1dG1oIn0sIm5hbWUiOiJmbW94dHh3a3JvdWhtZG90In0sImlkIjoiaHR0cDovL2RlbHRhOjgwODAvdjEvcmVzb3VyY2VzL2ExNG02MWVoM2o1bjc1Yy84a215aW9kMjMzNTJ4aWQvXy9hNGE5ODE2Mi1jYTNmLTQ2YmUtYWUxMC00MzJjYTZmOTdjNGYifQ",
"signature" : "htQLymfQIrks7MejErb4v3mnhQT2W6iPZdkd7LVBPJ0Ksybj8XG8dbTJH5pjZJF7-HXi848R14tquZ6iSeXpEqFGiZYge8obPQRLpJA0qbc9Mmhlq-CTbIdsy5OFpdzcDadSj6_k_kzuU2PR-Fli9GtH-34z2d4C9dWsBmnUo_IA3dvSFCF_PaQuajo7cJYa_0yc4VVGKG-xYi9yV4ylD5D2cxMUDFun78NOKDD_2upF-kuf9t5E-NjCl0DffkelbqYuH6nMop2zmwfu-cwHnChaDwKM7HLJGLomD5duU5sq-mVsunnMy58NgzMecLGDbER-27zk7w0TwxkXTKfxWg"
}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"protected" : "eyJleHAiOjE3MTg2Mjg1NDUsImFsZyI6IlJTMjU2In0",
"payload" : "eyJidWNrZXQiOiJqNDc4M2NjNWFkY2F1a3UiLCJwYXRoIjoibXlwcmVmaXgvYTE0bTYxZWgzajVuNzVjLzhrbXlpb2QyMzM1MnhpZC9maWxlcy9iLzIvOS80LzMvYy9jLzYvaG5qeXR3b2x0ZnVyc2JlaCIsIm1lZGlhVHlwZSI6ImltYWdlL2RhbiIsIm1ldGFkYXRhIjp7ImRlc2NyaXB0aW9uIjoicnByZndzdWpveGJpaXllaSIsImtleXdvcmRzIjp7ImtvZXZvd3Bsc3Jld2NlZGIiOiJ2dnNlaW9wa3Z5Y3d1dG1oIn0sIm5hbWUiOiJmbW94dHh3a3JvdWhtZG90In0sImlkIjoiaHR0cDovL2RlbHRhOjgwODAvdjEvcmVzb3VyY2VzL2ExNG02MWVoM2o1bjc1Yy84a215aW9kMjMzNTJ4aWQvXy9hNGE5ODE2Mi1jYTNmLTQ2YmUtYWUxMC00MzJjYTZmOTdjNGYifQ",
"signature" : "htQLymfQIrks7MejErb4v3mnhQT2W6iPZdkd7LVBPJ0Ksybj8XG8dbTJH5pjZJF7-HXi848R14tquZ6iSeXpEqFGiZYge8obPQRLpJA0qbc9Mmhlq-CTbIdsy5OFpdzcDadSj6_k_kzuU2PR-Fli9GtH-34z2d4C9dWsBmnUo_IA3dvSFCF_PaQuajo7cJYa_0yc4VVGKG-xYi9yV4ylD5D2cxMUDFun78NOKDD_2upF-kuf9t5E-NjCl0DffkelbqYuH6nMop2zmwfu-cwHnChaDwKM7HLJGLomD5duU5sq-mVsunnMy58NgzMecLGDbER-27zk7w0TwxkXTKfxWg"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
curl -X POST \
-H "Content-Type: application/json" \
"http://localhost:8080/v1/delegate/files/myorg/myproject/validate?storage=mys3storage" -d \
'{
"filename": "myfile.png",
"mediaType": "image/png",
"metadata": {
"name": "My File",
"description": "a description of the file",
"keywords": {
"key1": "value1",
"key2": "value2"
}
}
}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"@context" : [
"https://bluebrain.github.io/nexus/contexts/files.json",
"https://bluebrain.github.io/nexus/contexts/metadata.json"
],
"@id" : "http://delta:8080/v1/resources/hkrxvoxdyiiev1p/03vctrp70usfehq/_/iwa41vwspwke6nx",
"@type" : "File",
"_bytes" : 29625,
"_constrainedBy" : "https://bluebrain.github.io/nexus/schemas/files.json",
"_createdAt" : "2024-06-14T12:44:36.525177Z",
"_createdBy" : "http://delta:8080/v1/realms/test-vuaplrsvrbkpkhca/users/byfxikrrdlmmvsvv",
"_deprecated" : false,
"_digest" : {
"_algorithm" : "SHA-256",
"_value" : "05bf442810213b9e5fecd5242eefeff1f3d207913861c96658c75ccf58997e87"
},
"_filename" : "myfile.png",
"_incoming" : "http://delta:8080/v1/files/hkrxvoxdyiiev1p/03vctrp70usfehq/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Fhkrxvoxdyiiev1p%2F03vctrp70usfehq%2F_%2Fiwa41vwspwke6nx/incoming",
"_location" : "relative/path/to/myfile.png",
"_mediaType" : "image/png",
"_origin" : "External",
"_outgoing" : "http://delta:8080/v1/files/hkrxvoxdyiiev1p/03vctrp70usfehq/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Fhkrxvoxdyiiev1p%2F03vctrp70usfehq%2F_%2Fiwa41vwspwke6nx/outgoing",
"_project" : "http://delta:8080/v1/projects/hkrxvoxdyiiev1p/03vctrp70usfehq",
"_rev" : 1,
"_self" : "http://delta:8080/v1/files/hkrxvoxdyiiev1p/03vctrp70usfehq/http:%2F%2Fdelta:8080%2Fv1%2Fresources%2Fhkrxvoxdyiiev1p%2F03vctrp70usfehq%2F_%2Fiwa41vwspwke6nx",
"_storage" : {
"@id" : "https://bluebrain.github.io/nexus/vocabulary/mys3storage",
"@type" : "S3Storage",
"_rev" : 3
},
"_updatedAt" : "2024-06-14T12:44:36.525177Z",
"_updatedBy" : "http://delta:8080/v1/realms/test-vuaplrsvrbkpkhca/users/byfxikrrdlmmvsvv",
"_uuid" : "79695062-ecbb-42dc-a62d-61c2c02be129"
}
15 changes: 15 additions & 0 deletions docs/src/main/paradox/docs/delta/api/assets/files/register-post.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
curl -X POST \
-H "Content-Type: application/json" \
"http://localhost:8080/v1/files/myorg/myproject/register/myfile?storage=mys3storage" -d \
'{
"path": "relative/path/to/myfile.png",
"mediaType": "image/png",
"metadata": {
"name": "My File",
"description": "a description of the file",
"keywords": {
"key1": "value1",
"key2": "value2"
}
}
}'
140 changes: 125 additions & 15 deletions docs/src/main/paradox/docs/delta/api/files-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ When using the endpoints described on this page, the responses will contain glob
- `_incoming`: address to query to obtain the @ref:[list of incoming links](resources-api.md#list-incoming-links)
- `_outgoing`: address to query to obtain the @ref:[list of outgoing links](resources-api.md#list-outgoing-links)

## Custom file metadata

When creating file resources, users can optionally provide custom metadata to be indexed and therefore searchable.

This takes the form of a `metadata` field containing a JSON Object with one or more of the following fields:

- `name`: a string which is a descriptive name for the file. It will be indexed in the full-text search.
- `description`: a string that describes the file. It will be indexed in the full-text search.
- `keywords`: a JSON object with `Label` keys and `string` values. These keywords will be indexed and can be used to search for the file.

## Indexing

Expand All @@ -52,10 +61,7 @@ This part can contain the following disposition parameters:

**Headers:**

- `x-nxs-file-metadata`: an optional JSON object containing one or more of the following fields:
- `name`: a string which is a descriptive name for the file. It will be indexed in the full-text search.
- `description`: a string that describes the file. It will be indexed in the full-text search.
- `keywords`: a JSON object with `Label` keys and `string` values. These keywords will be indexed and can be used to search for the file.
- `x-nxs-file-metadata`: an optional JSON object containing one or more of fields described in @ref:[custom file metadata](#custom-file-metadata).
- `x-nxs-file-content-length`: the size of the uploaded file:
- mandatory to upload to a S3 storage
- ignored for other types of storage
Expand Down Expand Up @@ -127,10 +133,7 @@ POST /v1/files/{org_label}/{project_label}?storage={storageId}&tag={tagName}
- `{filename}`: String - the name that will be given to the file during linking. This field is optional. When not specified, the original filename is retained.
- `{mediaType}`: String - the MediaType fo the file. This field is optional. When not specified, Nexus Delta will attempt to detect it.
- `{tagName}` an optional label given to the linked file resource on its first revision.
- `{metadata}`: JSON Object - optional object containing one or more of the following fields:
- `name`: a string which is a descriptive name for the file. It will be indexed in the full-text search.
- `description`: a string that describes the file. It will be indexed in the full-text search.
- `keywords`: a JSON object with `Label` keys and `string` values. These keywords will be indexed and can be used to search for the file.
- `{metadata}`: JSON Object - Optional, see @ref:[custom file metadata](#custom-file-metadata).

**Example**

Expand Down Expand Up @@ -167,10 +170,7 @@ When not specified, the default storage of the project is used.
- `{filename}`: String - the name that will be given to the file during linking. This field is optional. When not specified, the original filename is retained.
- `{mediaType}`: String - the MediaType fo the file. This field is optional. When not specified, Nexus Delta will attempt to detect it.
- `{tagName}` an optional label given to the linked file resource on its first revision.
- `{metadata}`: JSON Object - optional object containing one or more of the following fields:
- `name`: a string which is a descriptive name for the file. It will be indexed in the full-text search.
- `description`: a string that describes the file. It will be indexed in the full-text search.
- `keywords`: a JSON object with `Label` keys and `string` values. These keywords will be indexed and can be used to search for the file.
- `{metadata}`: JSON Object - Optional, see @ref:[custom file metadata](#custom-file-metadata).

**Example**

Expand Down Expand Up @@ -437,11 +437,121 @@ Request
Response
: @@snip [listed.json](assets/files/listed.json)

## Delegation & Registration
To support files stored in the cloud, delta allows users to register files already uploaded to S3. This is useful primarily for large files where uploading directly through delta is inefficient and expensive.
## Delegation & Registration (S3 only)
To support files stored in the cloud, Delta allows users to register files already uploaded to S3. This is useful primarily for large files where uploading directly through Delta using HTTP is inefficient and expensive.

There are two use cases: registering an already uploaded file by specifying its path, and asking Delta to generate a path in its standard format.

### Register external file

This endpoint accepts a path and creates a new file resource based on an existing S3 file.

```
POST /v1/files/{org_label}/{project_label}/register/{file_id}?storage={storageId}&tag={tagName}
{
"path": "{path}",
"mediaType": "{mediaType}",
"metadata": {metadata}
}
```

... where

- `{path}`: String - the relative path to the file from the root of S3.
- `{mediaType}`: String - Optional @link:[MIME](https://en.wikipedia.org/wiki/MIME){ open=new } specifying the file type. If omitted this will be inferred by S3.
- `{metadata}`: JSON Object - Optional, see @ref:[custom file metadata](#custom-file-metadata).

**Example**

Request
: @@snip [register-post.sh](assets/files/register-post.sh)

Response
: @@snip [register-post.json](assets/files/register-post.json)

### Delegating file uploads

Users can use delegation for files that cannot be uploaded through Delta (e.g. large files). Here Delta will provide bucket and path details for the upload. Users are then expected to upload the file using other methods, and call back to Delta to register this file with the same metadata that was initially validated. The three steps are outlined in detail below.

#### 1. Validate and generate path for file delegation

Delta accepts and validates the following payload.

```
POST /v1/delegate/files/{org_label}/{project_label}/validate?storage={storageId}
{
"filename": "{filename}",
"mediaType": "{mediaType}",
"metadata": {metadata}
}
```

... where

- `{filename}`: String - mandatory name given to the file within the generated path.
- `{mediaType}`: String - Optional @link:[MIME](https://en.wikipedia.org/wiki/MIME){ open=new } specifying the file type. If omitted this will be inferred by S3.
- `{metadata}`: JSON Object - Optional, see @ref:[custom file metadata](#custom-file-metadata).

It then generates the following details for the file:

```json
{
"bucket": "<s3 bucket>",
"id": "<file resource identifier>",
"path": "<path from s3 root>",
"mediaType": "<user provided mediaType>",
"metadata": {}
}
```

The user is expected to upload their file to `path` within `bucket`. The `id` is reserved for when the file resource is created. `mediaType` and `metadata` are what the user specified in the request.

This payload is then signed using the [flattened JWS serialization format](https://datatracker.ietf.org/doc/html/rfc7515#section-7.2.2) to ensure that Delta has validated and generated the correct data. This same payload will be passed when creating the file resource.

```json
{
"payload": "<base64 encoded payload contents>",
"protected": "<integrity-protected header contents>",
"signature": "<signature contents>"
}
```

The `payload` field can be base64 decoded to access the generated file details. Note that `protected` contains an expiry field `exp` with the datetime at which this signature will expire (in epoch seconds). To view this can also be base64 decoded.

**Example**

There are two use cases: registering an already uploaded file by specifying its path, and asking Delta to generate a path with its standard format.
Request
: @@snip [delegate-validate-post.sh](assets/files/delegate-validate-post.sh)

Response
: @@snip [delegate-validate-post.json](assets/files/delegate-validate-post.json)

#### 2. Upload file to S3

Using the bucket and path from the previous step, the file should be uploaded to S3 by whatever means are appropriate. The only restriction is that this must be finished before the expiry datetime of the signed payload.

#### 3. Create delegated file resource

Once the file has been uploaded to S3 at the specified path, the file resource can be created. The payload can be passed back exactly as it was returned in the previous step.

```
POST /v1/delegate/files/{org_label}/{project_label}?storage={storageId}
{
"payload": "<base64 encoded payload contents>",
"protected": "<integrity-protected header contents>",
"signature": "<signature contents>"
}
```

Delta will verify that the signature matches the payload and that the expiry date is not passed. Then the file will be registered as a resource. The usual file resource response will be returned with all the standard metadata and file location details.

**Example**

Request
: @@snip [delegate-create-post.sh](assets/files/delegate-create-post.sh)

Response
: @@snip [delegate-create-post.json](assets/files/delegate-create-post.json)

## Server Sent Events

Expand Down