In this Tutorial we introduce a first example for executing a method on DIVAServices. The goal is that after reading through this you can execute simple methods on DIVAServices yourself.
We provide first a complete code example in Python, then provide additional information as well as code examples in other programming languages.
In this example we are going to turn the following color image into grayscale using a Grayification method available on DIVAServices.
Experiment with it Live
This image is available on DIVAServices with the identifier testCollection/ubb-A-II-0004_0002r.jpeg
First we need to execute the method on DIVAServices with a POST request as follows:
import requests
import json
url = "http://divaservices.unifr.ch/api/v2/enhancement/grayification/1"
payload = " {\"parameters\":{},\"data\":[{\"inputImage\": \"testCollection/ubb-A-II-0004_0002r.jpeg\"}]}"
headers = {'content-type': 'application/json'}
response = json.loads(requests.request("POST", url, data=payload, headers=headers).text)
The response
of will look as follows:
{
"results": [
{
"resultLink":"http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/data_0.json"
}
],
"collection": "genuinetubbycero",
"resultLink": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero.json",
"message": "This url is available for 24 hours",
"status": "done",
"statusCode": 202
}
Using the resultLink
inside the results
array we can poll for the actual result using the following method:
def pollResult(self, result_link):
""" Polls for the result of the execution in 1s intervals
Arguments:
result_link {string} -- [the resultLink generated by the POST request that started the execution]
Returns:
[json] -- [the result of the execution]
"""
response = json.loads(requests.request("GET", result_link).text)
while(response['status'] != 'done'):
if(response['status'] == 'error'):
sys.stderr.write('Error in executing the request. See the log file at: ' + response['output'][0]['file']['url'])
sys.exit()
time.sleep(1)
response = json.loads(requests.request("GET", result_link).text)
return response
Where result_link
in this case would be response['outputs'][0]['resultLink']
.
As discussed in the Architecture article, methods on DIVAServices are executed using HTTP POST request. In this Tutorial we want to execute a first simple method on DIVAServices. This method requires one input file and produces one output file.
A GET request (with the browser or any other application) to the URL of the method (see link above), will return the following information in JSON:
{
"general": {
"name": "Grayification",
"description": "Image Grayification",
"developer": "Manuel Bouillon",
"affiliation": "University of Fribourg",
"email": "manuel.bouillon@unifr.ch",
"author": "Manuel Bouillon",
"type": "enhancement",
"license": "Other",
"ownsCopyright": "1",
"expectedRuntime": 14.321428571428571,
"executions": 28
},
"input": [
{
"file": {
"name": "inputImage",
"description": "The input image to transform",
"options": {
"required": true,
"mimeTypes": {
"allowed": [
"image/jpeg",
"image/png",
"image/tiff"
],
"default": "image/jpeg"
}
},
"userdefined": true
}
},
{
"outputFolder": {
"userdefined": false
}
}
],
"output": [
{
"file": {
"name": "grayImage",
"type": "image",
"description": "Generated Grayscale Image",
"options": {
"mimeTypes": {
"allowed": [
"image/jpeg",
"image/png"
],
"default": "image/jpeg"
},
"colorspace": "grayscale",
"visualization": true
}
}
}
]
}
In order to execute the method, two parts are important, the input
and the output
array.
These specify what kind of inputs the method requires and what kind of outputs it produces.
For more information there is the article on Inputs and Outputs
For this tutorial we need to know that the method requires the following inputs:
file
specified in inputImage
that needs to be either a JPEG, a PNG, or a TIFF.outputFolder
that will automatically be provided by DIVAServices (as userdefined
is false
).And the method will produce as output:
file
that is an image
, which is either a JPEG, a PNG, or a TIFF, that could be used by a third-party system as a visualization
.With the information from the GET request we can put together the POST request for executing the method.
For the inputImage
we need the DIVAServices identifier for the image to binarize. Details for getting this are describe in the Tutorial on Data Management.
For this Tutorial we use the identifier testCollection/ubb-A-II-0004_0002r.jpeg
which points to this image.
And we need to remember, that information about data elements goes into the data
part of the request-body
of the POST request.
So the POST request will look like this:
{
"parameters":{},
"data":[
{
"inputImage": "testCollection/ubb-A-II-0004_0002r.jpeg"
}
]
}
This returns the immediate response:
{
"results": [
{
"resultLink": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/data_0.json"
}
],
"collection": "genuinetubbycero",
"resultLink": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero.json"
}
And when polling for the resultLink
inside the results
array you will get the following result of the method:
{
"output": [
{
"file": {
"name": "grayImage",
"type": "image",
"description": "Generated Grayscale Image",
"options": {
"colorspace": "grayscale",
"visualization": true
},
"mime-type": "image/jpeg",
"url": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/grayImage.jpeg"
}
},
{
"file": {
"mime-type": "text/plain",
"type": "log",
"url": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/logFile.txt",
"name": "logFile.txt",
"options": {
"visualization": false
}
}
}
],
"status": "done",
"resultLink": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/data_0.json",
"collectionName": "genuinetubbycero"
}
In the output
array there are two file
entries:
grayImage
: The output image that is the result of the method.logFile
: The logfile of the method.Each with a url
to the location where the file can be downloaded from.
In this example we want to turn the following image into grayscale using the method from above.
Following are examples how this request could be executed using various programming languages.
HttpResponse<JSONObject> response = Unirest.post("http://divaservices.unifr.ch/api/v2/enhancement/grayification/1")
.header("content-type", "application/json")
.body(" {\"parameters\":{},\"data\":[{\"inputImage\": \"testCollection/ubb-A-II-0004_0002r.jpeg\"}]}")
.asJSON();
And polling for the result could be performed as:
/**
* Gets a result JSON object from the exeuction response This method will
* run GET requests in a 5 second interval until the result is available
*
* @param result The JSON object return from the POST request
* @param checkInterval How often to check for new results (in seconds)
* @return The result JSON object
*/
public static List<JSONObject> getResult(JSONObject result, int checkInterval) throws IOException {
JSONArray results = result.getJSONArray("results");
List<JSONObject> response = new LinkedList<>();
for (int i = 0; i < results.length(); i++) {
JSONObject res = results.getJSONObject(i);
String url = res.getString("resultLink");
JSONObject getResult = getSingleResult(url, checkInterval);
response.add(getResult);
}
return response;
}
var request = require("request");
var options = { method: 'POST',
url: 'http://divaservices.unifr.ch/api/v2/enhancement/grayification/1',
headers: { 'content-type': 'application/json' },
body:
{
parameters: {},
data: [
{
inputImage: 'testCollection/ubb-A-II-0004_0002r.jpeg'
}
]
},
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
And polling can be performed as follows:
/**
*
* Fetch the result from a given url
* Polls for the result every 1000ms (1s)
*
* */
function getResult(url) {
return new Promise((resolve,reject) => {
fetch(url, {
method: "GET"
}).then(function (res) {
return res.json();
}).then(function (data) {
if (data.status === "done") {
resolve(data);
}else if(data.status === "error"){
return reject(data);
} else {
setTimeout(function () {
resolve(getResult(url));
}, 1000);
}
});
});
}
Where url
in this case would be response.outputs[0].resultLink
.
The JSON that is returned by the method looks as follows:
{
"output": [
{
"file": {
"name": "grayImage",
"type": "image",
"description": "Generated Grayscale Image",
"options": {
"colorspace": "grayscale",
"visualization": true
},
"mime-type": "image/jpeg",
"url": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/grayImage.jpeg"
}
},
{
"file": {
"mime-type": "text/plain",
"type": "log",
"url": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/logFile.txt",
"name": "logFile.txt",
"options": {
"visualization": false
}
}
}
],
"status": "done",
"resultLink": "http://divaservices.unifr.ch/api/v2/results/genuinetubbycero/data_0/data_0.json",
"collectionName": "genuinetubbycero"
}
This JSON contains the resulting image in the first file
object and log information in the second file
object.
The output image can access using response['output'][0]['file']['url']
.