Getting started with the Kidney REST API

This page describes the basics of using the kidney exchange REST API

Quick Start

In addition to the SOAP API the Kidney Exchange Allocator also exposes a REST-like API - there is no strict sense of resources, it's just essentially an API over HTTP. The API makes available two methods, find.json and find.xml, both of which find an allocation of donors to patients with the output data being formatted in JSON and XML respectively.

There are many libraries available in most programming languages to consume such a service; they vary from full blown REST resource kits to simple HTTP client libraries. Here we use the Apache Java HttpClient library to show how the service can be used and the output data processed.

First you will need to download the appropriate jar files from the Apache website. On this page select 'binaries with dependencies' to get a superset of the jar files required to run this example - of these files you only really need the httpclient, httpcore and the common-logging jar files. The sample code below simply builds a URL to the service and sends this data using an HTTP POST request. It's worth noting that this must be a POST request and an error will be returned should you try to access this API with any other HTTP request type (e.g. GET or PUT). In the example below we are calling the find.json method and as such the output data (also shown below) is returned in JSON format - more detailed information is available about the format on the Output Formats page.

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.net.URISyntaxException;

import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class Client {
    public static void main(String[] args) throws IOException, URISyntaxException {

      String data = "{ \"data\" :"
        + "{ \"1\" : { \"sources\" : [1],"
        +             "\"dage\" : 65,"
        +             "\"matches\" : [ { \"recipient\" : 2, \"score\" : 3},"
        +                             "{ \"recipient\" : 3, \"score\" : 1},"
        +                             "{ \"recipient\" : 4, \"score\" : 2} ]},"
        +   "\"2\" : { \"sources\" : [2],"
        +             "\"dage\" : 45,"
        +             "\"matches\" : [ { \"recipient\" : 1, \"score\" : 2},"
        +							                 "{ \"recipient\" : 5, \"score\" : 1} ]},"
        + "\"3\" : { \"sources\" : [3],"
        +           "\"dage\" : 25,"
        +           "\"matches\" : [ { \"recipient\" : 1, \"score\" : 1} ]},"
        + "\"4\" : { \"sources\" : [4],"
        +           "\"dage\" : 55,"
        +           "\"matches\" : [ { \"recipient\" : 2, \"score\" : 3},"
        +                           "{ \"recipient\" : 3, \"score\" : 2},"
        +                           "{ \"recipient\" : 5, \"score\" : 4} ]},"
        + "\"5\" : { \"sources\" : [5],"
        +           "\"dage\" : 30,"
        +           "\"matches\" : [ { \"recipient\" : 2, \"score\" :	1},"
        +                           "{ \"recipient\" : 4, \"score\" : 2} ]} } }";

    List<NameValuePair> qparams = new ArrayList<NameValuePair>();
    qparams.add(new BasicNameValuePair("data", data));
    qparams.add(new BasicNameValuePair("operation", "optimal"));
    qparams.add(new BasicNameValuePair("altruistic_chain_length", "1"));

    URI uri = URIUtils.createURI("https", "kidney.optimalmatching.com", -1, "/kidney/find.json",
                                 URLEncodedUtils.format(qparams, "UTF-8"), null);
    HttpPost httpost = new HttpPost(uri);

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpResponse response = httpclient.execute(httpost);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
         InputStream instream = entity.getContent();
         BufferedReader reader = new BufferedReader(new InputStreamReader(instream));

         String str;
         while ((str = reader.readLine()) != null) {
          System.out.println(str);
         }
       }

      httpclient.getConnectionManager().shutdown();
  }
}
    
{ "algorithm" : "Optimal set of exchanges with respect to the optimality criteria",
  "output" : {
    "all_cycles": {
      "0": {"cycle": [{"p": 1,"d": 1,"tb": 0.025,"dif": 3,"s": 3},
                      {"p": 2,"d": 2,"tb": 0.025,"dif": 3,"s": 2}],
            "backarcs": 0, "weight": 11.05, "alt": []},
      "1": {"cycle": [{"p": 1,"d": 1,"tb": 0.009,"dif": 0,"s": 1},
                      {"p": 3,"d": 3,"tb": 0.009,"dif": 0,"s": 1}],
            "backarcs": 0, "weight": 2.018, "alt": []},
      "2": {"cycle": [{"p": 2,"d": 2,"tb": 0.03025,"dif": 3,"s": 1},
                      {"p": 5,"d": 5,"tb": 0.03025,"dif": 3,"s": 1}],
            "backarcs": 0, "weight": 8.0605, "alt": []},
      "3": {"cycle": [{"p": 4,"d": 4,"tb": 0.02025,"dif": 0,"s": 4},
                      {"p": 5,"d": 5,"tb": 0.02025,"dif": 0,"s": 2}],
            "backarcs": 0, "weight": 6.0405, "alt": []},
      "4": {"cycle": [{"p": 1,"d": 1,"tb": 0.036,"dif": 3,"s": 2},
                      {"p": 4,"d": 4,"tb": 0.036,"dif": 3,"s": 3},
                      {"p": 2,"d": 2,"b": 0,"tb": 0.025,"dif": 3,"s": 2}],
            "backarcs": 1, "weight": 16.097, "alt": []},
      "5": {"cycle": [{"p": 1,"d": 1,"tb": 0.036,"dif": 3,"s": 2},
                      {"p": 4,"d": 4,"tb": 0.016,"dif": 0,"s": 2},
                      {"p": 3,"d": 3,"b": 1,"tb": 0.009,"dif": 0,"s": 1}],
            "backarcs": 1, "weight": 8.061, "alt": []},
      "6": {"cycle": [{"p": 2,"d": 2,"b": 2,"tb": 0.03025,"dif": 3,"s": 1},
                      {"p": 5,"d": 5,"b": 3,"tb": 0.02025,"dif": 0,"s": 2},
                      {"p": 4,"d": 4,"tb": 0.036,"dif": 3,"s": 3}],
            "backarcs": 2, "weight": 12.0865, "alt": []}},
    "exchange_data": [
      { "description": "(COIN) Optimal set of exchanges",
        "exchanges": [1,6],
        "weight": 14.1045,
        "two_way_exchanges": 1,
        "total_transplants": 5,
        "three_way_exchanges": 1 } ]
  }
}

REST Requests

REST is the simplest request format to use - it's a simple HTTP POST action. The REST Endpoint URL is http://kidney.optimalmatching.com/kidney

REST Response

REST is the simplest response format to use - it's a simple XML or JSON block depending on what format you have requested For XML the format will look something like this:

        <?xml version="1.0" encoding="utf-8" ?>
        <data>
          <algorithm>
            [algorithm-name-here]
          </algorithm>
          <output>
            [xml-payload-here]
          </output>
        </data>
      
And for JSON it's something like this:
       { "algorithm" : [algorithm-name-here],
         "output" : [json-payload-here] }
     
If an error occurs, and XML format is being used, the following is returned:
      <?xml version="1.0" encoding="utf-8" ?>
      <data>
        <algorithm>
          [algorithm-name-here]
        <algorithm>
        <error>
          [error-message-here]
        <error>
      </data>
    
Similarly if an error occurs when using json we get:
      { "algorithm" : [algorithm-name-here],
        "output" : [error-message-here] }
    

API Guide

The REST API exposes two methods, namely find.xml and find.json. As you may expect these methods carry out the same operation and differ only in the format of the data they returned. Each method is discussed in detail below.

find.json(data, operation, altruistic_chain_length)
Finds an allocation of kidney donors to potential recipients. The data returned is in JSON format and is described in more detail in the Output Formats section.
data
Holds a list of matched source patients, and their donors, to compatible target patients. The data must also include the score between donors and target patients and the donor's age. The various formats that the data can take are described in detail on the Input Formats page.
operation
This controls what type of allocation is returned. There are four possible parameters:
optimal
returns a solution that is defined as optimal in the optimality criteria section.
maxcard
returns a solution that has maximum cardinality and subject to this maximum weight, i.e. is not constraint by maximising the effective number of pairwise exchanges. More details of this can be found in the maxcard sub-section of the optimality criteria section.
pairs
returns an optimal solution involving only pairwise exchanges.
altruistic_chain_length
Indicates the length of a chain in an altruistic cycle. Default is 1.
The parameters below are only supported in versions 1.0.0 and above of the kidney_server (ruby) application and all version of the kidney_service application.
max_cycle_size
Indicates the maximum length of a cycle in an optimal solution. Default is 3.
output_format
The format of the data returned this can be either nhsbtv1 or nhsbtv2. Default is nhsbtv1.
find.xml(data, operation, altruistic_chain_length)
Finds an allocation of kidney donors to potential recipients. The data returned is in XML format and is described in more detail in the Output Formats section.
data
Holds a list of matched source patients, and their donors, to compatible target patients. The data must also include the score between donors and target patients and the donor's age. The various formats that the data can take are described in detail on the Input Formats page.
operation
This controls what type of allocation is returned. There are four possible parameters:
optimal
returns a solution that is defined as optimal in the optimality criteria section.
maxcard
returns a solution that has maximum cardinality and subject to this maximum weight, i.e. is not constraint by maximising the effective number of pairwise exchanges. More details of this can be found in the maxcard sub-section of the optimality criteria section.
pairs
returns an optimal solution involving only pairwise exchanges.
altruistic_chain_length
Indicates the length of a chain in an altruistic cycle. Default is 1.
The parameters below are only supported in versions 1.0.0 and above of the kidney_server (ruby) application and all version of the kidney_service application.
max_cycle_size
Indicates the maximum length of a cycle in an optimal solution. Default is 3.
output_format
The format of the data returned this can be either nhsbtv1 or nhsbtv2. Default is nhsbtv1.
v1.0.0