The blob service allows developers to attach various files to avatars. This file could be pictures, manuals, plan, map, etc...
Blob are stored in OBOS, an Orange S3 compliant object storage service. Manipulating blobs is done though the Thing'in REST API.
The figure below illustrates the process of a blob registration. Registering a blob is done using a POST request with a mandatory file and optional description, a comma sepatarated list of tags, and/or a visibility field in formdata query parameters. We discuss the visibility field later in the document. The file and the optional description and tags are received by the API server which streams the file to object storage service. Then the API server sends to the Thingin backend server, the metadata of the blob. The backend server will store a blob document in the Thingin graph.
Hereafter an HTTP request to register a blob:
curl --location --request POST 'API_SERVER_URL/blobs' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN' \
--form 'file=@PATH_TO_FILE' \
--form 'description=a description' \
--form 'comma,separated,list,of,tags'
This request returns an HTTP 201 status code with ''Location'' header containing the Thingin REST URL to the blob resource in the plateform.
Example of location header in a successfull response upon registration of a blob:
location: API_SERVER_URL/blobs/17c723dd-48c1-4b87-a88d-b1a5b4d72707
Update follows the same process as registering a blob except that the file is also optional, the request is made using the PUT command on the blob URI. Here after an example of such query
curl --location --request PUT 'API_SERVER_URL/blobs/17c723dd-48c1-4b87-a88d-b1a5b4d72707' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN' \
--form 'file=@PATH_TO_UPDATED_FILE' \
--form 'description=a description' \
--form 'comma,separated,list,of,tags'
In order to remove or reinitialize the description or tags fields, send an empty string value (e.g. description='')
Developers can use an HTTP GET requests to retrieve the metadata of a blob.
Example of request to get a blob metadata
curl --location --request GET 'API_SERVER_URL/blobs/BLOB_UUID' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN’
Example of blob metadata:
{
"owner": "OWNER_UUID",
"filename": "FILENAME",
"content_type": "CONTENT_TYPE",
"description": "DESCRIPTION",
"mimetype": "MIMTYPE",
"uuid": "BLOB_UUID",
"url": "DOWNLOAD_URL_FOR_BLOB",
"content_length": 1024,
"hasAvatars": 0,
"visibility": 255,
"timestamp": 1604598845511
}
A blob file can be downloaded using its download URL that can be found in the blob metadata under the field url. The blob download URL can also be guessed from the blob UUID as it is in the following form
API_SERVER_URL/blobs/BLOB_UUID/download
The following figure illustrates the process to download a blob file from the object storage service given its download URL.
An HTTP POST request can be used to link some existing avatars and an existing blob. Note that only the owner of the blobs and the avatar can link them.
curl --location --request POST 'API_SERVER_URL/blobs/link' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
"blob_uuid": "BLOB_UUID",
"avatar_iris": [ "avatar_iri"],
"avatar_uuids": ["avatar_uuid"],
"ignore_conflicts": true
}'
The response to link query contains the list of avatar iris that have been ignored upon conflicts (i.e. they are already linked to that avatar).
Example of response to a link query where one avatar has been ignored:
{
"ignored": [
"avatar_iri"
]
}
The thingin backend server will add a hasBlobs
property containing the number of blobs linked to that avatar. The property is serialized in RDF with the data property
http://orange-labs.fr/fog/ont/iot.owl#hasBlobs
This property is read-only for clients. The backend maintains the state of that property.
An HTTP POST request should be sent to the server to unlink an avatar to a blob. Note that only the owner of the blobs and the avatar can unlink them.
Example of an unlink request
curl --location --request POST 'API_SERVER_URL/blobs/unlink' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '
{
"blob_uuid": "BLOB_UUID",
"avatar_iris": ["avatar_iri"],
"avatar_uuids": ["avatar_uuid"]
}'
Upon a successfull unlink request the api return an HTTP 204 status code. The backend is responsible to update the hasBlobs
property of avatar or remove it if it reaches the threshold 0.
Deleting a blob is done using an HTTP DELETE query with the uuid blob as query parameter. Note that only the owner of a blob can delete it.
Example a query to delete a blob
curl --location --request DELETE 'API_URL_SERVER/blobs/BLOB_UUID' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN’
The API return a HTTP 204 status code upon a successfull deletion of a blob. Upon the deletion of a blob, the Thingin backend server will delete all the links to that blob and update the hasBlobs property of avatars. The API server will be responsible to delete the blob in the object storage service. The figure below illustrate a blob deletion.
An HTTP GET request can used to retrieve the list of blobs attached to an avatar as follows:
curl --location --request GET 'API_SERVER_URL/avatars/AVATAR_UUID/blobs' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN'
Example of response on an avatars linked to 2 blobs
{
"status": true,
"data": {
"count": 2,
"size": 2,
"items": [
{
"owner": "OWNER_UUID",
"filename": "FILENAME",
"content_type": "CONTENT_TYPE",
"mimetype": "MIMETYPE",
"uuid": "BLOB_UUID",
"url": "BLOB_DOWNLOAD_URL",
"content_length": CONTENT_LENGTH,
"hasAvatars": 1,
"visibility": 255,
"timestamp": 1604394539856
},
{
"owner": "OWNER_UUID",
"filename": "FILENAME",
"content_type": "CONTENT_TYPE",
"mimetype": "MIMETYPE",
"uuid": "BLOB_UUID",
"url": "BLOB_DOWNLOAD_URL",
"content_length": CONTENT_LENGTH,
"hasAvatars": 10,
"visibility": 0,
"timestamp": 1604394539856
}
],
"page_size": 2,
"index": 2
},
"code": 200
}
The following HTTP GET request allows to retrieve the list of IRIs of avatar linked to a blob.
curl --location --request GET 'API_SERVER_URL/blobs/BLOB_UUID/avatars' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN’
Here after an example of response
{
"avatar_iris": [
"AVATAR_IRI_1",
"AVATAR_IRI_2"
]
}
The following request allows to retrieve the list of blobs registered by a user
curl --location --request GET 'API_SERVER_URL/users/USER_UUID/blobs' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer CLIENT_TOKEN'
Here after an example of response
{
"status": true,
"data": {
"count": 2,
"size": 2,
"items": [
{
"owner": "OWNER_UUID",
"filename": "FILENAME",
"content_type": "CONTENT_TYPE",
"mimetype": "MIMETYPE",
"uuid": "BLOB_UUID",
"url": "BLOB_DOWNLOAD_URL",
"content_length": CONTENT_LENGTH,
"hasAvatars": 10,
"visibility": 0,
"timestamp": 1604394539856
},
{
"owner": "OWNER_UUID",
"filename": "FILENAME",
"content_type": "CONTENT_TYPE",
"mimetype": "MIMETYPE",
"uuid": "BLOB_UUID",
"url": "BLOB_DOWNLOAD_URL",
"content_length": CONTENT_LENGTH,
"hasAvatars": 10,
"visibility": 0,
"timestamp": 1604394539856
}
],
"page_size": 2,
"index": 2
},
"code": 200
}
By default, when a user creates an blob, only him/her (the owner) can reach it (aka visibility=255). If he wants to share with anyone else, he must set the blob as visible (aka visibility=0).
A visible blob can be seen by external user (i.e. user from an other TiPod) if the conditions set by access control on the blob can be checked.
The access to blobs can be controlled using Thing in ACL. Use the resource name blob to refer to a blob in an acl as follows.
{
"desc": "Blob acl 1",
"owner": "user1",
"statements": [
{
"condition": {"$eq": [ "dummyRestrictedUserUUID", "$user.uuid"]},
"rules": [
{
"action": [
"Read", "Update", "Delete"
],
"effect": "Deny",
"resources": [
"blob"
]
}
]
},
{
"condition": {},
"rules" : [
{
"effect" : "Allow",
"action" : "Read",
"resources": "blob"
},
{
"effect" : "Deny",
"action": [
"Update", "Delete"
],
"resources": "blob"
}
]
}
]
}
Thing'in core model includes a "hasBlobs" label to count the number of blobs attached to an avatar. This label is also available in queries to help find avatars with a set number of blobs. Refer to Avatar search -> Datatype property -> Blobs section.
The current implementation has the following limitations: