API

Introduction

Using curl

The following section demonstrates a simple way of sending and retrieving XML using the simple Unix command line tool curl. The following example POSTs the request to the server (our server configuration requires you to also unset the default value in the header for Expect, -H ‘Expect:’):

curl -L -H 'Expect:' -H 'Accept:text/xml' -F seqdb=pdb -F algo=phmmer -F seq='<test.seq' https://www.ebi.ac.uk/Tools/hmmer/search/phmmer
<?xml version="1.0" encoding="UTF-8"?>
<opt>
  <data name='results' resultSize='224339'>
    <_internal highbit='370.5' lowbit='19.0' numberSig='242' offset='42280'>
      <timings search='0.283351' unpack='0.176821' />
    </_internal>
    <hits
        name='2abl_A'
        acc='2abl_A'
        bias='0.1'
        desc='mol:protein length:163  ABL TYROSINE KINASE'
        evalue='1.1e-110'
        ndom='1'
        nincluded='1'
        nregions='1'
        reported='1'
        score='370.5'
        species='Homo sapiens'
        taxid='9606' >
            <domains
                aliL='163'
                aliM='163'
                aliN='163'
                aliaseq='MGPSENDPNLFVALYDFVASGDNTLSITKGEKLRVLGYNHNGEWCEAQTKNGQGWVPSNYITPVNSLEKHSWYHGPVSRNAAEYLLSSGINGSFLVRESESSPGQRSISLRYEGRVYHYRINTASDGKLYVSSESRFNTLAELVHHHSTVADGLITTLHYPAP'
                alihmmfrom='1'
                alihmmname='2abl_A'
                alihmmto='163'
                alimline='+gpsendpnlfvalydfvasgdntlsitkgeklrvlgynhngewceaqtkngqgwvpsnyitpvnslekhswyhgpvsrnaaeyllssgingsflvresesspgqrsislryegrvyhyrintasdgklyvssesrfntlaelvhhhstvadglittlhypap'
                alimodel='lgpsendpnlfvalydfvasgdntlsitkgeklrvlgynhngewceaqtkngqgwvpsnyitpvnslekhswyhgpvsrnaaeyllssgingsflvresesspgqrsislryegrvyhyrintasdgklyvssesrfntlaelvhhhstvadglittlhypap'
                alippline='8*****************************************************************************************************************************************************************9'
                alisqacc='2abl_A'
                alisqdesc='mol:protein length:163  ABL TYROSINE KINASE'
                alisqfrom='1'
                alisqname='2abl_A'
                alisqto='163'
                bias='0.05'
                bitscore='370.357543945312'
                envsc='250.653518676758'
                cevalue='4.21e-121'
                ievalue='4.21e-121'
                                iali='1'
                ienv='1'
                is_included='1'
                is_reported='1'
                jali='163'
                jenv='163'
            />
    </hits>
    .
    .
    .
  </data>
</opt>

In this example, the sequence to be searched is in the file test.seq. The value of the parameter “seq” needs to be quoted so that its value is taken correctly from the file. The other parameters can also be added directly to the URL, as a regular CGI-style parameter, if you prefer.

Using a script

Most programming languages have the ability to send HTTP requests and receive HTTP responses. A Perl script to submit a search and receive the responses as XML might be as trivial as this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/perl

use strict;
use warnings;
use LWP::UserAgent;
use XML::Simple;

#Get a new Web user agent.
my $ua = LWP::UserAgent->new;
$ua->timeout(20);
$ua->env_proxy;

my $host = "https://www.ebi.ac.uk/Tools/hmmer";
my $search = "/search/phmmer";

#Parameters
my  $seq = qq(>2abl_A mol:protein length:163  ABL TYROSINE KINASE
MGPSENDPNLFVALYDFVASGDNT
LSITKGEKLRVLGYNHNGEWCEAQ
TKNGQGWVPSNYITPVNSLEKHSW
YHGPVSRNAAEYLLSSGINGSFLV
RESESSPGQRSISLRYEGRVYHYR
INTASDGKLYVSSESRFNTLAELV
HHHSTVADGLITTLHYPAP);

my $seqdb = 'pdb';

#Make a hash to encode for the content.
my %content = ( 'seqdb' => $seqdb,
                'content'   => "<![CDATA[$seq]]>" );

#Convert the parameters to XML
my $xml = XMLout(\%content, NoEscape => 1);

#Now post it off
my $response = $ua->post( $host.$search, 'content-type' => 'text/xml', Content => $xml );

#By default, we should get redirected!
if($response->is_redirect){

  #Now make a second requests, a get this time, to get the results.
  $response =
  $ua->get($response->header("location"), 'Accept' => 'text/xml' );

  if($response->is_success){
    print $response->content;
  }else{
    print "Error with redirect GET:".$response->content;
    die $response->status_line;
  }
}else{
  die $response->status_line;
}

Retrieving results

Although XML is just plain text and therefore human-readable, it’s intended to be parsed into a data structure. Extending the Perl script above, we can add the ability to parse the XML using an external Perl module, XML::LibXML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/perl

use strict;
use warnings;
use LWP::UserAgent;
use XML::Simple;
use XML::LibXML;

#Get a new Web user agent.
my $ua = LWP::UserAgent->new;
$ua->timeout(20);
$ua->env_proxy;

my $host = "https://www.ebi.ac.uk/Tools/hmmer";
my $search = "/search/phmmer";

#Parameters
my  $seq = qq(>2abl_A mol:protein length:163  ABL TYROSINE KINASE
MGPSENDPNLFVALYDFVASGDNTLSITKGE
KLRVLGYNHNGEWCEAQTKNGQGWVPSNYIT
PVNSLEKHSWYHGPVSRNAAEYLLSSGINGS
FLVRESESSPGQRSISLRYEGRVYHYRINTA
SDGKLYVSSESRFNTLAELVHHHSTVADGLI
TTLHYPAP);

my $seqdb = 'pdb';

#Make a hash to encode for the content.
my %content = ( 'seqdb' => $seqdb,
                'content'   => "<![CDATA[$seq]]>" );

#Convert the parameters to XML
my $xml = XMLout(\%content, NoEscape => 1);

#Now post it off
my $response = $ua->post( $host.$search, 'content-type' => 'text/xml', Content => $xml );

die "error: failed to successfully POST request: " . $response->status_line . "\n"
  unless ($response->is_redirect);

#By default, we should get redirected!
$response =
  $ua->get($response->header("location"), 'Accept' => 'text/xml' );

die "error: failed to retrieve XML: " . $response->status_line . "\n"
  unless $response->is_success;


my $xmlRes = '';

$xmlRes .= $response->content;
my $xml_parser = XML::LibXML->new();
my $dom = $xml_parser->parse_string( $xmlRes );

my $root = $dom->documentElement();

my ( $entry ) = $root->getChildrenByTagName( 'data' );
my @hits  = $entry->getChildrenByTagName( 'hits' );

foreach my $hit (@hits){
  next if($hit->getAttribute( 'nincluded' ) == 0 );
  print $hit->getAttribute( 'name' )."\t".$hit->getAttribute( 'desc' )."\t".$hit->getAttribute( 'evalue' )."\n";
}

This script now prints out the name, description and E-value of all significant sequence hits for the given query sequence in tab delimited format:

2abl_A        mol:protein length:163  ABL TYROSINE KINASE     1.1e-110
2fo0_A        mol:protein length:495  Proto-oncogene tyrosine-protein kinase ABL1 (   8.4e-109
1opk_A        mol:protein length:495  Proto-oncogene tyrosine-protein kinase ABL1     8.4e-109
1opl_A        mol:protein length:537  proto-oncogene tyrosine-protein kinase  9.7e-109
1ab2_A        mol:protein length:109  C-ABL TYROSINE KINASE SH2 DOMAIN        3.3e-62
3k2m_A        mol:protein length:112  Proto-oncogene tyrosine-protein kinase ABL1     3.1e-61
2ecd_A        mol:protein length:119  Tyrosine-protein kinase ABL2    6.5e-58
1abo_A        mol:protein length:62  ABL TYROSINE KINASE      1.1e-38
3eg1_A        mol:protein length:63  Proto-oncogene tyrosine-protein kinase ABL1      1.6e-38
3eg0_A        mol:protein length:63  Proto-oncogene tyrosine-protein kinase ABL1      1.7e-38
3eg3_A        mol:protein length:63  Proto-oncogene tyrosine-protein kinase ABL1      3.3e-38
1ju5_C        mol:protein length:61  Abl      8.4e-38
1bbz_A        mol:protein length:58  ABL TYROSINE KINASE      7.0e-36
2o88_A        mol:protein length:58  Proto-oncogene tyrosine-protein kinase ABL1      9.1e-35
1awo_A        mol:protein length:62  ABL TYROSINE KINASE      1.7e-34

Available services

phmmer searches

The main two input parameters to a phmmer search are a protein sequence and the target database, defined using the seq and seqdb parameters respectively. Other parameters for controlling the search are defined in the search section. If any of these parameters are omitted, then the default values for that parameter will be set.

Searches should be POST-ed to the following url:

https://www.ebi.ac.uk/Tools/hmmer/search/phmmer

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F seqdb=pdb -F seq='<test.seq' https://www.ebi.ac.uk/Tools/hmmer/search/phmmer

When using the website, we also perform a Pfam search by default. However, when using the API you will only be returned the phmmer results. To get Pfam search results, use the hmmscan interface.

hmmscan searches

Hmmscan also has two main parameters - a sequence and a profile HMM database - defined using the seq and hmmdb parameters respectively. We currently offer six profile HMM databases: Pfam, TIGRFAMs, Gene3D, Superfamily, PIRSF and TreeFam. When searching against the first two, the cut-offs can be defined by the user (other parameters for controlling the search are defined in the search section). With the remaining databases all cut-off parameters will be ignored and the default HMM database parameters will be used. This is because these databases use their own post-processing mechanisms to define their domains, in addition to the hmmscan results.

Searches should be POST-ed to the following url:

https://www.ebi.ac.uk/Tools/hmmer/search/hmmscan

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F hmmdb=pfam -F seq='<test.seq' https://www.ebi.ac.uk/Tools/hmmer/search/hmmscan

hmmsearch searches

The input to hmmsearch on the web is either a multiple sequence alignment or a hidden Markov model in HMMER3 format. We do not support HMMER2 format as these HMMs are not forward compatible with HMMER3. When uploading a multiple sequence alignment, an HMM is built on the server using hmmbuild with the default parameters.

Searches should be POST-ed to the following url:

https://www.ebi.ac.uk/Tools/hmmer/search/hmmsearch

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F seqdb=pdb -F seq='<test.ali' https://www.ebi.ac.uk/Tools/hmmer/search/hmmsearch

jackhmmer searches

Jackhmmer is an iterative search algorithm that can be initiated with a sequence, multiple sequence alignment or profile HMM. The number of iterations to run can be supplied as an additional parameter and will perform a succession of searches until the job has completed. Fetching the results is a little more complicated, as the search may finish before the number of iterations if it converges.

Searches should be POST-ed to the following url:

https://www.ebi.ac.uk/Tools/hmmer/search/jackhmmer

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F seqdb=pdb -F iterations=5 -F seq='<test1.fa' https://www.ebi.ac.uk/Tools/hmmer/search/jackhmmer

Taxonomic restrictions

For searches against a sequence database (i.e. all types excluding hmmscan) you may restrict your search by taxonomy. To do this, set the parameter taxFilterType=search, alongwith either or both of tax_included and tax_excluded, each of which takes a comma delimited list of taxonomy IDs.

Example:

curl -L -H 'Expect:' -H 'Accept:application/json' -F taxFilterType=search -F tax_included=40674 -F tax_excluded=9606,10090 -F seqdb=pdb -F seq='<seq.fa' https://www.ebi.ac.uk/Tools/hmmer/search/phmmer

Annotation searches

In addition to the standard HMMER searches an uploaded sequence can be annotated to show signal peptide & transmembrane regions, disordered regions and coiled-coil regions.

Annotation requests should be POST-ed to the following urls.

Disorder:

https://www.ebi.ac.uk/Tools/hmmer/annotation/disorder

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F  seq='<test.fa' https://www.ebi.ac.uk/Tools/hmmer/annotation/disorder

Coiled-coil:

https://www.ebi.ac.uk/Tools/hmmer/annotation/coils

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F  seq='<test.fa' https://www.ebi.ac.uk/Tools/hmmer/annotation/coils

Transmembrane & Signal Peptides:

https://www.ebi.ac.uk/Tools/hmmer/annotation/phobius

Example:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F  seq='<test.fa' https://www.ebi.ac.uk/Tools/hmmer/annotation/phobius

Annotation results can be fetched with a GET request using the UUID supplied in the POST response:

https://www.ebi.ac.uk/Tools/hmmer/annotation/<annotation-type>/UUID

Example:

curl -H 'Expect:' -H 'Accept:text/xml' https://www.ebi.ac.uk/Tools/hmmer/annotation/phobius/4162F712-1DD2-11B2-B17E-C09EFE1DC403

Results

Search results can be retrieved using the job identifier that is returned in your initial search response. The job identifier is a UUID (format such as 4162F712-1DD2-11B2-B17E-C09EFE1DC403). Thus, to retrieve your job, you can use the following URL in a GET request:

https://www.ebi.ac.uk/Tools/hmmer/results/$your_uuid?output=html

Example:

https://www.ebi.ac.uk/Tools/hmmer/results/4162F712-1DD2-11B2-B17E-C09EFE1DC403?output=html

This is one of the few services where the returned format can be modified using a parameter.

Parameter range ali output
Description The range of the results to retrieve Return alignments Modify the format that the results are returned in
Accepted values Integer,Integer true | 1 xml | json | text | yaml
Example range=1,100 ali=1 html
Default/Without Parameter All results No alignments will be returned output=text
Notes The results are ordered by E-value and as there can be thousands of matches to your query, it can be useful to retrieve a subset of results. The range is two, unsigned, comma separated integers. The first integer is expected to be less than the second integer. To retrieve one row, just fetch using a range where the two integers are the same value. If your first integer is in range, and your second is out of range, the second integer will be modified to include all results. i.e. If your results set is only 300 in size, and a range of 1,1000 is requested, then you will get 300 results. If your starting integer is “out” of range, then no results will be returned. Sometimes you are not so interested in the alignment of the match to the query sequence. By default no alignments are returned, to keep results compact. The format of the results can be modified with by setting “output=$format”. The same can be achieved by setting the “Accept” field in the HTTP header. If both the HTTP header and the parameter are set, we currently assume that the parameter is the desired format.

Deleting results

The results will normally only remain on the server for a maximum of one week; however they may be deleted by sending a DELETE request:

curl -X DELETE -H 'Accept:application/json' https://www.ebi.ac.uk/Tools/hmmer/results/F36F96A4-0806-11E8-A990-C006DCC3747A/score

Taxonomy and domain views

The API may also be used to retrive the data behind the taxonomy and domain architecture tabs on the results page. For taxonomy the URL has the form:

https://www.ebi.ac.uk/Tools/hmmer/results/$your_uuid/taxonomy

Example:

curl -s -H "Content-type: application/json" 'https://www.ebi.ac.uk/Tools/hmmer/results/8D5B74A0-6158-11E7-B311-1331132D729D/taxonomy'

The fields returned are described in Appendix F - JSON format

For domain architecture, two endpoints are provided. The first returns an overview of all architectures:

https://www.ebi.ac.uk/Tools/hmmer/results/$your_uuid/domain

Example:

curl -s -H "Content-type: application/json" 'https://www.ebi.ac.uk/Tools/hmmer/results/8D5B74A0-6158-11E7-B311-1331132D729D/domain'

The second queries an individual architecture identifier:

https://www.ebi.ac.uk/Tools/hmmer/results/$your_uuid/domain/$arch_id

Example:

curl -s -H "Content-type: application/json" 'https://www.ebi.ac.uk/Tools/hmmer/results/D33FBDA4-6230-11E7-BC34-E492DBC3747A/domain/36055491190690'

Examples

phmmer

The following piece of python is a little more complex than those discussed previously. In this case, we submit a search to the server, but stop the HTTP handler from automatically following the redirection to the results page. Instead, a custom handler is define that grabs the redirection URL and modifies it by the addition of parameters such that it fetches just the first 10 matches in JSON format, rather than grabbing the whole response. This can be useful when the results are large and you want to paginate the response, or if you are only interested in the most significant sequence matches.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import urllib, urllib2

# install a custom handler to prevent following of redirects automatically.
class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
    def http_error_302(self, req, fp, code, msg, headers):
        return headers
opener = urllib2.build_opener(SmartRedirectHandler())
urllib2.install_opener(opener);

parameters = {
    'seqdb':'pdb',
    'seq':'>Seq\nKLRVLGYHNGEWCEAQTKNGQGWVPSNYITPVNSLENSIDKHSWYHGPVSRNAAEY'
}
enc_params = urllib.urlencode(parameters);

#post the seqrch request to the server
request = urllib2.Request('https://www.ebi.ac.uk/Tools/hmmer/search/phmmer',enc_params)

#get the url where the results can be fetched from
results_url = urllib2.urlopen(request).getheader('location')

# modify the range, format and presence of alignments in your results here
res_params = {
    'output': 'json',
    'range': '1,10'
}

# add the parameters to your request for the results
enc_res_params = urllib.urlencode(res_params)
modified_res_url = results_url + '?' + enc_res_params

# send a GET request to the server
results_request = urllib2.Request(modified_res_url)
data = urllib2.urlopen(results_request)

# print out the results
print data.read()

hmmscan

The following is a very basic Java source file that, once compiled and and executed performs an hmmscan search. The response is returned in JSON format. With this two stage POST and GET, you can POST the request in one format and get a response back in another by setting the Accept type. To get this example to work, you should save the code in a file called RESTClient.java. Then run the command “javac RESTClient.java”. Assuming that this is successful and a file called RESTClient.class is produced, you can execute the class by running the command “java RESTClient”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.net.*;
import java.io.*;

public class RESTClient{
  public static void main(String[] args) {
    try {
        URL url = new URL("https://www.ebi.ac.uk/Tools/hmmer/search/hmmscan");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setInstanceFollowRedirects(false);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setRequestProperty("Accept", "application/json");

        //Add the database and the sequence. Add more options as you wish!
        String urlParameters = "hmmdb=" + URLEncoder.encode("pfam", "UTF-8") +
        "&seq=" + ">seq\nEMGPSENDPNLFVALYDFVASGDNTLSITKGEKLRVLGYNHNGEWCEAQTKNGQGWVPSNYITPV" +
        "NSLEKHSWYHGPVSRNAAEYLLSSGINGSFLVRESESSPGQRSISLRYEG" +
        "RVYHYRINTASDGKLYVSSESRFNTLAELVHHHSTVADGLITTLHYPAP";

         connection.setRequestProperty("Content-Length", "" +
               Integer.toString(urlParameters.getBytes().length));


        //Send request
        DataOutputStream wr = new DataOutputStream (
                  connection.getOutputStream ());
        wr.writeBytes (urlParameters);
        wr.flush ();
        wr.close ();



        //Now get the redirect URL
        URL respUrl = new URL( connection.getHeaderField( "Location" ));
        HttpURLConnection connection2 = (HttpURLConnection) respUrl.openConnection();
        connection2.setRequestMethod("GET");
        connection2.setRequestProperty("Accept", "application/json");


        //Get the response and print it to the screen
        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                connection2.getInputStream()));

        String inputLine;

        while ((inputLine = in.readLine()) != null)
            System.out.println(inputLine);
        in.close();


    } catch(Exception e) {
        throw new RuntimeException(e);
    }
  }
}

jackhmmer

A jackhmmer is a multipart search. The following Perl code performs a series of requests to the server. The first POST request generates the jobs, the while loop then performs GET requests to get the job status, until the status of the job is done. The last request GETs the results of the last iteration, which are returned in JSON format.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env perl
use strict;
use warnings;
use LWP::UserAgent;
use JSON;

#Get a new Web user agent.
my $ua = LWP::UserAgent->new;
$ua->timeout(60);
$ua->env_proxy;
#Set a new JSON end encoder/decoder
my $json = JSON->new->allow_nonref;

#-------------------------------------------------------------------------------
#Set up the job

#URL to query
my $rootUrl = "https://www.ebi.ac.uk/Tools/hmmer";
my $url = $rootUrl."/search/jackhmmer";

my $seq = ">2abl_A mol:protein length:163  ABL TYROSINE KINASE
MGPSENDPNLFVALYDFVASGDNTLSITKGEKLRVLGYNHNGEWCEAQTKNGQGWVPSNYITPVNSLEKHS
WYHGPVSRNAAEYLLSSGINGSFLVRESESSPGQRSISLRYEGRVYHYRINTASDGKLYVSSESRFNTLAE
LVHHHSTVADGLITTLHYPAP";

my %content = (
  'algo'     => 'jackhmmer',
  'seq'      => $seq,
  'seqdb'    => 'pdb',
  iterations => 5,
);

#-------------------------------------------------------------------------------
#Now POST the request and generate the search job.
my $response = $ua->post(
  $url,
  'content-type' => 'application/json',
  Content        => $json->encode( \%content )
);

if($response->status_line ne "201 Created"){
  die "Failed to create job, got:".$response->status_line;
}

my $job = $json->decode( $response->content );
print "Generated job UUID:".$job->{job_id}."\n";

#Follow the redicrection to the resouce create for the job.
my $job_location = $response->header("location");
#Now poll the server until the job has finished
$response = $ua->get( $job_location, 'Accept' => 'application/json' );

my $max_retry = 50;
my $count     = 1;

while ( $response->status_line eq '200 OK' ) {
  my $status = $json->decode( $response->content );

  print "Checking status ($count)......";
  if ( $status->{status} eq 'DONE' ) {
    print "Job done.\n";
    last;
  }
  elsif ( $status->{status} eq 'ERROR' ) {
    print "Job failed, exiting!\n";
    exit(1);
  }
  elsif ( $status->{status} eq 'RUN' or $status->{status} eq 'PEND' ) {
    my ($lastIteration) = $status->{result}->[-1]->{uuid} =~ /\.(\d+)/;
    print "Currently on iteration $lastIteration [$status->{status}].\n";
  }

  if ( $count > $max_retry ) {
    print "Jobs should have finished.....exiting\n";;
    exit(1);
  }
  #Job still running, so give it a chance to complete.
  sleep(5);
  #Check again on the job status...
  $response = $ua->get( $job_location, 'Accept' => 'application/json' );
  $count++;
}

#Job should have finished, but we may have converged, so get the last job.
my $results = $json->decode( $response->content );
my $lastIteration = pop( @{ $results->{result} } );
#Now fetch the results of the last iteration
my $searchResult = $ua->get( $rootUrl."/results/" . $lastIteration->{uuid} . "/score", 'Accept' => 'application/json' );
unless( $searchResult->status_line eq "200 OK"){
  die "Failed to get search results\n";
}

#Decode the content of the full set of results
$results = $json->decode( $searchResult->content );
print "Matched ".$results->{'results'}->{'stats'}->{'nincluded'}." sequences ($lastIteration->{uuid})!\n";
#Now do something more interesting with the results......

Batch searches

So far, the submission of batch searches via REST has not really been mentioned. This is because we do not anticipate this being so useful as you can programmatically send sequence after sequence. However, a batch upload of sequences is possible for phmmer and hmmscan. The main difference is that instead of using the seq parameter, we use the file parameter. There is also a subtle difference in the way that the curl command is formulated. Rather than using a redirect (<), a the symbol is used to force the content part of the request to be what is contained within the file, rather than being attached to the parameter:

curl -L -H 'Expect:' -H 'Accept:text/xml' -F seqdb=pdb -F file='@batch.fasta' https://www.ebi.ac.uk/Tools/hmmer/search/phmmer

It is also possible to include an email address for notification of when the batch search has been processed. Again, not particularly useful for an API, but it may be useful for keeping track of a pipeline. To specify an email via the command line, simply use the parameter email and set this to a valid email address. All of the other phmmer or hmmscan search parameters apply to the batch search.

Fetching results

Using curl to fetch results is very easy:

curl -L -H 'Expect:' -H 'Accept:text/xml' https://www.ebi.ac.uk/Tools/hmmer/results/CF5BCDA4-0C7E-11E0-AF4F-B1E277D6C7BA?output=text&ali=1&range=1,2

In this case we want to fetch the first two hits, with their alignments as a textual output format.

Downloading files from batch searches

For batch searches, it is not possible to download results for all individual query sequences in a single request. A single combined output might make sense for some formats (e.g. tsv), but not others (such as an alignment). The results of each search need to be downloaded individually.

The summary page may be requested as json or xml to make it easier to obtain the list of individual search IDs:

curl -H 'Accept: application/json' 'https://www.ebi.ac.uk/Tools/hmmer/results/A67B56FE-CA07-11E7-A02C-F964E976C163/score'

Once you have the list of IDs you can download any of the files programmatically, for example:

curl 'https://www.ebi.ac.uk/Tools/hmmer/download/A67B56FE-CA07-11E7-A02C-F964E976C163.5/score?format=csv'