-
Notifications
You must be signed in to change notification settings - Fork 2
RO API 6
⚠️ The API name has been changed
The API name has changed from Research Object Storage and Retrieval API (ROSR API) to Research Object API (RO API).
The Research Object API allows:
- Storing and retrieving research objects.
- Storing and retrieving resources aggregated within the research objects.
- Annotating the aggregated resources, including the research object itself.
The RO API is based heavily on the Research Object model, version 0.1 at the moment of writing. It therefore uses the Open Annotation and the Object Reuse and Exchange models. The mechanism of using proxies and annotations as gateways for aggregated resources and annotation bodies has been based on the AtomPub specification.
⚠️ Missing
The following functions are missing
* Specify RDF classes of resources that are added via API (i.e. query parameters)
Authorization and access control policy is out of scope of this document but for simplicity, the use of OAuth 2.0 with the Bearer authorization schema will be assumed.
The response format may be an RDF file or a list of URIs.C: GET /ROs/ HTTP/1.1 C: Host: example.com C: Accept: text/plain C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 200 OK S: Content-Type: text/uri-list S: Content-Length: ... S: S: http://example.com/ROs/ro1/ S: http://example.com/ROs/ro2/ S: ...
The Research Object id can be any string. If this id is already in use, 409 Conflict will be returned.
C: POST /ROs/ HTTP/1.1 C: Host: example.com C: Content-Type: text/plain C: Content-Length: ... C: Accept: text/turtle C: Slug: ro_id C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/ S: Content-Type: text/turtle S: Content-Length: ... S: S: (the initial manifest)
It's possible to create a completely new RO from a set of different files and folders collected in a one zip file. RO service aggregates all sent resources including folders and maintains their structure. The operation is performed in the background. User receives link to the operation status object as a server response. Status object contains information about the process status, the final uri of processed RO, possible error messages if an error occurred. Status object knows how many resources were submitted and how many of them were already processed by server.
C: POST /zip/create HTTP/1.1 C: Host: example.com C: Content-Type: application/zip C: Content-Length: ... C: Accept: text/turtle C: Slug: ro_id C: Authorization: Bearer h480djs93hd8 C: C: (the zip file with some files or/and directories) S: HTTP/1.1 201 Created S: Location: http://example.com/zip/create/12345 S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "running", S: "submitted_resources": "15", S: "processed_resources": "3" S: }
Get a copy of job status (running).
Get a job status (finished)C: GET [http://example.com/zip/create/12345] HTTP/1.1 C: Accept: application/json S: HTTP/1.1 200 OK S: Content-Type: application/json S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "running", S: "submitted_resources": "15", S: "processed_resources": "8" S: }
C: GET [http://example.com/zip/create/12345] HTTP/1.1 C: Accept: application/json S: HTTP/1.1 200 OK S: Content-Type: application/json S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "done", S: "submitted_resources": "15", S: "processed_resources": "15" S: }
It's possible to upload to a server an existing RO. Once server receives a zip with an existing RO, server unpacks and processes the given artifact in a background process in a few simple steps:
1. Look for the .ro/manifest.rdf. If not found, 400 Bad Request is returned. 1. Create the RO. 1. Scan for each resource aggregated in the RO and add it to the RO. 1. If there is anything else in the zip which was not aggregated, log it but don't return error.
User receives link to the operation status object as a server response. Status object contains information about process status, the final uri of processed RO and possible error messages if an error occurred. Status object knows how many resources were submitted and how many of them were already processed by server.
Get a job status (running).C: POST /zip/upload HTTP/1.1 C: Host: example.com C: Content-Type: application/zip C: Content-Length: ... C: Accept: text/turtle C: Slug: ro_id C: Authorization: Bearer h480djs93hd8 C: C: (the zip with manifest and resources) S: HTTP/1.1 201 Created S: Location: [http://example.com/zip/upload/12345] S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "running", S: "submitted_resources": "15", S: "processed_resources": "3" S: }
Get a copy job status (finished).C: GET http://example.com/zip/upload/12345 HTTP/1.1 C: Accept: application/json S: HTTP/1.1 200 OK S: Content-Type: application/json S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "running", S: "submitted_resources": "15", S: "processed_resources": "10" S: }
C: GET http://example.com/zip/upload/12345 HTTP/1.1 C: Accept: application/json S: HTTP/1.1 200 OK S: Content-Type: application/json S: S: { S: "target": "http://example.com/ROs/ro_id/", S: "status": "done", S: "submitted_resources": "15", S: "processed_resources": "15" S: }
What do you get when you ask for an RO? This implementation is related to the page ??RO dereferencing:
- If "text/html" is requested, the response is a 303 redirection to an HTML page representing the RO.
- If any RDF type is requested, the response is a 303 redirection to the manifest.
- If "application/zip", "multipart/related" or anything else (or nothing in particular) is requested, the response is a 303 redirection to a URI /zippedROs/:roid/. This is a specific resource only for downloading ROs as ZIP files. Requests to this resource will return a ZIP file regardless of the Accept header, which in case of web browsers is out of control of the user
RO requested (example) | Accept HTTP header | Response code | Response Location HTTP header (example) |
ROs/ro1/ | application/zip | 303 See Other | zippedROs/ro1/ |
ROs/ro1/ | text/html | 303 See Other | sandbox.../portal?ro=...ROs/ro1/ |
ROs/ro1/ | application/rdf+xml | 303 See Other | ROs/ro1/.ro/manifest.rdf |
ROs/ro1/ | text/turtle | 303 See Other | ROs/ro1/.ro/manifest.ttl?original=manifest.rdf |
ROs/ro1/ | - | 303 See Other | zippedROs/ro1/ |
Links to all 3 formats available are included as link headers or HTML links described in the ?RO dereferencing.
This example assumes retrieving the RO metadata, i.e. the manifest.
This example assumes retrieving a zip file.C: GET /ROs/ro_id/ HTTP/1.1 C: Host: example.com C: Accept: text/turtle C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 303 See Other S: Location: http://example.com/ROs/ro_id/.ro/manifest.ttl?original=manifest.rdf C: GET /ROs/ro_id/.ro/manifest.ttl?original=manifest.rdf HTTP/1.1 C: Host: example.com C: Accept: text/turtle C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 200 OK S: Content-Type: text/turtle S: Content-Length: ... S: S: <http://example.com/ROs/ro_id/.ro/manifest.rdf> a <http://purl.org/wf4ever/ro#Manifest> ; (...)
C: GET /ROs/ro_id/ HTTP/1.1 C: Host: example.com C: Accept: application/zip C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 303 See Other S: Location: http://example.com/zippedROs/ro_id/ C: GET /zippedROs/ro_id/ HTTP/1.1 C: Host: example.com C: Accept: application/zip C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 200 OK S: Content-Type: application/zip S: Content-Length: ... S: S: (content here)
C: DELETE /ROs/ro_id/ HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 204 No Content
Each resource aggregated in the research object has an associated proxy. Proxies are references to the resource in the context of the research object and in the case of external resources, their representations in the RO API. The structure of a proxy is described by ORE.
The API design here uses similar patterns to AtomPub, with an RO being analogous to an Atom feed, a proxy for an Atom item, and resource content for an Atom media resource. The Slug: header field is defined by AtomPub (http://tools.ietf.org/html/rfc5023).
Aggregating resources involves 2 steps, though in most cases one of them can be omitted:
- Creating a proxy for a resource.
- Uploading a resource.
application/vnd.wf4ever.proxy
and using a resource URI not pointed to by an existing proxy. When a proxy is created, the proxy target is automatically aggregated in the research object.
The resource URI is indicated either using the Slug: header
if a new internal resource is being aggregated (in which it is a relative URI reference), or in the request body otherwise. If the resource URI is not indicated in the Slug: header
nor in the request body, the server should generate any URI it sees fit, i.e. using a random UUID. The server will return 409 Conflict
if the resulting URI has already been aggregated in this research object. Client applications should not, however, make assumptions about the URI of the resulting resource but should, instead, use the ore:proxyFor link value returned by the service.
Resources are aggregated in the following ways:
- External resources: only create a proxy, pointing to the external resource.
- Internal resources: only upload a resource. The service will create the proxy automatically and will return the URI of the proxy rather than the URI of the resource itself.
- Internal resources, the long way: create a proxy and then upload the resource. This is the only method to add a proxy as an aggregated resource (a rare case).
application/vnd.wf4ever.proxy
signals to the RO service that a new proxy is being created.
A application/vnd.wf4ever.proxy
entity is an RDF/XML expression that describes just one ore:Proxy
resource. Other information present in the RDF is ignored. Behaviour is undefined if there is not exactly one ore:Proxy
resource described, and a service MAY reject such a request as ill-formed. (Future proposals may accept any format of RDF, and use a separate mechanism to signal that it is intended to be interpreted as a proxy description.)
The example below demonstrates adding a proxy for an internal resource, and then putting the new resource content at the server-indicated URI. The RO-internal name for the new resource is indicated using aC: POST /ROs/ro1/ HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.proxy C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ore="http://www.openarchives.org/ore/terms/" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ore:Proxy> C: <ore:proxyFor rdf:resource="http://external.example.com/resource.uri" /> C: </ore:Proxy> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: https://sandbox/rodl/ROs/ro1/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 S: Link: <http://external.example.com/resource.uri>; rel="http://www.openarchives.org/ore/terms/proxyFor" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ore="http://www.openarchives.org/ore/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="https://sandbox/rodl/ROs/ro1/"/> S: <ore:proxyFor rdf:resource="http://external.example.com/resource.uri" /> S: </rdf:Description> S: </rdf:RDF>
Slug: header
(following AtomPub). The supplied entity body is a Proxy description from which the proxyFor property is omitted.
The example below demonstrates the short-cut mechanism aggregating an internal resource by simply posting its content to the RO. TheC: POST /ROs/ro_id/ HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.proxy C: Slug: foo/bar.txt C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ore="http://www.openarchives.org/ore/terms/" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ore:Proxy> C: </ore:Proxy> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66 S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://www.openarchives.org/ore/terms/proxyFor" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ore="http://www.openarchives.org/ore/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="http://example.org/ROs/ro_id/"/> S: <ore:proxyFor rdf:resource="http://example.org/ROs/ro_id/foo/bar.txt" /> S: </rdf:Description> S: </rdf:RDF> C: GET /ROs/ro_id/foo/bar.txt HTTP/1.1 C: Host: example.com S: HTTP/1.1 404 Not Found C: PUT /ROs/ro_id/foo/bar.txt HTTP/1.1 C: Host: example.com C: Content-Type: text/plain C: C: This is the important note S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/foo/bar.txt S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ore="http://www.openarchives.org/ore/terms/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/foo/bar.txt"> S: <dct:creator rdf:resource="http://test2.myopenid.com"/> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2011-12-02T15:02:11Z</dct:created> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/AggregatedResource"/> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#Resource"/> S: </rdf:Description> S: </rdf:RDF>
Slug: header
is used to indicate the desired path within the RO. The server responds with the proxy description.
C: POST /ROs/ro_id/ HTTP/1.1 C: Host: example.com C: Content-Type: text/plain C: Content-Length: ... C: Slug: foo/bar.txt C: Authorization: Bearer h480djs93hd8 C: C: Lorem ipsum S: HTTP/1.1 201 Created S: Location: http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66 S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://www.openarchives.org/ore/terms/proxyFor" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ore="http://www.openarchives.org/ore/terms/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="http://example.org/ROs/ro_id/"/> S: <ore:proxyFor rdf:resource="http://example.org/ROs/ro_id/foo/bar.txt" /> S: </rdf:Description> S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/foo/bar.txt"> S: <dct:creator rdf:resource="http://test2.myopenid.com"/> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2011-12-02T15:02:11Z</dct:created> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/AggregatedResource"/> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#Resource"/> S: </rdf:Description> S: </rdf:RDF>
The example below demonstrates updating an internal resource. Updating external resources is out of control of the service.
Clients may use the proxy URI or, for internal resources, the resource URI.
Trying to create new content in this way or trying to update the manifest will result in 403 Forbidden.
When a resource that is RO metadata is modified, different formats can be used by means of content negotiation. For updating such resources, the clients may use either resource URIs or the format-specific URIs. Responses for PUT:C: PUT /ROs/ro1/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66 HTTP/1.1 C: Host: example.com C: Content-Type: text/plain C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: Lorem ipsum dolor sit amet S: HTTP/1.1 307 Temporary Redirect S: Location: http://example.com/ROs/ro_id/foo/bar.txt C: PUT /ROs/ro_id/foo/bar.txt HTTP/1.1 C: Host: example.com C: Content-Type: text/plain C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: Lorem ipsum dolor sit amet S: HTTP/1.1 200 OK
Resource requested (example) | URI Extension | Content-Type HTTP header | Response code | Request body RDF format |
---|---|---|---|---|
graph.rdf | yes | application/rdf+xml | 200 OK | based on URI extension and Content-Type HTTP header |
graph.rdf | yes | - | 200 OK | based on URI extension |
graph.rdf | yes | text/turtle | 200 OK | based on Content-Type HTTP header |
graph | no | application/rdf+xml | 200 OK | based on Content-Type HTTP header |
graph | no | - | 200 OK | default: RDF/XML |
The default response when dereferencing the resource URI is the resource content. Resource metadata can be found in the manifest.
When dereferencing the aggregated resource proxy, the client is redirected to the resource that the proxy is for.C: GET /ROs/ro1/foo/bar.txt HTTP/1.1 C: Host: example.com C: Accept: text/plain C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 200 OK S: Content-Type: text/plain S: Content-Length: ... S: S: Lorem ipsum
When retrieving resources that are RDF RO metadata, content negotiation is allowed.C: GET /ROs/ro1/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 303 See Other S: Location: http://example.com/external.txt S: Link: <http://example.com/ROs/ro1/>; rel="up"
- Specific RDF format can be asked using content negotiation, i.e. adding an
"Accept: text/turtle"
header to the request. - If the URI has no extension or has an extension that does not match the requested format, the server will return 302 Found redirecting the client to the format-specific resource. See below.
- The format-specific resource can be used by clients to access the resource directly in a specific format without content negotiation. Note the "original" query param that identifies the format-specific version of another resource.
Resource requested (example) | URI Extension | Accept HTTP header | Response code | Response Location HTTP header (example) | Response RDF format |
---|---|---|---|---|---|
graph.rdf | yes | application/rdf+xml | 200 OK | - | based on URI extension and Accept HTTP header |
graph.rdf | yes | - | 200 OK | - | based on URI extension |
graph.rdf | yes | text/turtle | 302 Found | graph.ttl?original=graph.rdf | based on Accept HTTP header |
graph | no | application/rdf+xml | 302 Found | graph.rdf?original=graph | based on Accept HTTP header |
graph | no | - | 302 Found | graph.rdf?original=graph | default: RDF/XML |
Removing has a slightly different meaning for internal and external resources:
- For internal resources, it means de-aggregating the resource, deleting its proxy from the manifest and deleting the resource itself.
- For external resources, it means de-aggregating the resource and deleting its proxy from the manifest.
For resources that have different RDF formats (i.e. RO metadata), the clients may use either resource URIs or the format-specific URIs.
Trying to remove resources that are under control of the RO service (such as aggregation resource maps) will result in 403 Forbidden.
The example below demonstrated de-aggregating an external resource.
The example below demonstrated de-aggregating an internal resource. If the internal resource has no content (i.e. only a proxy was created), there will be no redirection and the proxy will be deleted.C: DELETE /ROs/ro_id/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 204 No Content
C: DELETE /ROs/ro_id/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 307 Temporary Redirect S: Location: [http://example.com/ROs/ro_id/foo/bar.txt] C: DELETE /ROs/ro_id/.ro/foo/bar.txt HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 204 No Content
In order to annotate a resource, an annotation has to be created in the manifest, pointing to a set of annotated resources and an annotation body. The annotated resources must be resources already aggregated by the research object. The annotation body may an internal or external resource. In the first case, it will also have a proxy as all internal resources aggregated by the research object. The annotation body does not have to exist when annotating a resource.
Annotating resources involves 2 steps, though in some cases one of them can be omitted:
- Creating an annotation for a resource or resources.
- Aggregating an annotation body.
application/vnd.wf4ever.annotation.
The second step is recognized by aggregating a resource that is either referenced in an existing annotation or has a Link header ao:annotatesResource.
Resources are annotated in the following ways:
- External annotation bodies: only create an annotation, pointing to the external annotation body. Optionally, aggregate the external annotation body in the research object.
- Internal annotation bodies: only aggregate an annotation body and use the ao:annotatesResource Link header. The service will create the proxy and the annotation automatically and will return the URI of the annotation.
- Internal annotation bodies, the long way: create an annotation and then upload the annotation body, or the other way round. This is the only method to add an annotation as an annotation body (a rare case). It can also be used to convert an existing aggregated resource into an annotation body.
foo/bar.txt
using an external annotation body.
The example below demonstrates annotating the same resource using an internal annotation body that will be created asC: POST /ROs/ro1/ HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.annotation C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ro="http://purl.org/wf4ever/ro#" C: xmlns:ao="http://purl.org/ao/" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ro:AggregatedAnnotation> C: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> C: <ao:body rdf:resource="http://example.com/external.txt" /> C: </ro:AggregatedAnnotation> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://purl.org/ao/annotatesResource" S: Link: <http://example.com/external.txt>; rel="http://purl.org/ao/body" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:ao="http://purl.org/ao/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66"> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2012-12-11T12:06:53.551Z</dct:created> S: <dct:creator rdf:resource="http://test.myopenid.com"/> S: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> S: <ao:body rdf:resource="http://example.com/external.txt" /> S: </rdf:Description> S: </rdf:RDF>
"foo/ann.ttl".
Note that the proxy URI for the annotation body is not returned, even though it is created. In this example, the primary operation is POSTing the annotation body to the RO, which causes it to be aggregated, but the Link: header
causes the annotation stub to be created that adds this to the set of annotations for the RO.
C: POST http://example.com/ROs/ro_id/ HTTP/1.1 C: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://purl.org/ao/annotatesResource" C: Slug: foo/ann.ttl C: Content-Type: text/turtle C: C: <http://example.com/ROs/ro_id/foo/bar.txt> dcterm:description "How great!" . S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://purl.org/ao/annotatesResource" S: Link: <http://example.com/external.txt>; rel="http://purl.org/ao/body" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:ao="http://purl.org/ao/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="http://example.org/ROs/ro_id/"/> S: <ore:proxyFor rdf:resource="http://example.org/ROs/ro_id/foo/bar.txt" /> S: </rdf:Description> S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/foo/bar.txt"> S: <dct:creator rdf:resource="http://test2.myopenid.com"/> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2011-12-02T15:02:11Z</dct:created> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/AggregatedResource"/> S: </rdf:Description> S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66"> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2012-12-11T12:06:53.551Z</dct:created> S: <dct:creator rdf:resource="http://test.myopenid.com"/> S: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> S: <ao:body rdf:resource="http://example.com/external.txt" /> S: </rdf:Description> S: </rdf:RDF>
✅ Example in JavaThe next code shows how to do a request in Java:
The example below demonstrates adding an annotation body and then creating the annotation. Note that the use of the resource URI is recommended over using the proxy URI.PostMethod method = new PostMethod(roID); method.addRequestHeader("token", Constants.authToken); method.addRequestHeader("Content-Type", "application/rdf+xml"); method.addRequestHeader("Slug", Constants.slug); method.addRequestHeader("Link", "<"+roID+">; rel=\"http://purl.org/ao/annotatesResource\""); String body = "<?xml version=\"1.0\"?>"+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:prov=\"http://www.w3.org/ns/prov#\">"+ "<rdf:Description rdf:about=\""+roID+"\">"+ "<prov:wasDerivedFrom rdf:resource=\""+t2flowURI+"\" />"+ "</rdf:Description>"+ "</rdf:RDF>"; method.setRequestEntity(new StringRequestEntity(body)); client.executeMethod(method);
C: POST http://example.com/ROs/ro_id/ HTTP/1.1 C: Content-Type: text/turtle C: Slug: foo/ann.ttl C: C: <http://example.com/ROs/ro_id/foo/bar.txt> dcterm:description "How great!" . S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 S: Link: <http://example.com/ROs/ro_id/foo/ann.ttl>; rel="http://www.openarchives.org/ore/terms/proxyFor" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:ao="http://purl.org/ao/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.org/ROs/ro_id/.ro/proxies/d953d020-becc-11e1-afa7-0800200c9a66"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="http://example.org/ROs/ro_id/"/> S: <ore:proxyFor rdf:resource="http://example.org/ROs/ro_id/foo/bar.txt" /> S: </rdf:Description> S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/foo/bar.txt"> S: <dct:creator rdf:resource="http://test2.myopenid.com"/> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2011-12-02T15:02:11Z</dct:created> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/AggregatedResource"/> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#Resource"/> S: </rdf:Description> S: </rdf:RDF> C: POST http://example.com/ROs/ro_id/ HTTP/1.1 C: Content-Type: application/vnd.wf4ever.annotation C: C: <rdf:RDF C: xmlns:ro="http://purl.org/wf4ever/ro#" C: xmlns:ao="http://purl.org/ao/" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ro:AggregatedAnnotation> C: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> C: <ao:body rdf:resource="http://example.com/ROs/ro_id/foo/ann.ttl" /> C: </ro:AggregatedAnnotation> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://purl.org/ao/annotatesResource" S: Link: <http://example.com/ROs/ro_id/foo/ann.ttl>; rel="http://purl.org/ao/body" S: Content-Type: application/rdf+xml S: Content-Length: ... S: S: <rdf:RDF S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:ao="http://purl.org/ao/" S: xmlns:dct="http://purl.org/dc/terms/" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="http://example.com/ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66"> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2012-12-11T12:06:53.551Z</dct:created> S: <dct:creator rdf:resource="http://test.myopenid.com"/> S: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> S: <ao:body rdf:resource="http://example.com/external.txt" /> S: </rdf:Description> S: </rdf:RDF>
The example below demonstrates updating an existing annotation. Trying to create a new annotation in this way will result in 403 Forbidden.
C: PUT /ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.annotation C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ro="http://purl.org/wf4ever/ro#" C: xmlns:ao="http://purl.org/ao/" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ro:AggregatedAnnotation> C: <ao:annotatesResource rdf:resource="http://example.com/ROs/ro_id/foo/bar.txt" /> C: <ao:body rdf:resource="http://example.com/external.txt" /> C: </ro:AggregatedAnnotation> C: </rdf:RDF> S: HTTP/1.1 200 OK S: Link: <http://example.com/ROs/ro_id/foo/bar.txt>; rel="http://purl.org/ao/annotatesResource" S: Link: <http://example.com/external.txt>; rel="http://purl.org/ao/body"
When dereferencing an annotation, the client is redirected to the annotation body.
Note that since an annotation body is always an RDF graph, content negotiation is allowed. If you do content negotiation in the first request, you will be redirected to a format-specific resource.C: GET /ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 303 See Other S: Location: http://example.com/ROs/ro_id/foo/ann.ttl S: Link: <http://example.com/ROs/ro1/>; rel="up"
C: GET /ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 HTTP/1.1 C: Host: example.com C: Accept: application/rdf+xml C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 303 See Other S: Location: http://example.com/ROs/ro_id/foo/ann.rdf?original=ann.ttl S: Link: <http://example.com/ROs/ro1/>; rel="up"
Removing an annotation does not remove the annotation body, even if it is an internal resource. For this reason, note that the annotation URI must be used, not the annotation body URI.
C: DELETE /ROs/ro_id/.ro/annotations/4a00dc90-c02c-11e1-afa7-0800200c9a66 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 204 No Content C: GET /ROs/ro_id/foo/ann.ttl HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 200 OK S: Content-Type: text/turtle S: S: <http://example.com/ROs/ro_id/foo/bar.txt> dcterm:description "How great!" .
Creating a folder is like creating any RO resource, only with a special MIME type: application/vnd.wf4ever.folder.
When the folder is created, an RDF/XML graph must be supplied with initial content defined according to the RO model. The folder may aggregate no content initially, in which case an empty aggregation must be sent.
The RDF/XML graph may define ro:FolderEntries
for the aggregated resources. If they are not defined, then the service must create them with arbitrary ro:EntryNames (the names under which resources are visible in the ro:Folder
). The full RDF description of the folder is returned in response.
A folder will have its proxy created, as any RO resource.
The first folder created in the RO becomes the rootFolder of the RO. If it's deleted, then the next one that is created becomes the new root folder.
C: POST /ROs/ro1/ HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.folder C: Content-Length: ... C: Slug: myfolder/ C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ore="http://www.openarchives.org/ore/terms/" C: xmlns:ro="http://purl.org/wf4ever/ro#" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ro:Folder> C: <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> C: <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/anotherfolder/file2.txt" /> C: <ore:aggregates rdf:resource="http://example.org" /> C: </ro:Folder> C: <ro:FolderEntry> C: <ro:entryName>the main file.txt</ro:entryName> C: <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> C: </ro:FolderEntry> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: https://sandbox/rodl/ROs/ro1/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34 S: Content-Type: application/vnd.wf4ever.folder S: Link: <https://sandbox/rodl/ROs/ro1/myfolder/>; rel="http://www.openarchives.org/ore/terms/proxyFor" S: Link: <https://sandbox/rodl/ROs/ro1/myfolder/myfolder.rdf>; rel="http://www.openarchives.org/ore/terms/isDescribedBy" S: S: <rdf:RDF S: xmlns:ore="http://www.openarchives.org/ore/terms/" S: xmlns:ro="http://purl.org/wf4ever/ro#" S: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/.ro/proxies/9a3fdd90-becf-11e1-afa7-0800200c9a34"> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/Proxy"/> S: <ore:proxyIn rdf:resource="https://sandbox/rodl/ROs/ro1/"/> S: <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/" /> S: </rdf:Description> S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/myfolder/"> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#Folder"/> S: <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> S: <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/anotherfolder/file2.txt" /> S: <ore:aggregates rdf:resource="http://example.org" /> S: <dct:creator rdf:resource="http://test2.myopenid.com"/> S: <dct:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2011-12-02T15:02:11Z</dct:created> S: <rdf:type rdf:resource="http://www.openarchives.org/ore/terms/AggregatedResource"/> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#Resource"/> S: </rdf:Description> S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/myfolder/entries/1"> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#FolderEntry"/> S: <ro:entryName>the main file</ro:entryName> S: <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> S: <ore:proxyIn rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/" /> S: </rdf:Description> S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/myfolder/entries/2"> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#FolderEntry"/> S: <ro:entryName>file2.txt</ro:entryName> S: <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/anotherfolder/file2.txt" /> S: <ore:proxyIn rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/" /> S: </rdf:Description> S: <rdf:Description rdf:about="https://sandbox/rodl/ROs/ro1/myfolder/entries/3"> S: <rdf:type rdf:resource="http://purl.org/wf4ever/ro#FolderEntry"/> S: <ro:entryName>example_org</ro:entryName> S: <ore:proxyFor rdf:resource="http://example.org" /> S: <ore:proxyIn rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/" /> S: </rdf:Description> S: </rdf:RDF>
When dereferencing a folder, the service may redirect to the RDF file describing the ORE aggregation. The redirection may be based on content negotiation. The service may also return a ZIP file with the ORE aggregation in RDF/XML and some of the resources serialized (informally called "internal" resources).
A folder can be deleted like any other aggregated resource. All folder entries of this folder will be also deleted but the resources aggregated in the folder will be left intact.
If the folder aggregated another folder, it may happen that the latter becomes orphaned, i.e. aggregated only by the RO. This will lead to the folder being not reachable by traversing the folder structure from the root folder and clients should either delete such orphaned folder or show it as unassigned.
A resource can be added to a folder only if it is already aggregated by the RO. To do it, a new ro:FolderEntry must be created in the ro:Folder
. ro:Folder
is a specialization of ore:Proxy
and adding it is analogous to adding a resource proxy to the Research Object.
The ore:proxyFor
is mandatory. The ro:entryName
is optional, and server SHOULD generate it arbitrarily if missing.
C: POST /ROs/ro1/myfolder/ HTTP/1.1 C: Host: example.com C: Content-Type: application/vnd.wf4ever.folderentry C: Content-Length: ... C: Authorization: Bearer h480djs93hd8 C: C: <rdf:RDF C: xmlns:ore="http://www.openarchives.org/ore/terms/" C: xmlns:ro="http://purl.org/wf4ever/ro#" C: xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > C: <ro:FolderEntry> C: <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> C: <ro:entryName>file1.txt</ro:entryName> C: </ro:FolderEntry> C: </rdf:RDF> S: HTTP/1.1 201 Created S: Location: https://sandbox/rodl/ROs/ro1/.ro/myfolder/entries/4 S: Link: <https://sandbox/rodl/ROs/ro1/myfolder/file1.txt>; rel="http://www.openarchives.org/ore/terms/proxyFor"
Deleting a resource from a folder means to de-aggregate it from the folder and leave the resource intact, and is analogous to deleting a resource proxy from a Research Object.
C: DELETE /ROs/ro_id/.ro/myfolder/entries/4 HTTP/1.1 C: Host: example.com C: Authorization: Bearer h480djs93hd8 S: HTTP/1.1 204 No Content
⚠️ A missing link
As Graham pointed out below, we miss a link from the ROs collection (/ROs/) to individual ROs (/ROs/ro_id/). For simplicity, I'd suggest using ore:aggregates for that.
Full URI is http://purl.org/ro/service/ro/ros. It links the service (service description) with the collection of ROs.
Full URI is http://purl.org/ro/service/ro/zipCreate. It links the service (service description) resource to which a ZIP with files and folders can be POSTed to create a new RO.
Full URI is http://purl.org/ro/service/ro/zipUpload. It links the service (service description) resource to which a ZIP with a complete RO can be POSTed to store this RO.
This relation comes from the ?Research Object Vocabulary Specification v0.1 and is used to indicate that a resource is aggregated by the Research Object. Ore:aggregates links the RO with ro:Resources and with ro:AggregatedAnnotations. It does NOT link it with ore:Proxies and annotation bodies.
This relation comes from the ?Research Object Vocabulary Specification v0.1 and is used to indicate that a resource that is ore:aggregated by the RO is annotated by another resource, called the annotation body.
This relation comes from the ?Research Object Vocabulary Specification v0.1 and it links a resource that is an rdfs:Graph
(the annotation body) with an annotation. By combining the ro:annotatesAggregatedResource
and ao:body
, annotation bodies are linked with aggregated resources that they annotate.
The ORE relation links proxies and the resources they represent. It is used for ro:Resources
aggregated in ro:ResearchObjects
as well as for resources aggregated in ro:Folders
.
The RO SRS API uses four HTTP methods: GET, POST, PUT and DELETE.
GET is used to retrieve the research object and its resources. In case of the research object itself and its metadata, content negotiation is available to get a desired RDF format of the response. Also, in case of research objects, annotations, proxies and folders the client is redirected to the resource that is the representation of each resource.
POST is used to create new content: a new research object, an aggregated resource, an annotation, proxy or a new folder entry. When creating a new annotation or a proxy, it is possible to specify in the request a URI for a resource associated with it (annotation body and proxied resource, respectively), which can be added later if necessary.
PUT is used to update the content or specification of existing resources. In case the URI has been reserved by creating an annotation or a proxy, PUT can also be used for uploading the resource for the first time.
DELETE is used to delete a research object or any other resource.
The description below is based on ?Research Object Vocabulary Specification v0.1.
A research object aggregates resources and annotations. Each aggregated resource is associated with a proxy that identifies that resource in the context of that research object.
The RO API service description is an RDF file that contains URI templates for accessing services related to the RO AOI. The RDF syntax used may be content negotiated. In the absence of content negotiation, RDF/XML should be returned.
Example:
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . <http://sandbox.wf4ever-project.org/rodl/> <http://purl.org/ro/service/ro/ros> "http://sandbox.wf4ever-project.org/rodl/ROs/" ; <http://purl.org/ro/service/ro/zipCreate> "http://sandbox.wf4ever-project.org/rodl/ROs/zip/create/" ; <http://purl.org/ro/service/ro/zipUpload> "http://sandbox.wf4ever-project.org/rodl/ROs/zip/upload/" ; # The links below are not part of RO API. <http://purl.org/ro/service/notification/notifications> "http://sandbox.wf4ever-project.org/rodl/notifications/{?ro,from,to,source,limit}" ; <http://purl.org/ro/service/evolution/copy> "http://sandbox.wf4ever-project.org/rodl/evo/copy/" ; <http://purl.org/ro/service/evolution/finalize> "http://sandbox.wf4ever-project.org/rodl/evo/finalize/" ; <http://purl.org/ro/service/evolution/info> "http://sandbox.wf4ever-project.org/rodl/evo/info{?ro}" .
A Research Object can have 3 different formats, as described in RO dereferencing. These are:
- a ZIP file with all internal resources and metadata.
- an RDF file, i.e. its manifest.
- an HTML page.
A resource can be any file including even a proxy or an annotation. If the resource is an RDF graph that stores the RO metadata (i.e. the manifest or an annotation body), its content can be retrieved using content negotiation.
MIME media type: application/vnd.wf4ever.proxy @@TODO
registration
A application/vnd.wf4ever.proxy entity contains an RDF/XML expression that describes one or more ore:Proxy
resource. Other information present in the RDF may be ignored. In principle, any RDF data can be used to describe a proxy, but the application/vnd.wf4ever.proxy
is currently the only mechanism used for signaling that it is intended to be interpreted as a proxy description.
The ore:Proxy
resource type is part of the ORE aggregation structure, and as such is incorporated by reference in the structure of a Research Object. It is described by the ORE abstract model specification (http://www.openarchives.org/ore/1.0/datamodel).
Example:
<rdf:RDF xmlns:ore="http://www.openarchives.org/ore/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > <ore:Proxy> <ore:proxyFor rdf:resource="http://example.com/resource.uri" /> </ore:Proxy> </rdf:RDF>
MIME media type: application/vnd.wf4ever.annotation @@TODO
registration
A application/vnd.wf4ever.annotation
entity contains an RDF/XML expression that describes one or more ro:AggregatedAnnotation resource
. Other information present in the RDF may be ignored. In principle, any RDF data can be used to describe a annotation, but the application/vnd.wf4ever.annotation
is currently the only mechanism used for signaling that it is intended to be interpreted as an annotation description.
The annotation gets stored in the manifest as ro:AggregatedAnnotation
which is a specialization of the AO annotation ontology for the structure of a Research Object. ao:Annotation
is described by the AO model specification (http://code.google.com/p/annotation-ontology/wiki/UnderstandingAO).
Example:
<rdf:RDF xmlns:ro="http://purl.org/wf4ever/ro#" xmlns:ao="http://purl.org/ao/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > <ro:AggregatedAnnotation> <ao:annotatesResource rdf:resource="http://example.com/resource.uri" /> <ao:annotatesResource rdf:resource="http://example.com/resource2.uri" /> <ao:body rdf:resource="stiansComments.ttl" /> </ro:AggregatedAnnotation> </rdf:RDF>
MIME media type: application/vnd.wf4ever.folder
A application/vnd.wf4ever.folder
entity contains an RDF/XML expression that describes one or more ro:Folder
resources. Other information present in the RDF may be ignored. The folder description must contain an aggregation of resources. It may also contain ro:FolderEnties
for some of the aggregated resources for the purpose of specifying the name of the resource in the folder described.
Example:
<rdf:RDF xmlns:ore="http://www.openarchives.org/ore/terms/" xmlns:ro="http://purl.org/wf4ever/ro#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > <ro:Folder> <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> <ore:aggregates rdf:resource="https://sandbox/rodl/ROs/ro1/anotherfolder/file2.txt" /> <ore:aggregates rdf:resource="http://example.org" /> </ro:Folder> <ro:FolderEntry> <ro:entryName>the main file.txt</ro:entryName> <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> </ro:FolderEntry> </rdf:RDF>
MIME media type: application/vnd.wf4ever.folderentry
A application/vnd.wf4ever.folderentry
entity contains an RDF/XML expression that describes one or more ro:FolderEntry
resources. Other information present in the RDF may be ignored. The folder entry description must contain a ore:proxyFor
reference to an aggregated resources. It may contain a reference to the aggregation itself (ore:proxyIn
) and the name of the resource in the folder described (ro:entryName
).
Example:
<rdf:RDF xmlns:ore="http://www.openarchives.org/ore/terms/" xmlns:ro="http://purl.org/wf4ever/ro#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" > <ro:FolderEntry> <ore:proxyFor rdf:resource="https://sandbox/rodl/ROs/ro1/myfolder/file1.txt" /> <ro:entryName>file1.txt</ro:entryName> </ro:FolderEntry> </rdf:RDF>
Resources (stored by this service) may be cached provided that they are always validated.
Research objects may be cached as well but their validation depends on the representation:
- for RDF, it is equivalent to validating the manifest
- for a ZIP archive, it requires validating all archive content
- for HTML, the web server settings may be used
See also:
http://www.mnot.net/cache_docs/
This service stores data provided by users and allows to manipulate it, so access control is a crucial part of the API.
In order to authorize requests, OAuth 2 should be used. Bearer authorization schema is recommended since it is as simple as possible while providing the necessary security level if used with HTTPS.
Access control policy, i.e. mechanisms of deciding if the request can be performed based on the access token used, is out of scope of this document.
- OAuth: http://oauth.net
- OAuth: http://tools.ietf.org/html/rfc6749
- AtomPub:http://tools.ietf.org/html/rfc5023.
- http://linkeddata4.dia.fi.upm.es:8087/wiki/display/docs/RO+model
- http://linkeddata4.dia.fi.upm.es:8087/wiki/display/docs/Research+Object+Vocabulary+Specification
- http://linkeddata4.dia.fi.upm.es:8087/wiki/display/docs/Research+Object+model
- http://www.mnot.net/cache_docs/
- http://linkeddata4.dia.fi.upm.es:8087/wiki/display/docs/RO+dereferencing