Execute your First method

Introduction

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.

Example in Python

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

(Image Source: Basel, Universit├Ątsbibliothek, A II 4: Nycolaus de Lyra, Postilla super libros Regum et Esther (https://www.e-codices.unifr.ch/en/list/one/ubb/A-II-0004).)

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'].

Table of Content

Execute your first method on DIVAServices

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.

Interpreting the GET request information

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:

  • An input file specified in inputImage that needs to be either a JPEG, a PNG, or a TIFF.
  • An outputFolder that will automatically be provided by DIVAServices (as userdefined is false).

And the method will produce as output:

  • A 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.

Generating the POST request

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.

Example

In this example we want to turn the following image into grayscale using the method from above.

Running the Request

Following are examples how this request could be executed using various programming languages.

Java

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;
}

Node.js

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.

Working with the result

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'].