Objective: Upload content from a local drive into a workspace.
The currently supported file extensions for uploading content to a Workspace are:
Type | Allowed extensions | Maximum size to upload (default) |
---|---|---|
Images | png, jpeg, gif, tiff, pdf, docx, pptx, xlsx, doc, ppt, xls | 50 Mb |
Documents | doc, docx, ppt, pptx, xls, xlsx, pdf, docMime, docxMime, pptMime, pptxMime, xlsMime, xlsxMime, pdfMime | 50 Mb |
Videos | mp4, mov, m4v, quicktime, mp4Mime, m4vMime, quicktimeMime | 150 Mb |
This page contains the implementation details for REST APIs v3 and for GraphQL APIs, and you can see the page with details for the v2 REST APIs.
Check out the previous guide on how to create a Canvas and add a Text Element to see how to create a Canvas and obtain this new Canvas Id. You will need the Canvas Id to position the content to upload inside this Canvas.
The upload of content into a workspace by APIs can be done in 2 ways:
- upload from local drive: REST implementation, and GraphQL implementation
- upload by URL: REST implementation and GraphQL implementation
Upload from local using REST APIs
Upload from local In REST APIs v3, the upload process from your local drive is divided into 3 steps:
- Create a zygote or placeholder for the file to upload. Here you will get the credentials to upload the file to a storage service, Amazon S3 in the example.
- Upload the image to Amazon S3.
- Link the zygote or placeholder to the uploaded image: it finishes the upload into the workspace.
STEP 1: Create a zygote or placeholder for the file to upload
This is the first step of three for the upload, for both REST and GraphQL APIs. You will need to create a zygote or placeholder, in the workspace, for the file to upload. This step will generate the Id of the object and the credentials for doing the actual upload of the file. See the details below.
STEP 1, implementation using REST API
REST API | /v3/workspaces/<workspaceId>/elements |
---|---|
Method | POST |
Comments | <CANVAS_ID> is the ID of the previously created canvas. This is the canvas where you want to add the uploaded content. The position of the content to upload will be in reference to the top-left corner of this Canvas. |
You need to specify the type of file you will upload. Specify it in the imageFormat
field, according to the specific type of image you are uploading.
You will also need to assign, the values for the filename
and title
fields, set as “myImageToUpload.jpg” in the following example:
cURL
# The default "width" and "height" value is 1000.
# If your image is smaller than 1000x1000 pixels, and "width" and "height" are not specified,
# your image will be vertically and horizontally centered within a 1000x1000 placeholder space.
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/workspaces/<SET_WORKSPACEID>/elements?relativeToOriginOf=<CANVAS_ID>' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": "Image",
"filename": "myImageToUpload.jpg",
"title": "myImageToUpload.jpg",
"imageFormat": "jpg",
"transform": { "x": 100, "y": 100, "scale": 1 }
}'
Node.js
const request = require('request-promise');
const fs = require('fs');
const token = '<SET_TOKEN>'
const portal = 'https://api.apps.us.bluescape.com';
const workspaceId = '<WORKSPACE_ID>';
const api_version = '/v3';
const filePath = '<PATH_TO_IMAGE>';
const request_headers = {
'Authorization': "Bearer " + token,
'Content-Type' : 'application/json'
};
const zygote_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/elements?relativeToOriginOf=<CANVAS_ID>';
// The default "width" and "height" value is 1000.
// If your image is smaller than 1000x1000 pixels, and "width" and "height" are not specified,
// your image will be vertically and horizontally centered within a 1000x1000 placeholder space.
const zygote_body = {
"type": "Image",
"filename": "myImageToUpload.jpg",
"title": "myImageToUpload.jpg",
"imageFormat": "jpg",
"transform": { "x": 100, "y": 100, "scale": 1 }
}
const zygote_options = {
headers: request_headers,
uri: zygote_endpoint,
method: 'POST',
json: zygote_body
}
const zygote_response = await request(zygote_options)
.catch(err => console.log(err))
console.log(zygote_response)
const zygote_data = zygote_response.data.content;
Python
import requests
import pprint
token = '<SET_TOKEN>'
portal = 'https://api.apps.us.bluescape.com'
workspaceId = '<WORKSPACE_ID>';
api_version = '/v3';
filePath = '<PATH_TO_IMAGE>';
request_headers = {
'Authorization': "Bearer " + token,
'Content-Type' : 'application/json'
}
if __name__ == "__main__":
zygote_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/elements?relativeToOriginOf=<CANVAS_ID>'
# The default "width" and "height" value is 1000.
# If your image is smaller than 1000x1000 pixels, and "width" and "height" are not specified,
# your image will be vertically and horizontally centered within a 1000x1000 placeholder space.
zygote_body = {
"type": "Image",
"filename": "myImageToUpload.jpg",
"title": "myImageToUpload.jpg",
"imageFormat": "jpg",
"transform": { "x": 100, "y": 100, "scale": 1 }
}
zygote_request = requests.post(zygote_endpoint, headers = request_headers, json = zygote_body)
zygote_response = zygote_request.json()
pprint.pprint(zygote_response)
zygote_data = zygote_response['data']['content']
The response body you will get should look like this:
{
"data": {
"content": {
"uploadId": "60aed93111bf08bf22a2572a",
"url": "https://s3.us-east-1.amazonaws.com/acceptance-new.public-assets.bluescape.com",
"fields": {
"key": "sessions/objects/GDUWtDvSZGtE868PBBk2/60aed93111bf08bf22a2572a.jpg",
"bucket": "acceptance-new.public-assets.bluescape.com",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "AKIZIVWWSYKG79KFMQJA/20210526/us-east-1/s3/aws4_request",
"X-Amz-Date": "20210526T232643Z",
"Policy": "eyJleHNpcmF0aW9uIjoiMjAyMS0wNS0yNlQyMzozMTo0MVoiLCJjb25kaXRpb25zIjpbWyJlcSIsIiRrZXkiLCJzZXNzaW9ucy9vYmplY3RzL0dEVVd0RHZTWkd0Nzg2OFBCQmsyLzYwYWVkOTMxMTdiZjA4YmYyMmEyNTcyYS5qcGciXSxbImNvbnRlbnQtbGVuZ3RoLXJhbmdlIiwwLDUyNDI4ODAwXSx7ImJ1Y2tldCI6ImFjY2VwdGFuY2Utbmv3LnB1YmxpYy1hc3NldHMuYmx1ZXNjYXBlLmNvbSJ9LHsiWC1BbXotQWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsiWC1BbXotQ3JlZGVudGlhbCI6IkFLSUFJVldXU1lLRzdES0ZNUUpBLzIwMjEwNTI2L3VzLWVhc3QtMS9zMy9hd3M0X3JlcXVlc3QifSx7IlgtQW16LURhdGUiOiIyMDIxMDUyNlQyMzI2NDFaIn1dfQ==",
"X-Amz-Signature": "fd521d7b3416a12a9997a2e1a10408f7P8427d9d0ae01A53e65a926f0f07a56d"
}
},
"image": {
"id": "60aed93111bf08bf22a2572a",
"zIndex": 1183,
"transform": {
"x": 300,
"y": 100,
"scaleX": 1,
"scaleY": 1
},
"traits": {
"http://bluescape.dev/zygote/v1/ingestionState": {
"http://bluescape.dev/zygote/v1/ingestionState/timestamp": 1622071601170,
"http://bluescape.dev/zygote/v1/ingestionState/stage": "transferring"
}
},
"pinned": false,
"comments": [],
"width": 1000,
"height": 1000,
"title": "myImageToUpload.jpg",
"filename": "myImageToUpload.jpg",
"ingestionState": "transferring",
"type": "Image",
"asset": {
"imageFormat": "jpeg"
}
}
}
}
At this moment, you will see a placeholder element in the workspace, in the position you specified, displaying a “transferring” message (as shown in the traits in the response body).
From the response body, you will need to use the following fields for the next step:
Field | Description |
---|---|
data/content/url | Destination URL to where the file will be uploaded. |
data/image/id | This is the Id of the cygote/placeholder created for the file to upload. It is the final Id of the uploaded file. |
data/content/fields | These fields are the ones you will need to authenticate with S3 (or the repository you are using) and to upload the file. |
STEP 1, implementation using GraphQL API
For this first step, in GraphQL you can use the following mutations: createDocument
, createImage
, createVideo
.
In these mutations you will need to use the filename
field to specify that it is an upload from your local drive, and provide the fullpath to the file to upload.
In the example below, see an example of how to create the zygote for an image, using the createImage
mutation, providing a "testimage.jpeg"
placeholder for the title
and filename
fields:
cURL
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/graphql' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"#create Image from disk\n#imageFormat: jpeg, jpg, gif, png, tiff, tif, image/jpeg, image/gif, image/png, image/tiff\nmutation createImageFromDisk($ws: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $filename:String! $scale:Float) {\n createImage(\n workspaceId: $ws\n input: {\n title:$title\n imageFormat: $imageFormat\n filename:$filename\n transform: {\n x: $x\n y: $y\n scale:$scale\n }\n }) \n #return values after creation: \n {\n content{ uploadId url fields}\n preview{uploadId url fields}\n image{id width height ingestionState}\n }\n}","variables":{"ws":"<WORKSPACE_ID>","title":"testimage.jpeg","filename":"testimage.jpeg","imageFormat":"jpeg","previewFormat":"jpeg","x":0,"y":0,"scale":1}}'
Node.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.apps.us.bluescape.com/v3/graphql',
'headers': {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: `#create Image from disk
#imageFormat: jpeg, jpg, gif, png, tiff, tif, image/jpeg, image/gif, image/png, image/tiff
mutation createImageFromDisk($ws: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $filename:String! $scale:Float) {
createImage(
workspaceId: $ws
input: {
title:$title
imageFormat: $imageFormat
filename:$filename
transform: {
x: $x
y: $y
scale:$scale
}
})
#return values after creation:
{
content{ uploadId url fields}
preview{uploadId url fields}
image{id width height ingestionState}
}
}`,
variables: {"ws":"<WORKSPACE_ID>","title":"testimage.jpeg","filename":"testimage.jpeg","imageFormat":"jpeg","previewFormat":"jpeg","x":0,"y":0,"scale":1}
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Python
import requests
url = "https://api.apps.us.bluescape.com/v3/graphql"
payload="{\"query\":\"#create Image from disk\\n#imageFormat: jpeg, jpg, gif, png, tiff, tif, image/jpeg, image/gif, image/png, image/tiff\\nmutation createImageFromDisk($ws: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $filename:String! $scale:Float) {\\n createImage(\\n workspaceId: $ws\\n input: {\\n title:$title\\n imageFormat: $imageFormat\\n filename:$filename\\n transform: {\\n x: $x\\n y: $y\\n scale:$scale\\n }\\n }) \\n #return values after creation: \\n {\\n content{ uploadId url fields}\\n preview{uploadId url fields}\\n image{id width height ingestionState}\\n }\\n}\",\"variables\":{\"ws\":\"<WORKSPACE_ID>\",\"title\":\"testimage.jpeg\",\"filename\":\"testimage.jpeg\",\"imageFormat\":\"jpeg\",\"previewFormat\":\"jpeg\",\"x\":0,\"y\":0,\"scale\":1}}"
headers = {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
STEP 2: Upload the file to S3
In this step you will use the S3 credentials, generated in the previous step, to upload the file into S3.
This step is the same for both REST and GraphQL APIs. The main difference will be how you provide the "fields"
values to upload the file to S3.
Please note that you will run an API call directly to S3 (or the repository you are using), and the credentials for authentication and authorization for the upload are the ones provided in the previous step, in the data/content/fields
block.
This is the command to run the upload of the file:
cURL
curl --location --request POST '<SET-data/content/url>' \
--form 'key="<SET-data/content/field/key>"' \
--form 'bucket="<SET-data/content/field/bucket>"' \
--form 'X-Amz-Algorithm="<SET-data/content/field/X-Amz-Algorithm>"' \
--form 'X-Amz-Credential="<SET-data/content/field/X-Amz-Credential>"' \
--form 'X-Amz-Date="<SET-data/content/field/X-Amz-Date>"' \
--form 'Policy="<SET-data/content/field/Policy>"' \
--form 'X-Amz-Signature="<SET-data/content/field/X-Amz-Signature>"' \
--form 'file=@"<SET_FULL_PATH_TO_LOCAL_FILE"'
Node.js
const uploadToBucket = async (upload_data, file) => {
const uri = upload_data.url;
console.log(`Uploading to bucket with url: ${uri}`);
const formData = {
key: upload_data.fields.key,
bucket: upload_data.fields.bucket,
'X-Amz-Algorithm': upload_data.fields['X-Amz-Algorithm'],
'X-Amz-Credential': upload_data.fields['X-Amz-Credential'],
'X-Amz-Date': upload_data.fields['X-Amz-Date'],
Policy: upload_data.fields.Policy,
'X-Amz-Signature': upload_data.fields['X-Amz-Signature'],
file: {
value: fs.createReadStream(filePath),
options: {
filename: file.filename,
contentType: file.type + '/' + file.imageFormat
},
},
};
const options = {
uri,
method: 'POST',
formData,
resolveWithFullResponse: true
};
return await request(options)
};
const s3upload_response = await uploadToBucket(zygote_data, zygote_body)
.catch(err => console.log(err))
console.log(s3upload_response.statusCode)
Python
print('Updateing to bucket with url: ' + zygote_data['url'])
formData = {
'key': zygote_data['fields']['key'],
'bucket': zygote_data['fields']['bucket'],
'X-Amz-Algorithm': zygote_data['fields']['X-Amz-Algorithm'],
'X-Amz-Credential': zygote_data['fields']['X-Amz-Credential'],
'X-Amz-Date': zygote_data['fields']['X-Amz-Date'],
'Policy': zygote_data['fields']['Policy'],
'X-Amz-Signature': zygote_data['fields']['X-Amz-Signature'],
}
files = {'file': open(filePath, 'rb')}
s3upload_response = requests.post(zygote_data['url'], data=formData, files=files)
pprint.pprint(s3upload_response.status_code)
This is how the command will look when using the data from Step 1:
curl --location --request POST 'https://s3.us-east-1.amazonaws.com/acceptance-new.public-assets.bluescape.com' \
--form 'key="sessions/objects/GDUWtDvSZGtE868PBBk2/60aed93111bf08bf22a2572a.jpg"' \
--form 'bucket="acceptance-new.public-assets.bluescape.com"' \
--form 'X-Amz-Algorithm="AWS4-HMAC-SHA256"' \
--form 'X-Amz-Credential="AKIZIVWWSYKG79KFMQJA/20210526/us-east-1/s3/aws4_request"' \
--form 'X-Amz-Date="20210526T232643Z"' \
--form 'Policy="eyJleHNpcmF0aW9uIjoiMjAyMS0wNS0yNlQyMzozMTo0MVoiLCJjb25kaXRpb25zIjpbWyJlcSIsIiRrZXkiLCJzZXNzaW9ucy9vYmplY3RzL0dEVVd0RHZTWkd0Nzg2OFBCQmsyLzYwYWVkOTMxMTdiZjA4YmYyMmEyNTcyYS5qcGciXSxbImNvbnRlbnQtbGVuZ3RoLXJhbmdlIiwwLDUyNDI4ODAwXSx7ImJ1Y2tldCI6ImFjY2VwdGFuY2Utbmv3LnB1YmxpYy1hc3NldHMuYmx1ZXNjYXBlLmNvbSJ9LHsiWC1BbXotQWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsiWC1BbXotQ3JlZGVudGlhbCI6IkFLSUFJVldXU1lLRzdES0ZNUUpBLzIwMjEwNTI2L3VzLWVhc3QtMS9zMy9hd3M0X3JlcXVlc3QifSx7IlgtQW16LURhdGUiOiIyMDIxMDUyNlQyMzI2NDFaIn1dfQ=="' \
--form 'X-Amz-Signature="fd521d7b3416a12a9997a2e1a10408f7P8427d9d0ae01A53e65a926f0f07a56d"' \
--form 'file=@"/Users/pj/temp/docs/araucaria.jpg"'
IMPORTANT:
- If the upload process is successful, you will get a return code 204, then proceed to the last step of the upload.
- If you get an error on this step, you will need to specify the error code and the error message to the next final step. See more details on the next final step instructions.
STEP 3: Link the zygote or placeholder to the uploaded file
The last step is to link the zygote or placeholder to the file we uploaded in the previous step. For this step we will need the id from data/content/uploadId
generated in the response body in step 1.
In case something went wrong on the previous step and the asset was not uploaded successfully (maybe the asset was too big, over the size limit), then you will need to send the error in this step. Otherwise, the zygote will be in permanent “Processing” status until it times out. When you send the error message, the zygote will display an error message and a Cancel button to let you delete the zygote created for the failed upload operation.
Note that the error code and the error message can be customized, they do not need to follow a particular format and will not be verified by the API.
The image below shows how the zygote will show an error when the asset is too big (a video in this case) and the option to cancel the upload, that will delete the zygote:
STEP 3, implementation using REST API
API | /v3/workspaces/<workspaceId>/assets/uploads/ |
---|---|
Method | PUT |
Comments | is the element Id created in the first step of the upload. |
Examples for when the upload on step 2 was successful:
cURL
curl --location --request PUT 'https://api.apps.us.bluescape.com/v3/workspaces/<workspaceId>/assets/uploads/<uploadId>' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{}'
Node.js
const request = require('request-promise');
const upload_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/assets/uploads/' + zygote_response.data.content.uploadId
const upload_options = {
headers: request_headers,
uri: upload_endpoint,
method: 'PUT',
json: {},
resolveWithFullResponse: true
}
const upload_response = await request(upload_options)
.catch(err => console.log(err))
console.log(upload_response.statusCode)
Python
import requests
upload_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/assets/uploads/' + zygote_data['uploadId']
upload_response = requests.put(upload_endpoint, headers= request_headers, json={})
pprint.pprint(upload_response.status_code)
Examples for reporting errors on step 2, to show an error message in the zygote:
cURL
# Report error on the upload operation, to make the zygote to display an error message
curl --location --request PUT 'https://api.apps.us.bluescape.com/v3/workspaces/<workspaceId>/assets/uploads/<uploadId>' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{ "errorCode" : "<ERROR-CODE-FROM-STEP-2>", "errorMessage" : "<ERROR-MESSAGE-FROM-STEP-2>"}'
Node.js
const request = require('request-promise');
// Report error on the upload operation, to make the zygote to display an error message
const upload_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/assets/uploads/' + zygote_response.data.content.uploadId
const upload_options = {
headers: request_headers,
uri: upload_endpoint,
method: 'PUT',
json: {
"errorCode" : "<ERROR-CODE-FROM-STEP-2>",
"errorMessage" : "<ERROR-MESSAGE-FROM-STEP-2>"
},
resolveWithFullResponse: true
}
const upload_response = await request(upload_options)
.catch(err => console.log(err))
console.log(upload_response.statusCode)
Python
import requests
# Report error on the upload operation, to make the zygote to display an error message
upload_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/assets/uploads/' + zygote_data['uploadId']
upload_response = requests.put(upload_endpoint, headers= request_headers, json={ "errorCode" : "<ERROR-CODE-FROM-STEP-2>", "errorMessage" : "<ERROR-MESSAGE-FROM-STEP-2>" })
pprint.pprint(upload_response.status_code)
STEP 3, implementation using GraphQL API
Run the "processAsset"
GraphQL mutation to finish the upload process:
mutation linkUploadToZygote($workspaceId: String! $uploadID: String!) {
processAsset( workspaceId:$workspaceId id:$uploadID input:{})
}
and provide these variables:
{
"workspaceId": "<WORKSPACE_ID>",
"uploadID": "<uploadId>"
}
Here are examples of the implementation of the mutation when the upload of step 2 was successful:
cURL
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/graphql' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"\nmutation myProcessAsset($ws: String! $uploadID: String!) {\n processAsset( workspaceId:$ws id:$uploadID input:{\n })\n}","variables":{"ws":"<WORKSPACE_ID>","uploadID":"<uploadId>"}}'
Node.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.apps.us.bluescape.com/v3/graphql',
'headers': {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: `mutation myProcessAsset($ws: String! $uploadID: String!) {
processAsset( workspaceId:$ws id:$uploadID input:{
})
}`,
variables: {"ws":"<WORKSPACE_ID>","uploadID":"<uploadId>"}
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Python
import requests
url = "https://api.apps.us.bluescape.com/v3/graphql"
payload="{\"query\":\"\\nmutation myProcessAsset($ws: String! $uploadID: String!) {\\n processAsset( workspaceId:$ws id:$uploadID input:{\\n })\\n}\",\"variables\":{\"ws\":\"<WORKSPACE_ID>\",\"uploadID\":\"<uploadId>\"}}"
headers = {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
Here are examples of the mutation for reporting errors on step 2, to show an error message in the zygote:
cURL
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/graphql' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"\nmutation myProcessAsset($ws: String! $uploadID: String!) {\n processAsset( workspaceId:$ws id:$uploadID input:{\n errorCode: "<ERROR-CODE-FROM-STEP-2>" \n errorMessage: "<ERROR-MESSAGE-FROM-STEP-2>" })\n}","variables":{"ws":"<WORKSPACE_ID>","uploadID":"<uploadId>"}}'
Node.js
var request = require('request');
var options = {
'method': 'POST',
'url': 'https://api.apps.us.bluescape.com/v3/graphql',
'headers': {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: `mutation myProcessAsset($ws: String! $uploadID: String!) {
processAsset( workspaceId:$ws id:$uploadID input:{
errorCode: "<ERROR-CODE-FROM-STEP-2>"
errorMessage: "<ERROR-MESSAGE-FROM-STEP-2>"
})
}`,
variables: {"ws":"<WORKSPACE_ID>","uploadID":"<uploadId>"}
})
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Python
import requests
url = "https://api.apps.us.bluescape.com/v3/graphql"
payload="{\"query\":\"\\nmutation myProcessAsset($ws: String! $uploadID: String!) {\\n processAsset( workspaceId:$ws id:$uploadID input:{\\n errorCode: \"<ERROR-CODE-FROM-STEP-2>\" errorMessage: \"<ERROR-MESSAGE-FROM-STEP-2>\" })\\n}\",\"variables\":{\"ws\":\"<WORKSPACE_ID>\",\"uploadID\":\"<uploadId>\"}}"
headers = {
'Authorization': 'Bearer <SET_TOKEN>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
Upload by URL using REST APIs
An alternative method to upload content into a workspace is to upload by URL. You can use the URL pointing to a resource to upload it into a workspace.
When should we use this “upload by URL” approach? When you integrate with external services that host images, videos and/or documents, and you want to access them (to view or download them),most of the time you are provided with a URL to those assets, not the actual binary object. Then, you can use that URL to access those assets to upload them directly into a workspace.
API | /v3/workspaces/<workspaceId>/elements |
---|---|
Method | POST |
Comments |
See the example below to learn how to upload an image by URL.
cURL
# If you do not define height and width,
# the image will be centered in an squared area defined by whatever value is higher: width or height.
# This may lead to think that the image is wrongly positioned, not in the (x,y) position you specified.
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/workspaces/<SET_WORKSPACEID>/elements?relativeToOriginOf=<CANVAS_ID>' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": "Image",
"transform": {
"x": 50,
"y": 50
},
"sourceUrl": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG",
"imageFormat": "jpg",
"title": "Yosemite"
}'
Node.js
const request = require('request-promise');
const token = '<SET_TOKEN>'
const portal = 'https://api.apps.us.bluescape.com';
const workspaceId = '<WORKSPACE_ID>';
const api_version = '/v3';
const request_headers = {
'Authorization': "Bearer " + token,
'Content-Type' : 'application/json'
};
async function main() {
const zygote_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/elements?relativeToOriginOf=<CANVAS_ID>';
const zygote_body = {
"type": "Image",
"title": "Yosemite",
"imageFormat": "jpg",
"transform": { "x": 50, "y": 50, "scale": 1 },
"sourceUrl": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG"
}
const zygote_options = {
headers: request_headers,
uri: zygote_endpoint,
method: 'POST',
json: zygote_body
}
const zygote_response = await request(zygote_options)
.catch(err => console.log(err))
answer = JSON.stringify(zygote_response);
console.log(answer);
}
main();
Python
import requests
import pprint
token = '<SET_TOKEN>'
portal = 'https://api.apps.us.bluescape.com';
workspaceId = '<WORKSPACE_ID>';
api_version = '/v3';
request_headers = {
'Authorization': "Bearer " + token,
'Content-Type' : 'application/json'
}
if __name__ == "__main__":
zygote_endpoint = portal + api_version + '/workspaces/' + workspaceId + '/elements?relativeToOriginOf=<CANVAS_ID>'
zygote_body = {
"type": "Image",
"title": "Yosemite view",
"imageFormat": "jpg",
"transform": { "x": 50, "y": 50, "scale": 1 },
"sourceUrl": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG"
}
zygote_request = requests.post(zygote_endpoint, headers = request_headers, json = zygote_body)
zygote_response = zygote_request.json()
pprint.pprint(zygote_response)
In the REST APIs, while the image is still uploading, the status is visible in the traits of the elements, as “transfering” in the response body. For example:
{
"data": {
"image": {
"id": "<IMAGE_ID>",
...
"traits": {
"http://bluescape.dev/zygote/v1/ingestionState": {
"http://bluescape.dev/zygote/v1/ingestionState/timestamp": 1633481223994,
"http://bluescape.dev/zygote/v1/ingestionState/stage": "transferring"
}
}
...
}
}
}
Once the upload is completed, the traits will be empty, which means that the image upload is complete and you can access it in the workspace.
To upload video you will use the same API, but slightly different payload. The main changes are the value in type
and use a videoFormat
field instead of imageFormat
. The example below is set to upload a .mov video:
curl --location --request POST 'https://api.apps.us.bluescape.com/v3/workspaces/<SET_WORKSPACEID>/elements?relativeToOriginOf=<CANVAS_ID>' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": "Video",
"transform": {
"x": 12000,
"y": 200
},
"sourceUrl": "<ADD_URL_TO_MOV_VIDEO>",
"videoFormat": "mov"
}'
Upload by URL using GraphQL APIs
You can use the URL pointing to a resource to upload it into a workspace.
When should we use this “upload by URL” approach? When you integrate with external services that host images, videos and/or documents, and you want to access them (to view or download them),most of the time you are provided with a URL to those assets, not the actual binary object. Then, you can use that URL to access those assets to upload them directly into a workspace.
Note that <CANVAS_ID> is the ID of the preciously created canvas. This is the canvas where you want to add the uploaded content. The position of the content to upload will be in reference to the top-left corner of this Canvas. You can use the following mutations: createDocument
, createImage
, createVideo
. To specify that you will sue a URL for the upload of the asset, you will need to use the sourceUrl
field in the mutation, to specify the URL of the asset to upload.
Example of createImage
mutation:
mutation uploadImageFromURL($workspaceId: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $url:String! $scale:Float $idCanvasRelativeTo:String!) {
createImage(
workspaceId: $workspaceId, relativeToOriginOf: $idCanvasRelativeTo
input: {
title:$title
imageFormat: $imageFormat
sourceUrl: $url
transform: {
x: $x
y: $y
scale:$scale
}
})
#return values after creation:
{
content{ uploadId url fields}
preview{uploadId url fields}
image{id width height ingestionState}
}
}
and these are the variables for the mutation above:
{
"workspaceId": "<workspaceId>",
"idCanvasRelativeTo": "<CANVAS_ID>",
"title":"<title_or_filename>",
"imageFormat":"<SEE_ALLOWED_TYPES_AT_THE_TOP_OF_THE_PAGE>",
"previewFormat":"<SEE_ALLOWED_TYPES_AT_THE_TOP_OF_THE_PAGE>",
"url":"<URL_POINTING_TO_THE_IMAGE_TO_UPLOAD>",
"x":<X_COORDINATE>,
"y":<Y_COORDINATE>,
"scale":<SCALE_FACTOR>
}
Example of parameters to load an image:
{
"workspaceId": "<workspaceID>",
"idCanvasRelativeTo": "<CANVAS_ID>",
"title":"Yosemite, open view",
"imageFormat":"jpeg",
"previewFormat":"jpeg",
"url":"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG",
"x":0,
"y":0,
"scale":1
}
Here are implementation examples for the upload by URL using GraphQL and the sample image above:
cURL
curl --location -g --request POST 'https://api.apps.us.bluescape.com/v3/graphql' \
--header 'Authorization: Bearer <SET_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"mutation uploadImageFromURL($workspaceId: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $url:String! $scale:Float $idCanvasRelativeTo:String!) {\n createImage(\n workspaceId: $workspaceId, relativeToOriginOf: $idCanvasRelativeTo\n input: {\n title:$title\n imageFormat: $imageFormat\n sourceUrl: $url\n transform: {\n x: $x\n y: $y\n scale:$scale\n }\n }) \n #return values after creation:\n {\n content{ uploadId url fields}\n preview{uploadId url fields}\n image{id width height ingestionState}\n }\n}","variables":{"ws":"<WORKSPACE_ID>","idCanvasRelativeTo": "<CANVAS_ID>","title":"Yosemite, grand view","imageFormat":"jpeg","previewFormat":"gif","url":"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG","x":0,"y":0,"scale":1}}'
Node.js
const axios = require('axios');
const url = "https://api.apps.us.bluescape.com/v3/graphql"
const token = "<SET_TOKEN>"
const query =
`mutation uploadImageFromURL($workspaceId: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $url:String! $scale:Float $idCanvasRelativeTo: String!) {
createImage(
workspaceId: $workspaceId, relativeToOriginOf: $idCanvasRelativeTo
input: {
title:$title
imageFormat: $imageFormat
sourceUrl: $url
transform: {
x: $x
y: $y
scale:$scale
}
})
#return values after creation:
{
content{ uploadId url fields}
preview{uploadId url fields}
image{id width height ingestionState}
}
}`
const variables = {
"workspaceId": "<WORKSPACE_ID>",
"idCanvasRelativeTo": "<CANVAS_ID>",
"title": "Yosemite, open view",
"imageFormat": "jpeg",
"previewFormat": "jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG",
"x": 0,
"y": 0,
"scale": 1
}
const uploadImageByURL = async () => {
try {
const response = await axios.post(url,
{
query: query,
variables: variables
},
{ headers: { "Authorization": "Bearer " + token } })
answerData = JSON.stringify(response.data);
console.log(answerData);
return response
}
catch (error) {
console.error(error)
}
}
uploadImageByURL();
Python
import requests
import pprint
'''
Required modules:
requests 2.22.0
'''
url = "https://api.apps.us.bluescape.com/v3/graphql"
token = "<SET_TOKEN>"
query = """
mutation uploadImageFromURL($workspaceId: String! $x:Float! $y:Float! $title:String! $imageFormat:ImageFormatInput! $url:String! $scale:Float $idCanvasRelativeTo: String!) {
createImage(
workspaceId: $workspaceId, relativeToOriginOf: $idCanvasRelativeTo
input: {
title:$title
imageFormat: $imageFormat
sourceUrl: $url
transform: {
x: $x
y: $y
scale:$scale
}
})
#return values after creation:
{
content{ uploadId url fields}
preview{uploadId url fields}
image{id width height ingestionState}
}
}
"""
variables = {
"workspaceId": "<WORKSPACE_ID>",
"idCanvasRelativeTo": "<CANVAS_ID>",
"title": "Yosemite, open view",
"imageFormat": "jpeg",
"previewFormat": "jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Yosemite_nat_park_valley_view.JPG/1200px-Yosemite_nat_park_valley_view.JPG",
"x": 0,
"y": 0,
"scale": 1
}
def makeQuery():
response = requests.post(url,
headers={"Authorization": "Bearer " + token
},
json={
'query': query,
'variables': variables
})
return response.json()
if __name__ == "__main__":
response = makeQuery()
pprint.pprint(response)
The immediate answer is an "ingestionState": "transferring"
status, it means that the upload has started:
{
"data": {
"createImage": {
"content": null,
"preview": null,
"image": {
"id": "615c7d676c89c876cd079349",
"width": 1000,
"height": 1000,
"ingestionState": "transferring"
}
}
}
}
Review the upload Ingestion Status using GraphQL APIs
To verify that an image has been successfully uploaded, you can verify the value of the ingestionState
field of a particular image, using the image id:
query checkStatusImageIngestion ($workspace: String! $imageId: String!){
elements(workspaceId:$workspace type:Image id:$imageId) {
... on Image {
id
__typename
ingestionState
}
}
}
Use these variables:
{
"workspace": "<WORKSPACE_ID>",
"imageId" : "<IMAGE_ID>"
}
The response will inform you of the current status of the ingestion of the upload (image, video or document). For example, for an image for which the upload has been completed:
{
"data": {
"elements": [
{
"id": "<IMAGE_ID>",
"__typename": "Image",
"ingestionState": "complete_success"
}
]
}
}
Where to Next?
- Upload content from local drive into a Canvas for v2
- Bluescape API Guides
- Bluescape API Overview
- Latest Developer topics
Not what you were looking for? Reply below or Search the community and discover more Bluescape.