Objects are the primary resource to actually hold the data you upload.
Before you can initialize any Objects you have to create a Collection to ensure consistent authorization for all
If you don't know how to create a Collection you should read the previous chapter about the Collection API basics.
Initialize Object
The first step is to initialize an Object.
This creates an Object in the AOS with a status of Initializing and marks it as Staging.
As long as an Object is in the staging area data can be uploaded to it.
Hash validation
If you provide a hash with the initializing of an Object it will be automatically validated by
the DataProxy after the data upload has been finished. This ensures that the upload was successful and complete.
Info
This request needs at least APPEND permissions on the Object's Collection or the Project under which the Collection is registered.
// Create tonic/ArunaAPI request to initialize an staging objectletinit_request=InitializeNewObjectRequest{object: Some(StageObject{filename: "aruna.png".to_string(),content_len: 123456,source: None,dataclass: DataClass::Privateasi32,labels: vec![KeyValue{key: "LabelKey".to_string(),value: "LabelValue".to_string(),}],hooks: vec![KeyValue{key: "HookKey".to_string(),value: "HookValue".to_string(),}],sub_path: "".to_string(),}),collection_id: "<collection-id>".to_string(),preferred_endpoint_id: "".to_string(),multipart: false,is_specification: false,hash: Some(Hash{alg: Hashalgorithm::Sha256asi32,hash: "5839942d4f1e706fee33d0837617163f9368274a72b2b7e89d3b0877f390fc33".to_string(),},};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.initialize_new_object(init_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
# Create tonic/ArunaAPI request to initialize an staging objectrequest=InitializeNewObjectRequest(object=StageObject(filename="aruna.png",content_len=123456,source=None,# Parameter can also be omitted if Nonedataclass=DataClass.Value("DATACLASS_PRIVATE"),labels=[KeyValue(key="LabelKey",value="LabelValue")],hooks=[KeyValue(key="HookKey",value="HookValue")],subPath="",# Parameter can also be omitted if empty),collection_id="<collection-id>",preferred_endpoint_id="",# Parameter can also be omitted if emptymultipart=False,is_specification=False,hash=Hash(alg=Hashalgorithm.Value("HASHALGORITHM_SHA256"),hash="5839942d4f1e706fee33d0837617163f9368274a72b2b7e89d3b0877f390fc33"))# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.InitializeNewObject(request=request)# Do something with the responseprint(f'{response}')
Upload data to an Staging Object
After initializing an Object you can request an upload url with the object id you received from the initialization.
Data then can be uploaded through the received url to the AOS data proxy.
If the data associated with the Object is greater than 5 Gigabytes you have to request a multipart upload and chunk your data in parts which are at most 5 Gigabytes in size.
You also have to request an upload url for each part individually.
S3 Presigned download URL
You can also generate presigned URLs on your own for the specific AOS DataPoxy you want to upload the Object data to.
Info
Requesting an upload URL needs at least APPEND permissions on the Object's Collection or the Project under which the Collection is registered.
Single part upload
Info
Single part upload automatically starts the finishing process of the respective Object once the upload has been finished to make it available.
1234567
# Native JSON request to request an upload url for single part upload
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/staging/{upload-id}/upload
# Native JSON request to upload single part data through the generated data proxy upload url
curl-XPUT-T<path-to-local-file><upload-url>
// Create tonic/ArunaAPI request to request an upload url for single part uploadletget_request=GetUploadUrlRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),upload_id: "<upload-id>".to_string(),multipart: false,part_number: 1,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_upload_url(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);letupload_url=response.url.unwrap().url;// Upload local file to the generated upload URLletpath=Path::new("/path/to/local/file");letfile=tokio::fs::File::open(path).await.unwrap();letclient=reqwest::Client::new();letstream=FramedRead::new(file,BytesCodec::new());letbody=Body::wrap_stream(stream);// Send the request to the upload urlletresponse=client.put(upload_url).body(body).send().await.unwrap();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 91011121314151617181920212223
# Create tonic/ArunaAPI request to request an upload url for single part uploadrequest=GetUploadURLRequest(object_id="<object-id>",upload_id="<upload-id>",collection_id="<collection-id>",multipart=False,part_number=1)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetUploadURL(request=request)# Do something with the responseprint(f'{response}')upload_url=response.url.url# Upload local file to the generated upload URLfile_path="/tmp/aruna.png"headers={'Content-type':'application/octet-stream'}upload_response=requests.put(upload_url,data=open(file_path,'rb'),headers=headers)# Do something with the responseprint(f'{upload_response}')
Multipart upload
Note
For each uploaded part of the multipart upload you will receive a so called ETag in the response header which has to be saved with the correlating part number for the Object finishing.
Numbers of upload parts start with 1, not 0.
Multipart uploads have to be finished manually as the DataProxy cannot know or guess how many parts will be uploaded in total.
Tip
Upload of parts from multipart upload can be uploaded parallel.
Warning
If the data is stored in an S3 endpoint individual parts of multipart upload have to be at least 5MiB in size (5242880 bytes) or the Object finishing will fail.
1234567
# Native JSON request to request an upload url for specific part of multipart upload
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/staging/{upload-id}/upload?multipart=true&partNumber=<part-number>
# Upload multipart data with native JSON requests through the generated data proxy upload urls
curl-XPUT-T<path-to-local-file><upload-url>
1 2 3 4 5 6 7 8 91011121314151617
// Create tonic/ArunaAPI to request an upload url for specific part of multipart uploadletget_request=GetUploadUrlRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),upload_id: "<upload-id>".to_string(),multipart: true,part_number: <part-number>asi32,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_upload_url(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 91011121314
# Create tonic/ArunaAPI request to request an upload url for specific part of multipart uploadrequest=GetUploadURLRequest(object_id="<object-id>",upload_id="<upload-id>",collection_id="<collection-id>",multipart=True,part_number=<part-number>)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetUploadURL(request=request)# Do something with the responseprint(f'{response}')
Multipart upload example
1 2 3 4 5 6 7 8 9101112131415161718
COLLECTION_ID=<collection-id>
OBJECT_ID=<staging-object-id>
UPLOAD_ID=<objects-upload-id>
# Loop over all file parts, request an upload url, upload the data and display ETag with its part numberforiin"Dummy_Archive.tar.gz.aa",1"Dummy_Archive.tar.gz.ab",2"Dummy_Archive.tar.gz.ac",3"Dummy_Archive.tar.gz.ad",4;doIFS=",";# Split input at commaset--$i;# Convert the "tuple" into the param args $1 $2 ...PART_FILE=$1PART_NUM=$2UPLOAD_URL=$(curl-s-H"$API_HEADER"\-H'Content-Type: application/json'\-XGET"https://<URL-to-AOS-instance-API-gateway>/v1/collection/${COLLECTION_ID}/object/${OBJECT_ID}/staging/${UPLOAD_ID}/upload?multipart=true&partNumber=${PART_NUM}"|jq-r'.url.url')ETAG=$(curl-XPUT-T${PART_FILE}-i"${UPLOAD_URL}"|grepetag)echo-e"\nPart: ${PART_NUM}, ETag: ${ETAG}\n"done
letmutfile=tokio::fs::File::open("/path/to/local/file").await.unwrap();// File handleletmutremaining_bytes: usize=file.metadata().await.unwrap().len()asusize;// File size in bytesletmutupload_part_counter: i64=0;letmutcompleted_parts: Vec<CompletedParts>=Vec::new();constUPLOAD_BUFFER_SIZE: usize=1024*1024*50;// 50MiB chunksletmutbuffer_size=UPLOAD_BUFFER_SIZE;// Variable buffer size for looploop{// Increment part numberupload_part_counter+=1;// Set buffer sizeifremaining_bytes<UPLOAD_BUFFER_SIZE{buffer_size=remaining_bytes;}// Fill buffer with bytes from fileletmutdata_buf=vec![0u8;buffer_size];letsuccessful_read=file.read_exact(&mutdata_buf).await;matchsuccessful_read{Ok(bytes)=>bytes,Err(_)=>file.read_to_end(&mutdata_buf).await.unwrap(),};// Create tonic/ArunaAPI request to request an upload url for multipart upload partletupload_url=object_client.get_upload_url(GetUploadUrlRequest{object_id: object_id.to_string(),upload_id: upload_id.to_string(),collection_id: collection_id.to_string(),multipart: true,part_number: upload_part_counterasi32,}).await.unwrap().into_inner().url.unwrap().url;// Upload buffer content to upload url and parse ETag from response headerletclient=reqwest::Client::new();letresponse=client.put(upload_url).body(data_buf).send().await.unwrap();letetag_raw=response.headers().get("ETag").unwrap().as_bytes();letetag=std::str::from_utf8(etag_raw).unwrap().to_string();// Collect ETag with corresponding part numbercompleted_parts.push(CompletedParts{etag: etag,part: upload_part_counter,});// Update the amount of remaining bytes for the next loopremaining_bytes-=buffer_size;ifremaining_bytes==0{break;}}// Retain the completed parts for usage in the FinishObjectRequestprintln!("{:#?}",completed_parts);
CHUNK_SIZE=1024*1024*50;# 50MiB chunksfile_path="/path/to/local/file"headers={'Content-type':'application/octet-stream'}# Arbitrary binary data uploadcompleted_parts=[]# Open file and return a streamwithopen(file_path,'rb')asfile_in:fori,data_chunkinenumerate(read_file_chunks(file_in,CHUNK_SIZE)):# (1)# Create tonic/ArunaAPI request to request an upload url for multipart upload partget_request=GetUploadURLRequest(object_id="<object-id>",upload_id="<upload-id>",collection_id="<collection-id>",multipart=True,part_number=i+1)# Send the request to the AOS instance gRPC gatewayget_response=client.object_client.GetUploadURL(request=get_request)# Extraxt download url from responseupload_url=get_response.url.url# Upload file content chunk to upload urlupload_response=requests.put(upload_url,data=data_chunk,headers=headers)# Parse ETag from response headeretag=str(upload_response.headers["etag"].replace("\"",""))# Collect ETag with corresponding part numbercompleted_parts.append(CompletedParts(etag=etag,part=i+1))# Retain the completed parts for usage in the FinishObjectRequestprint(f'{completed_parts}')
This function returns a generator with byte chunks of the specified file:
1 2 3 4 5 6 7 8 91011121314
defread_file_chunks(file_object,chunk_size=5242880):""" Generator to read set chunk sizes of a file object. Args: file_object: Open file handle chunk_size: Size of chunk to read (Default: 5MiB) Returns: Generator with file content bytes in chunk size """whileTrue:data=file_object.read(chunk_size)ifnotdata:breakyielddata
Finish Object
Finishing the Object transfers it from the staging area into production i.e. makes it available.
From this moment the Object is generally available for other functions other than Get Object.
On success the response will contain all the information on the finished Object.
Info
Object finishing is only needed in the following cases:
Object created/updated without upload
Object created/updated with multipart upload
Single part upload automatically starts the finishing process of the respective Object once the data upload has been finished.
Info
This request needs at least APPEND permissions on the Object's Collection or the Project under which the Collection is registered.
1 2 3 4 5 6 7 8 91011
# Native JSON request to finish a staging object without upload
curl-d' { "hash": {}, "noUpload": true, "completedParts": [], "autoUpdate": true }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XPATCHhttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/staging/{upload-id}/finish
// Create tonic/ArunaAPI request to finish a staging object without uploadletfinish_request=FinishObjectStagingRequest{object_id: "<object-id>".to_string(),upload_id: "<upload-id>".to_string(),collection_id: "<collection-id>".to_string(),hash: None,no_upload: true,completed_parts: vec![],auto_update: true,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.finish_object_staging(finish_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
// Create tonic/ArunaAPI request to finish a multipart upload staging objectletfinish_request=FinishObjectStagingRequest{object_id: "<object-id>".to_string(),upload_id: "<upload-id>".to_string(),collection_id: "<collection-id>".to_string(),hash: Some(Hash{alg: Hashalgorithm::Sha256asi32,hash: "5839942d4f1e706fee33d0837617163f9368274a72b2b7e89d3b0877f390fc33".to_string()}),no_upload: false,completed_parts: vec![CompletedParts{etag: "bfa7d257edcc9b962b7ab1a0a75b9808".to_string(),part: 1,},CompletedParts{etag: "af62c64eb6bcc9890d0aadf5720bf1ff".to_string(),part: 2,},],auto_update: true,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.finish_object_staging(finish_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213141516
# Create tonic/ArunaAPI request to finish a staging object without uploadrequest=FinishObjectStagingRequest(object_id="<object-id>",upload_id="<upload-id>",collection_id="<collection-id>",hash=None,# Parameter can also be omitted if Noneno_upload=True,completed_parts=[],# Parameter can also be omitted if emptyauto_update=True)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.FinishObjectStaging(request=request)# Do something with the responseprint(f'{response}')
# Create tonic/ArunaAPI request to finish a multipart upload staging objectfinish_request=FinishObjectStagingRequest(object_id="<object-id>",upload_id="<upload-id>",collection_id="<collection-id>",hash=Hash(alg=Hashalgorithm.Value("HASHALGORITHM_SHA256"),hash="<sha256-file-hashsum>"# E.g. 5839942d4f1e706fee33d0837617163f9368274a72b2b7e89d3b0877f390fc33),no_upload=False,completed_parts=[CompletedParts(etag="<upload-etag>",# E.g. bfa7d257edcc9b962b7ab1a0a75b9808part=1),CompletedParts(etag="<upload-etag>",# E.g. af62c64eb6bcc9890d0aadf5720bf1ffpart=2)],auto_update=True)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.FinishObjectStaging(request=request)# Do something with the responseprint(f'{response}')
Get Object
Information on finished or staging Objects can be fetched with their id and the id of their Collection.
The with_url (or withUrl) parameter controls if the response includes a download URL for the specific Object.
Info
This request needs at least READ permissions on the Object's Collection or the Project under which the Collection is registered.
1234
# Native JSON request to fetch information of an object by its unique id
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}
1234
# Native JSON request to fetch information of an object by its unique id including a download url
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}?withUrl=true
1 2 3 4 5 6 7 8 9101112131415
// Create tonic/ArunaAPI request to fetch information of an objectletget_request=GetObjectByIdRequest{collection_id: "<collection-id>".to_string(),object_id: "<object-id>".to_string(),with_url: false};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_object(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 9101112
# Create tonic/ArunaAPI request to to fetch information of an objectrequest=GetObjectByIDRequest(object_id="<object-id>",collection_id="<collection-id>",with_url=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjectByID(request=request)# Do something with the responseprint(f'{response}')
Get Objects
You can also fetch information on multiple Objects of a Collection with a single request.
The Objects returned will not include staging Objects.
By default, this request also returns only the first 20 Objects.
You can either increase the page size to receive more Objects per request and/or request the next Objects by pagination.
Additionally, you can include id or label filters to narrow the returned Objects.
The with_url (or withUrl) parameter controls if the response includes a download URL for each of the returned Objects.
Info
This request needs at least READ permissions on the Object's Collection or the Project under which the Collection is registered.
1234
# Native JSON request to fetch information of the first 20 unfiltered objects in a collection with download URLs
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/objects?withUrl=true
1234
# Native JSON request to fetch information of the first 250 unfiltered objects in a collection
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/objects?pageRequest.pageSize=250
1234
# Native JSON request to fetch information of the objects 21-40 (i.e. the next page) in a collection
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/objects?pageRequest.lastUuid=<id-of-last-received-object>
1234
# Native JSON request to fetch information of all objects in a collection matching one of the provided ids
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/objects?labelIdFilter.ids=<object-id-001>&labelIdFilter.ids=<object-id-002>
1 2 3 4 5 6 7 8 910111213141516
// Create tonic/ArunaAPI to fetch information of the first 20 unfiltered objects in a collection with download URLsletget_request=GetObjectsRequest{collection_id: "<collection-id>".to_string(),page_request: None,label_id_filter: None,with_url: true,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_objects(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213141516171819
// Create tonic/ArunaAPI to fetch information of the first 250 unfiltered objects in a collectionletget_request=GetObjectsRequest{collection_id: "<collection-id>".to_string(),page_request: Some(PageRequest{last_uuid: "".to_string(),page_size: 250,}),label_id_filter: None,with_url: false,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_objects(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213141516171819
// Create tonic/ArunaAPI to fetch information of the objects 21-40 (i.e. the next page) in a collectionletget_request=GetObjectsRequest{collection_id: "<collection-id>".to_string(),page_request: Some(PageRequest{last_uuid: "<id-of-last-received-object>".to_string(),page_size: 0,}),label_id_filter: None,with_url: false,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_objects(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213141516171819
// Create tonic/ArunaAPI to fetch information of all objects in a collection matching one of the provided idsletget_request=GetObjectsRequest{collection_id: "<collection-id>".to_string(),page_request: None,label_id_filter: Some(LabelOrIdQuery{labels: None,ids: vec!["<object-id-001>".to_string(),"<object-id-001>".to_string()],}),with_url: false,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_objects(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
// Create tonic/ArunaAPI to fetch multiple object of a collection filtered by label key(s)letget_request=GetObjectsRequest{collection_id: "<collection-id>".to_string(),page_request: None,label_id_filter: Some(LabelOrIdQuery{labels: Some(LabelFilter{labels: vec![KeyValue{key: "LabelKey".to_string(),value: "".to_string(),}],and_or_or: false,keys_only: true,}),ids: vec![],}),with_url: false,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_objects(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213
# Create tonic/ArunaAPI request to fetch information of the first 20 unfiltered objects in a collection with download URLsrequest=GetObjectsRequest(collection_id="<collection-id>",page_request=None,label_id_filter=None,with_url=True)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjects(request=request)# Do something with the responseprint(f'{response}')
1 2 3 4 5 6 7 8 910111213141516
# Create tonic/ArunaAPI request to fetch information of the first 250 unfiltered objects in a collectionrequest=GetObjectsRequest(collection_id="<collection-id>",page_request=PageRequest(last_uuid="",# Parameter can also be omitted if emptypage_size=250),label_id_filter=None,with_url=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjects(request=request)# Do something with the responseprint(f'{response}')
1 2 3 4 5 6 7 8 910111213141516
# Create tonic/ArunaAPI request to fetch information of the objects 21-40 (i.e. the next page) in a collectionrequest=GetObjectsRequest(collection_id="<collection-id>",page_request=PageRequest(last_uuid="<last-received-object-id>",page_size=0# Parameter can also be omitted if <= 0),label_id_filter=None,# Parameter can also be omitted if Nonewith_url=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjects(request=request)# Do something with the responseprint(f'{response}')
1 2 3 4 5 6 7 8 910111213141516
# Create tonic/ArunaAPI request to fetch information of all objects in a collection matching one of the provided idsrequest=GetObjectsRequest(collection_id="<collection-id>",page_request=None,# Parameter can also be omitted if Nonelabel_id_filter=LabelOrIDQuery(labels=None,# Parameter can also be omitted if Noneids=["<object-id-001>","<object-id-001>"]),with_url=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjects(request=request)# Do something with the responseprint(f'{response}')
1 2 3 4 5 6 7 8 910111213141516171819202122
# Create tonic/ArunaAPI request to fetch multiple objects of a collection filtered by label key(s)request=GetObjectsRequest(collection_id="<collection-id>",page_request=None,# Parameter can also be omitted if Nonelabel_id_filter=LabelOrIDQuery(labels=LabelFilter(labels=[KeyValue(key="isDummyObject",value=""# Parameter can also be omitted if empty or keys_only=True)],and_or_or=False,keys_only=True)),with_url=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetObjects(request=request)# Do something with the responseprint(f'{response}')
Download Object data
To download the data associated with an Object you have to request a download url.
This can be done with an individual request or directly while getting information on an Object.
S3 Presigned download URL
You can also generate presigned URLs on your own for the specific AOS DataPoxy you want to download the Object data from.
Info
This request needs at least READ permissions on the Object's Collection or the Project under which the Collection is registered.
1234567
# Native JSON request to fetch an Objects download url
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/download
# Download the data with the provided remote file name
curl-J-O-XGET<received-download-url>
1234567
# Native JSON request to fetch information of an Object including its download id
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}?withUrl=true# Download the data
curl-J-O-XGET<received-download-url>
// Send GET request to download urlletresponse=reqwest::get(download_url).await.unwrap();// Only proceed if response status is okifresponse.status()!=StatusCode::OK{panic!("Get request for file download failed.");}// Set default filename to "object.<object-id>"letmutfile_name=format!("object.{}",response.url().path_segments().unwrap().last().unwrap());// Try to extract filename from download url query parameterforeleminresponse.url().query_pairs(){ifelem.0=="filename"{file_name=elem.1.to_string();}}// Create local filelettarget_path=Path::new("/tmp").join();letmuttarget_file=File::create(target_path).unwrap();// Write response content to fileletmutcontent=Cursor::new(response.bytes().await.unwrap());copy(&mutcontent,&muttarget_file).unwrap();
# Create tonic/ArunaAPI request to fetch an Objects download urldownload_url_request=GetDownloadURLRequest(collection_id="<collection-id>",object_id="<object-id>")# Send the request to the AOS instance gRPC gatewaydownload_url_response=client.object_client.GetDownloadURL(request=download_url_request)# Extract download url from responsedownload_url=download_url_response.url.url# Try to extract filename from download url query parameterparsed_url=urlparse(download_url)local_filename=parse_qs(parsed_url.query)['filename'][0]iflocal_filenameisNone:local_filepath=os.path.join("/tmp",f'object.{object_id}')else:local_filepath=os.path.join("/tmp",local_filename)# Send GET request to download urlwithrequests.get(download_url,stream=True)asr:r.raise_for_status()//Writeresponsecontentinchunkstolocalfilewithopen(local_filepath,'wb')asf:forchunkinr.iter_content(chunk_size=8192):# Chunk size can be adaptedf.write(chunk)
Update Object
Objects can still be updated after finishing.
When an update is started, a staging Object with the status Initializing is created in the specific collection. Only
one staging object per object can exist at a time, so parallel updates of an object are prohibited. This limitation
is due to the S3 compatibility of the AOS, but also helps to maintain the consistency of the revision hierarchy.
Info
This request needs at least MODIFY permissions on the Object's Collection or the Project under which the Collection is registered.
Update which does not create a new revision
Just adding one or multiple labels to an Object does not create a new revision with this specific request.
1 2 3 4 5 6 7 8 910111213
# Native JSON request to add a label to an object
curl-d' { "labelsToAdd": [ { "key": "AnotherKey", "value": "AnotherValue" } ] }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XPATCHhttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/add_labels
1 2 3 4 5 6 7 8 9101112131415161718
// Create tonic/ArunaAPI request to add a label to an objectletadd_request=AddLabelsToObjectRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),labels_to_add: vec![KeyValue{key: "AnotherKey".to_string(),value: "AnotherValue".to_string(),}],};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.add_label_to_object(add_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 9101112131415
# Create tonic/ArunaAPI request to add a label to an objectrequest=AddLabelsToObjectRequest(object_id="<object-id>",collection_id="<collection-id>",labels_to_add=[KeyValue(key="AnotherKey",value="AnotherValue")])# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.AddLabelsToObject(request=request)# Do something with the responseprint(f'{response}')
Update which creates a new revision
Every other update creates a new revision of an Object and basically an updated clone of the Object.
A regular update of an Object returns the updated Object which is still in the staging area.
Comparable to the Object initialization process, the updated Object must be finished before it is generally available.
Warning
An object update overwrites all the fields in the request, even if they're empty.
If you want to retain a field you have to explicitly set the old value.
// Create tonic/ArunaAPI request to update an objects dataclassletupdate_request=UpdateObjectRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),object: Some(StageObject{filename: "aruna.png".to_string(),content_len: 123456,source: None,dataclass: DataClass::Publicasi32,labels: vec![KeyValue{key: "LabelKey".to_string(),value: "LabelValue".to_string(),}],hooks: vec![KeyValue{key: "HookKey".to_string(),value: "HookValue".to_string(),}],sub_path: "".to_string(),}),reupload: false,preferred_endpoint_id: "".to_string(),multi_part: false,is_specification: false,force: false,hash: None,// Not needed in case of no data upload};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.update_object(update_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);letUpdateObjectResponse{object_id,staging_id,collection_id}=response;// Create tonic/ArunaAPI request to finish the updated objectletfinish_request=FinishObjectStagingRequest{object_id: object_id,upload_id_staging_id,collection_id: collection_id,hash: None,no_upload: true,completed_parts: vec![],auto_update: true,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.finish_object_staging(finish_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
# Create tonic/ArunaAPI request to update an objects descriptionupdate_request=UpdateObjectRequest(object_id="<object-id>",collection_id="<collection-id>",object=StageObject(filename="aruna.png",content_len=123456,source=None,# Parameter can also be omitted if Nonedataclass=DataClass.Value("DATACLASS_PUBLIC"),labels=[KeyValue(key="LabelKey",value="LabelValue")],hooks=[KeyValue(key="HookKey",value="HookValue")],subPath="",# Parameter can also be omitted if empty),reupload=False,preferred_endpoint_id="",# Parameter can also be omitted if emptymulti_part=False,# Parameter can also be omitted if `reupload=False`is_specification=False,force=False,hash=None# Not needed in case of no data upload)# Send the request to the AOS instance gRPC gatewayupdate_response=client.object_client.UpdateObject(request=update_request)# Do something with the responseprint(f'{update_response}')# Create tonic/ArunaAPI request to finish a single part upload staging objectfinish_request=FinishObjectStagingRequest(object_id=update_response.object_id,upload_id=update_response.upload_id,collection_id=update_response.collection_id,hash=None,no_upload=True,completed_parts=[],auto_update=True)# Send the request to the AOS instance gRPC gatewayfinish_response=client.object_client.FinishObjectStaging(request=finish_request)# Do something with the responseprint(f'{finish_response}')
# Native JSON request to re-upload the modified data
curl-d' { "object": { "filename": "aruna.png", "contentLen": "1234567", "dataclass": "DATA_CLASS_PRIVATE", "labels": [ { "key": "LabelKey", "value": "LabelValue" } ], "hooks": [], "subPath": "" }, "reupload": true, "preferredEndpointId": "", "multiPart": false, "isSpecification": false, "force": false, "hash": {} }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/update
# Native JSON request to request an upload url for single part upload
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/{collection-id}/object/{object-id}/staging/{upload-id}/upload
# Native JSON request to upload single part data through the generated data proxy upload url
curl-XPUT-T<path-to-local-file><upload-url>
# Request to finish the updated object only needed in case of no upload or multipart upload
// Create tonic/ArunaAPI request to re-upload the modified dataletupdate_request=UpdateObjectRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),object: Some(StageObject{filename: "aruna.png".to_string(),content_len: 1234567,source: None,dataclass: DataClass::Privateasi32,labels: vec![KeyValue{key: "LabelKey".to_string(),value: "LabelValue".to_string(),}],hooks: vec![KeyValue{key: "HookKey".to_string(),value: "HookValue".to_string(),}],sub_path: "".to_string(),}),reupload: true,preferred_endpoint_id: "".to_string(),multi_part: false,is_specification: false,force: false,hash: None,// Will be provided at object finish in this example};// Send the request to the AOS instance gRPC gatewayletupdate_response=object_client.update_object(update_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",update_response);letUpdateObjectResponse{object_id,staging_id,collection_id}=update_response;// Create tonic/ArunaAPI request to request an upload url for single part uploadletget_request=GetUploadUrlRequest{object_id: object_id.clone(),collection_id: collection_id.clone(),upload_id: staging_id.clone(),multipart: false,part_number: 1,};// Send the request to the AOS instance gRPC gatewayletget_response=object_client.get_upload_url(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",get_response);letupload_url=get_response.url.unwrap().url;// Upload local file to the generated upload URLletpath=Path::new("/path/to/local/file");letfile=tokio::fs::File::open(path).await.unwrap();letclient=reqwest::Client::new();letstream=FramedRead::new(file,BytesCodec::new());letbody=Body::wrap_stream(stream);// Send the request to the upload urlletupload_response=client.put(upload_url).body(body).send().await.unwrap();// Do something with the responseprintln!("{:#?}",upload_response);// Request to finish a staging object only needed in case of no upload or multipart upload
# Create tonic/ArunaAPI request to re-upload the modified dataupdate_request=UpdateObjectRequest(object_id="<object-id>",collection_id="<collection-id>",object=StageObject(filename="aruna.png",content_len=1234567,source=None,# Parameter can also be omitted if Nonedataclass=DataClass.Value("DATACLASS_PRIVATE"),labels=[KeyValue(key="LabelKey",value="LabelValue")],hooks=[KeyValue(key="HookKey",value="HookValue")],subPath="",# Parameter can also be omitted if empty),reupload=True,preferred_endpoint_id="",# Parameter can also be omitted if emptymulti_part=False,# Parameter can also be omitted if `reupload=False`is_specification=False,force=False,hash=None# Will be provided at object finish in this example)# Send the request to the AOS instance gRPC gatewayupdate_response=client.object_client.UpdateObject(request=update_request)# Do something with the responseprint(f'{update_response}')# Create tonic/ArunaAPI request to request an upload url for single part uploadget_request=GetUploadURLRequest(object_id=update_response.object_id,upload_id=update_response.upload_id,collection_id=update_response.collection_id,multipart=False,part_number=1)# Send the request to the AOS instance gRPC gatewayget_response=client.object_client.GetUploadURL(request=get_request)# Do something with the responseprint(f'{get_response}')upload_url=get_response.url.url# Upload updated local file to the generated upload URLfile_path="/path/to/updated/local/file"headers={'Content-type':'application/octet-stream'}upload_response=requests.put(upload_url,data=open(file_path,'rb'),headers=headers)# Do something with the response (e.g. check status if was successful)print(f'{upload_response}')# Request to finish a staging object only needed in case of no upload or multipart upload
Create Object reference
References of an Object can be created in other Collections, which points to the same object in the database.
A reference can be either "read only", which means that the Object can not be modified from the specific Collection, or writeable, in which case the object in the target collection will be no different from the one in the source collection.
Warning
Updates on writeable references also update the Object in all other Collections the Object is referenced in.
Info
This request needs permission in the source and target Collection.
The required permissions on the source collection depend on whether the reference should be writeable or not:
true: At least MODIFY on the source Collection or the Project under which the Collection is registered
false: At least READ on the source Collection or the Project under which the Collection is registered
Additionally, the request needs MODIFY permissions on the target Collection or the Project under which the Collection is registered.
1 2 3 4 5 6 7 8 910
# Native JSON request to create an auto-updated read-only reference to keep track of an object
curl-d' { "writeable": false, "autoUpdate": true, "subPath": "" }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XPOSThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<source-collection-id>/object/<object-id>/reference/<destination-collection-id>
1 2 3 4 5 6 7 8 910
# Native JSON request to create a writeable reference in another collection for collaborative work
curl-d' { "writeable": true, "autoUpdate": true "subPath": "" }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XPOSThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<source-collection-id>/object/<object-id>/reference/<destination-collection-id>
1 2 3 4 5 6 7 8 9101112131415161718
// Create tonic/ArunaAPI request to create an auto-updated read-only reference to keep track of an objectletcreate_request=CreateObjectReferenceRequest{object_id: "<object-id>".to_string(),collection_id: "<source-collection-id>".to_string(),target_collection_id: "<target-collection-id>".to_string(),writeable: false,auto_update: true,sub_path: "".to_string(),};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.create_object_reference(create_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 9101112131415161718
// Create tonic/ArunaAPI request to create a writeable reference in another collection for collaborative workletcreate_request=CreateObjectReferenceRequest{object_id: "<object-id>".to_string(),collection_id: "<source-collection-id>".to_string(),target_collection_id: "<target-collection-id>".to_string(),writeable: true,auto_update: true,sub_path: "".to_string(),};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.create_object_reference(create_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 9101112131415
# Create tonic/ArunaAPI request to create an auto-updated read-only reference to keep track of an objectrequest=CreateObjectReferenceRequest(object_id="<object-id>",collection_id="<source-collection-id>",target_collection_id="<target-collection-id>",writeable=False,auto_update=True,subPath="",# Parameter can also be omitted if empty)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.CreateObjectReference(request=request)# Do something with the responseprint(f'{response}')
1 2 3 4 5 6 7 8 9101112131415
# Create tonic/ArunaAPI request to create a writeable reference in another collection for collaborative workrequest=CreateObjectReferenceRequest(object_id="<object-id>",collection_id="<source-collection-id>",target_collection_id="<target-collection-id>",writeable=True,auto_update=True,subPath="",# Parameter can also be omitted if empty)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.CreateObjectReference(request=request)# Do something with the responseprint(f'{response}')
Move Object to other Collection
Objects can be moved to another Collection without cloning.
E.g. this can be used to transfer Collection ownership of an Object.
This process consists of two steps:
Create writeable reference of the Object in another Collection
Delete reference of the Object in the source Collection
1 2 3 4 5 6 7 8 910111213141516171819
# Native JSON request to create a writeable reference in another collection
curl-d' { "writeable": true, "autoUpdate": true }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XPOSThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<source-collection-id>/object/<object-id>/reference/<target-collection-id>
# Native JSON request to delete writeable reference in source collection
curl-d' { "withRevisions": true, "force": false }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XDELETEhttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<source-collection-id>/object/<source-object-id>
// Create tonic/ArunaAPI request to create a writeable reference in another collectionletcreate_request=CreateObjectReferenceRequest{object_id: "<object-id>".to_string(),collection_id: "<source-collection-id>".to_string(),target_collection_id: "<target-collection-id>".to_string(),writeable: true,auto_update: true,};// Send the request to the AOS instance gRPC gatewayletcreate_response=object_client.create_object_reference(create_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",create_response);// Create tonic/ArunaAPI request to delete the object in the source collectionletdelete_request=DeleteObjectRequest{object_id: "<source-object-id>".to_string(),collection_id: "<source-collection-id>".to_string(),with_revisions: true,force: false,};// Send the request to the AOS instance gRPC gatewayletdelete_response=object_client.delete_object(delete_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",delete_response);
# Create tonic/ArunaAPI request to create a writeable reference in another collectioncreate_request=CreateObjectReferenceRequest(object_id="<object-id>",collection_id="<source-collection-id>",target_collection_id="<target-collection-id>",writeable=True,auto_update=True)# Send the request to the AOS instance gRPC gatewaycreate_response=client.object_client.CreateObjectReference(request=create_request)# Do something with the responseprint(f'{create_response}')# Create tonic/ArunaAPI request to delete the object in the source collectiondelete_request=DeleteObjectRequest(object_id="<source-object-id>",collection_id="<source-collection-id>",with_revisions=True,force=False)# Send the request to the AOS instance gRPC gatewaydelete_response=client.object_client.DeleteObject(request=delete_request)# Do something with the responseprint(f'Deleted: {delete_response}')
Get all Object references
You can fetch information of all references an Object has in different Collections.
Info
This request needs at least READ permissions on the Object's Collection or the Project under which the Collection is registered.
1234
# Native JSON request to fetch all references of an object
curl-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XGEThttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<collection-id>/object/<object-id>/references
1 2 3 4 5 6 7 8 9101112131415
// Create tonic/ArunaAPI request to fetch all references of an objectletget_request=GetReferencesRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),with_revisions: false};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.get_references(get_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 9101112
# Create tonic/ArunaAPI request torequest=GetReferencesRequest(object_id="<object-id>",collection_id="<collection-id>",with_revisions=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.GetReferences(request=request)# Do something with the responseprint(f'Deleted: {response}')
Delete Object
Objects can also be deleted again according to the FAIR guidelines.
This means that deleted objects or individually deleted revisions of objects do not simply disappear,
but a reference to the deleted resource remains.
Object deletion rulebook:
Deletion of the last reference of an Object deletes the complete Object.
Deleting a reference of an object while other references still exist only removes the specific reference.
If the last existing reference of an Object is writeable == false (i.e. read-only) the Object exists without possibility of further modification.
With force == true an Objects revision can be deleted without regards to other references.
With force == true and with_revisions == true an Object can be deleted completely without regards to other references.
Deletion of Objects from versioned Collections is prohibited without exceptions.
Info
The required permissions of this request depend on the value of the force parameter:
true: At least ADMIN on the source Collection or the Project under which the Collection is registered
false: At least APPEND on the source Collection or the Project under which the Collection is registered
All conditions can be overwritten with the use of force = true in the request but this should be avoided at all costs.
Therefore, only users with ADMIN permissions on the Project can use force = true in the request.
123456789
# Native JSON request to force delete an object with all its revisions
curl-d\'{ "withRevisions": "false", "force": "false" }'\-H'Authorization: Bearer <API_TOKEN>'\-H'Content-Type: application/json'\-XDELETEhttps://<URL-to-AOS-instance-API-gateway>/v1/collection/<collection-id>/object/<object-id>
1 2 3 4 5 6 7 8 910111213141516
// Create tonic/ArunaAPI request to delete an object with all its revisionsletdelete_request=DeleteObjectRequest{object_id: "<object-id>".to_string(),collection_id: "<collection-id>".to_string(),with_revisions: false,force: false,};// Send the request to the AOS instance gRPC gatewayletresponse=object_client.delete_object(delete_request).await.unwrap().into_inner();// Do something with the responseprintln!("{:#?}",response);
1 2 3 4 5 6 7 8 910111213
# Create tonic/ArunaAPI request to delete an object with all its revisionsrequest=DeleteObjectRequest(object_id="<source-object-id>",collection_id="<source-collection-id>",with_revisions=False,force=False)# Send the request to the AOS instance gRPC gatewayresponse=client.object_client.DeleteObject(request=request)# Do something with the responseprint(f'{response}')