Table of Contents

guest
2020-05-28
       HTTP Interface
         Examples: Controller Actions / API Test Page
         Example: Access APIs from Perl

HTTP Interface


Topics

Overview

We strongly recommend using the client library corresponding to your preferred programming language to interact programmatically with LabKey Server. Our client libraries provide flexible authentication mechanisms and automatically handle cookies & sessions, CSRF tokens, marshalling of parameters & payloads, and returning results in native data structures that are easy to manipulate. If absolutely required (e.g., a client library does not exist for your preferred language), you can interact with a LabKey Server through direct HTTP requests, but this requires significantly more effort than using a client library.

The HTTP Interface exposes a set of API endpoints that accept parameters & JSON payloads and return JSON results. These may be called from any program capable of making an HTTP request and decoding the JSON format used for responses (e.g., C++, C#, etc.).

This document describes the API actions that can be used by HTTP requests, detailing their URLs, inputs and outputs. For information on using the JavaScript helper objects within web pages, see JavaScript API. For an example of using the HTTP Interface from Perl, see Example: Access APIs from Perl.

Calling API Actions from Client Applications and Scripts

The API actions documented below may be used by any client application or script capable of making an HTTP request and handling the response. Consult your programming language’s or operating environment’s documentation for information on how to submit an HTTP request and process the response. Most modern languages include HTTP and JSON libraries or helpers.

Several actions accept or return information in the JavaScript Object Notation (JSON) format, which is widely supported. See https://json.org for information on the format, and to obtain libraries/plug-ins for most languages.

Most of the API actions require the user to be authenticated so that the correct permissions can be evaluated. Clients should use basic authentication over HTTPS so that the headers will be encrypted. See https://en.wikipedia.org/wiki/Basic_authentication_scheme for details on the HTTP headers to include, and how to encode the user name and password. The "realm" can be set to any string, as the LabKey server does not support the creation of multiple basic authentication realms. The credentials provided can be a username & password combination or an API key, as described in more detail on this page.

CSRF Token

Important: All mutating API actions (including insertRows, updateRows, and deleteRows) require a CSRF token in addition to user credentials. (For background and rationale, see Cross-Site Request Forgery (CSRF) Protection.) CSRF tokens are handled automatically by the client libraries, but code that invokes APIs via direct HTTP must obtain a CSRF token, send it with every API request. Follow these steps:
  • Execute a GET request to the whoAmI API:
    https://<MyServer>/<MyProject>/<MyFolder>/login-whoAmI.api
  • Retrieve the CSRF token from the JSON response
  • Send the "X-LABKEY-CSRF" cookie back to the server on every request. Note: Many HTTP libraries will re-send server cookies automatically.
  • Add an "X-LABKEY-CSRF" header with the value of the CSRF token to every request. Note: Many HTTP libraries have a mechanism for setting an HTTP header globally.
You can verify that your code is correctly handling CSRF tokens by invoking the test csrf action and ensuring a success response:
https://<MyServer>/<MyProject>/<MyFolder>/test-csrf.api

If you are looking for information on building a custom login page, see Modules: Custom Login Pages.

The following sections document the supported API actions in the current release of LabKey Server.

For further examples of these actions in use, plus a tool for experimenting with "Get" and "Post" parameters, see Examples: Controller Actions / API Test Page

Query Controller API Actions

selectRows Action

The selectRows action may be used to obtain any data visible through LabKey’s standard query grid views.

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/query-selectRows.api?schemaName=lists&query.queryName=my%20list

where "<MyServer>", "<MyProject>", and "<MyFolder>" are placeholders for your server, project, and folder names.

HTTP Method: GET

Parameters: Essentially, anything you see on a query string for an existing query grid is legal for this action.

The following table describes the basic set of parameters.

  
ParameterDescription
schemaNameName of a public schema.
query.queryNameName of a valid query in the schema.
query.viewName(Optional) Name of a valid custom grid view for the chosen queryName.
query.columns(Optional) A comma-delimited list of column names to include in the results. You may refer to any column available in the query, as well as columns in related tables using the 'foreign-key/column' syntax (e.g., 'RelatedPeptide/Protein'). If not specified, the default set of visible columns will be returned.
query.maxRows(Optional) Maximum number of rows to return (defaults to 100)
query.offset(Optional) The row number at which results should begin. Use this with maxRows to get pages of results.
query.showAllRows(Optional) Include this parameter, set to true, to get all rows for the specified query instead of a page of results at a time. By default, only a page of rows will be returned to the client, but you may include this parameter to get all the rows on the first request. If you include the query.showAllRows parameter, you should not include the query.maxRows nor the query.offset parameters. Reporting applications will typically set this parameter to true, while interactive user interfaces may use the query.maxRows and query.offset parameters to display only a page of results at a time.
query.sort(Optional) Sort specification. This can be a comma-delimited list of column names, where each column may have an optional dash (-) before the name to indicate a descending sort.
query.<column-name>~<oper>=<value>(Optional) Filter specification. You may supply multiple parameters of this type, and all filters will be combined using AND logic. The list of valid operators are as follows:
eq = equals
neq = not equals
gt = greater-than
gte = greater-than or equal-to
lt = less-than
lte = less-than or equal-to
dateeq = date equal (visitdate~dateeq=2001-01-01 is equivalent to visitdate >= 2001-01-01:00:00:00 and visitdate < 2001-01-02:00:00:00)
dateneq = date not equal
neqornull = not equal or null
isblank = is null
isnonblank = is not null
contains = contains
doesnotcontain = does not contain
startswith = starts with
doesnotstartwith = does not start with
in = equals one of a semi-colon delimited list of values ('a;b;c').

For example, query.BodyTemperature~gt=98.6

Response Format:

The response can be parsed into an object using any one of the many JSON parsers available via https://www.json.org.

The response object contains four top-level properties:

  • metaData
  • columnModel
  • rows
  • rowCount
metaData: This property contains type and lookup information about the columns in the resultset. It contains the following properties:
  
PropertyDescription
rootThe name of the property containing rows (“rows”). This is mainly for the Ext grid component.
totalPropertyThe name of the top-level property containing the row count (“rowCount”) in our case. This is mainly for the Ext grid component.
sortInfoThe sort specification in Ext grid terms. This contains two sub-properties, field and direction, which indicate the sort field and direction (“ASC” or “DESC”) respectively.
idThe name of the primary key column.
fieldsan array of field information.
name = name of the field
type = JavaScript type name of the field
lookup = if the field is a lookup, there will be three sub-properties listed under this property: schema, table, and column, which describe the schema, table, and display column of the lookup table (query).

columnModel: The columnModel contains information about how one may interact with the columns within a user interface. This format is generated to match the requirements of the Ext grid component. See Ext.grid.ColumnModel for further information.

rows: This property contains an array of rows, each of which is a sub-element/object containing a property per column.

rowCount: This property indicates the number of total rows that could be returned by the query, which may be more than the number of objects in the rows array if the client supplied a value for the query.maxRows or query.offset parameters. This value is useful for clients that wish to display paging UI, such as the Ext grid.

updateRows Action

The updateRows action allows clients to update rows in a list or user-defined schema. This action may not be used to update rows returned from queries to other LabKey module schemas (e.g., ms2, flow, etc). To interact with data from those modules, use API actions in their respective controllers.

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/query-updateRows.api

HTTP Method: POST

POST body: The post body should contain JSON in the following format:

{"schemaName": "lists",
"queryName": "Names",
"rows": [
{"Key": 5,
"FirstName": "Dave",
"LastName": "Stearns"}
]
}

Content-Type Header: Because the post body is JSON and not HTML form values, you must include the 'Content-Type' HTTP header set to 'application/json' so that the server knows how to parse the incoming information.

The schemaName and queryName properties should match a valid schema/query name, and the rows array may contain any number of rows. Each row must include its primary key value as one of the properties, otherwise, the update will fail.

By default, all updates are transacted together (meaning that they all succeed or they all fail). To override this behavior, include a “transacted”: false property at the top level. If 'transacted' is set to 'false,' updates are not automatic and partial updates may occur if an error occurs mid-transaction. For example, if some rows have been updated and an update produces an error, the rows that have been updated before the error will still be updated.

The response from this action, as well as the insertRows and deleteRows actions, will contain JSON in the following format:

{ "schemaName": "lists",
"queryName": "Names",
"command": "update",
"rowsAffected": 1,
"rows": [
{"Key": 5,
"FirstName": "Dave",
"LastName": "Stearns"}
]
}

The response can be parsed into an object using any one of the many JSON parsers available via https://www.json.org.

The response object will contain five properties:

  • schemaName
  • queryName
  • command
  • rowsAffected
  • rows
The schemaName and queryName properties will contain the same schema and query name the client passed in the HTTP request. The command property will be "update", "insert", or "delete" depending on the API called (see below). These properties are useful for matching requests to responses, as HTTP requests are typically processed asynchronously.

The rowsAffected property will indicate the number of rows affected by the API action. This will typically be the same number of rows passed in the HTTP request.

The rows property contains an array of row objects corresponding to the rows updated, inserted, or deleted, in the same order as the rows supplied in the request. However, the field values may have been modified by server-side logic, such as LabKey's automatic tracking feature (which automatically maintains columns with certain names, such as "Created", "CreatedBy", "Modified", "ModifiedBy", etc.), or database triggers and default expressions.

insertRows Action

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/query-insertRows.api

HTTP Method: POST

Content-Type Header: Because the post body is JSON and not HTML form values, you must include the 'Content-Type' HTTP header set to 'application/json' so that the server knows how to parse the incoming information.

The post body for insertRows should look the same as updateRows, except that primary key values for new rows need not be supplied if the primary key columns are auto-increment.

deleteRows Action

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/query-deleteRows.api

HTTP Method: POST

Content-Type Header: Because the post body is JSON and not HTML form values, you must include the 'Content-Type' HTTP header set to 'application/json' so that the server knows how to parse the incoming information.

The post body for deleteRows should look the same as updateRows, except that the client need only supply the primary key values for the row. All other row data will be ignored.

executeSql Action

This action allows clients to execute SQL.

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/query-executeSql.api

HTTP Method: POST

Post Body:

The post body should be a JSON-encoded object with two properties: schemaName and sql. Example:

{
schemaName: 'study',
sql: 'select MyDataset.foo, MyDataset.bar from MyDataset'
}

The response comes back in exactly the same shape as the selectRows action, which is described at the beginning of the Query Controller API Actions section of this page.

Project Controller API Actions

getWebPart Action

The getWebPart action allows the client to obtain the HTML for any web part, suitable for placement into a <div> defined within the current HTML page.

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/project-getWebPart.api?webpart.name=Wiki&name=home

HTTP Method: GET

Parameters: The “webpart.name” parameter should be the name of a web part available within the specified container. Look at the Select Web Part drop-down menu for the valid form of any web part name.

All other parameters will be passed to the chosen web part for configuration. For example, the Wiki web part can accept a “name” parameter, indicating the wiki page name to display. Note that this is the page name, not the page title (which is typically more verbose).

Assay Controller API Actions

assayList Action

The assayList action allows the client to obtain a list of assay definitions for a given folder. This list includes all assays visible to the folder, including those defined at the folder and project level.

Example URL:

https://<MyServer>/<MyProject>/<MyFolder>/assay-assayList.api

HTTP Method: GET

Parameters: None

Return value: Returns an array of assay definition descriptors.

Assay definition descriptor has the following properties:

  
PropertyDescription
NameString name of the assay
idUnique integer ID for the assay.
TypeString name of the assay type. "ELISpot", for example.
projectLevelBoolean indicating whether this is a project-level assay.
descriptionString containing the assay description.
plateTemplateString containing the plate template name if the assay is plate based. Undefined otherwise.
domainsAn object mapping from String domain name to an array of domain property objects. (See below.)

Domain property objects have the following properties:

  
PropertyDescription
nameThe String name of the property.
typeNameThe String name of the type of the property. (Human readable.)
typeURIThe String URI uniquely identifying the property type. (Not human readable.)
labelThe String property label.
descriptionThe String property description.
formatStringThe String format string applied to the property.
requiredBoolean indicating whether a value is required for this property.
lookupContainerIf this property is a lookup, this contains the String path to the lookup container or null if the lookup in the same container. Undefined otherwise.
lookupSchemaIf this property is a lookup, this contains the String name of the lookup schema. Undefined otherwise.
lookupQueryIf this property is a lookup, this contains the String name of the lookup query. Undefined otherwise.

Troubleshooting Tips

If you hit an error, here are a few "obvious" things to check:

Spaces in Parameter Names. If the name of any parameter used in the URL contains a space, you will need to use "%20" or "+" instead of the space.

Controller Names: "project" vs. "query" vs "assay." Make sure your URL uses the controller name appropriate for your chosen action. Different actions are provided by different controllers. For example, the "assay" controller provides the assay API actions while the "project" controller provides the web part APIs.

Container Names. Different containers (projects and folders) provide different schemas, queries and grid views. Make sure to reference the correct container for your query (and thus your data) when executing an action.

Capitalization. The parameters schemaName, queryName and viewName are case sensitive.

Related Topics




Examples: Controller Actions / API Test Page


Overview

This page provides examples to help you get started using the HTTP Interface.

Topics

The API Test Tool

Please note that only admins have access to the API Test Tool.

To reach the test screen for the HTTP Interface, enter the following URL in your browser, substituting the name of your server for "<MyServer>" and the name of your container path for "<MyProject>/<MyFolder>"

http://<MyServer>/labkey/<MyProject>/<MyFolder>/query-apiTest.view?

Note that 'labkey' in this URL represents the default context path, but your server may be configured with a different context path, or no context path. This documentation assumes that 'labkey' (the default) is your server's context path.

Define a List

You will need a query table that can be used to exercise the HTTP Interface. In this section, we create and populate a list to use as our demo query table.

  • Go to the Manage Lists page at (Admin) > Manage Lists.
  • Under Available Lists click Create a New List.
  • Name the list "API Test List" and retain default parameters.
  • Click "Create List."
  • Add fields to the list. Under List Fields click the Add Field button.
  • Add two fields:
    • FirstName - a String
    • Age - an Integer
  • Click Save.

Populate the List

  • On the Create New List page, click Import Data.
  • Copy and paste the following table into the text box labeled Copy/paste text:
List Data

FirstNameAge
A10
B15
C20

Query Controller API Actions: getQuery Action

The getQuery action may be used to obtain any data visible through LabKey’s standard query views.

Get Url:

/labkey/home/query-getQuery.api?schemaName=lists&query.queryName=API%20Test%20List

Response:

{
"schemaName" : "lists",
"queryName" : "API Test List",
"formatVersion" : 8.3,
"metaData" : {
"importTemplates" : [ {

<<< snip >>>

} ],
"title" : "API Test List",
"importMessage" : null
},
"columnModel" : [ {
"hidden" : false,
"dataIndex" : "FirstName",
"editable" : true,
"width" : 200,
"header" : "First Name",
"scale" : 4000,
"sortable" : true,
"align" : "left",
"required" : false
}, {
"hidden" : false,
"dataIndex" : "Age",
"editable" : true,
"width" : 60,
"header" : "Age",
"scale" : 4000,
"sortable" : true,
"align" : "right",
"required" : false
}, {
"hidden" : true,
"dataIndex" : "Key",
"editable" : false,
"width" : 180,
"header" : "Key",
"scale" : 4000,
"sortable" : true,
"align" : "right",
"required" : true
} ],
"rows" : [ {
"FirstName" : "A",
"_labkeyurl_FirstName" : "/labkey/list/MyProject/MyFolder/details.view?listId=1&pk=1",
"Age" : 10,
"Key" : 1
}, {
"FirstName" : "B",
"_labkeyurl_FirstName" : "/labkey/list/MyProject/MyFolder/details.view?listId=1&pk=2",
"Age" : 15,
"Key" : 2
}, {
"FirstName" : "C",
"_labkeyurl_FirstName" : "/labkey/list/MyProject/MyFolder/details.view?listId=1&pk=3",
"Age" : 20,
"Key" : 3
} ],
"rowCount" : 3
}

Query Controller API Actions: updateRows Action

The updateRows action allows clients to update rows in a list or user-defined schema. This action may not be used to update rows returned from queries to other LabKey module schemas (e.g., ms2, flow, etc). To interact with data from those modules, use API actions in their respective controllers.

Post Url:

query-updateRows.api?

Post Body:

{ "schemaName": "lists",
"queryName": "API Test List",
"rows": [
{"Key": 1,
"FirstName": "Z",
"Age": "100"}]
}

Response:

{
"rowsAffected" : 1,
"queryName" : "API Test List",
"schemaName" : "lists",
"containerPath" : "/MyProject/MyFolder",
"rows" : [ {
"EntityId" : "5ABF2605-D85E-1035-A8F6-B43C73747420",
"FirstName" : "Z",
"Key" : 1,
"Age" : 100
} ],
"command" : "update"
}

Result:

FirstNameAge
Z100
B15
C20

Query Controller API Actions: insertRows Action

Post Url:

query-insertRows.api?

Post Body:

Note: The primary key values for new rows need not be supplied when the primary key columns are auto-increment.

{ "schemaName": "lists",
"queryName": "API Test List",
"rows": [
{"FirstName": "D",
"Age": "30"}]
}

Response:

{
"rowsAffected" : 1,
"queryName" : "API Test List",
"schemaName" : "lists",
"containerPath" : "/MyProject/MyFolder",
"rows" : [ {
"EntityId" : "5ABF26A7-D85E-1035-A8F6-B43C73747420",
"FirstName" : "D",
"Key" : 4,
"Age" : 30
} ],
"command" : "insert"
}

Result:

FirstNameAge
Z100
B20
C30
D30

Query Controller API Actions: deleteRows Action

Post Url:

query-deleteRows.api?

Post Body:

Note: Only the primary key values for the row to delete are required.

{ "schemaName": "lists",
"queryName": "API Test List",
"rows": [
{"Key": 3}]
}

Response:

{
"rowsAffected" : 1,
"queryName" : "API Test List",
"schemaName" : "lists",
"containerPath" : "/MyProject/MyFolder",
"rows" : [ {
"EntityId" : "5ABF27C9-D85E-1035-A8F6-B43C73747420",
"FirstName" : "C",
"Key" : 3,
"Age" : 20
} ],
"command" : "delete"
}

Result:

FirstNameAge
Z100
B20
D30

Project Controller API Actions: getWebPart Action

The URL of Project Controller actions uses "project" instead of "query," in contrast to the Query Controller Actions described above.

Lists. The Lists web part:

/<MyProject>/<MyFolder>/project-getWebPart.api?webpart.name=Lists

{
"html" : "<!--FrameType.PORTAL--><div name="webpart"rn id="webpart_0"rn><div class="panel panel-portal">rn<div class="panel-heading"><h3 class="panel-title pull-left" title="Lists"><a name="Lists" class="labkey-anchor-disabled"><a href="/labkey/list/MyProject/MyFolder/begin.view?"><span class="labkey-wp-title-text">Lists</span></a></a></h3>&nbsp;<span class="dropdown dropdown-rollup pull-right"><a href="#" data-toggle="dropdown" class="dropdown-toggle fa fa-caret-down"></a><ul class="dropdown-menu dropdown-menu-right"><li><a href="/labkey/list/MyProject/MyFolder/editListDefinition.view?returnUrl=%2Flabkey%2FMyProject%2FMyFolder%2Fproject-getWebPart.api%3Fwebpart.name%3DLists" tabindex="0" style="">Create New List</a></li><li><a href="/labkey/list/MyProject/MyFolder/begin.view?" tabindex="0" style="">Manage Lists</a></li><li><a href="javascript:LABKEY.Portal._showPermissions(0,null,null);" tabindex="0" style="">Permissions</a></li></ul></span><div class="clearfix"></div></div>rn<div id="WebPartView519542865" class=" panel-body"><!--FrameType.DIV--><div>rnrnrnrnrnrnrnrnrnrnrnrnrnrnrnrnrnrnrnrn<table id="lists">rn <tr><td class="lk-menu-drop dropdown"> <a href="#" data-toggle="dropdown" style="color:#333333;" class="dropdown-toggle fa fa-caret-down"> &nbsp; </a><ul class="dropdown-menu dropdown-menu-right"><li><a href="/labkey/list/MyProject/MyFolder/grid.view?listId=1" tabindex="0" style="">View Data</a></li><li><a href="/labkey/list/MyProject/MyFolder/editListDefinition.view?listId=1" tabindex="0" style="">View Design</a></li><li><a href="/labkey/list/MyProject/MyFolder/history.view?listId=1" tabindex="0" style="">View History</a></li><li><a href="/labkey/list/MyProject/MyFolder/deleteListDefinition.view?listId=1" tabindex="0" style="">Delete List</a></li></ul></td><td><a href="/labkey/list/MyProject/MyFolder/grid.view?listId=1">API Test List</a></td></tr>rn</table>rnrn <a class="labkey-text-link" href="/labkey/list/MyProject/MyFolder/begin.view?">manage lists</a>rnrn</div></div></div></div><!--/FrameType.PORTAL-->",
"requiredJsScripts" : [ ],
"implicitJsIncludes" : [ ],
"requiredCssScripts" : [ ],
"implicitCssIncludes" : [ ],
"moduleContext" : {
"pipeline" : { },
"core" : { },
"internal" : { },
"search" : { },
"experiment" : { },
"filecontent" : { },
"query" : { },
"wiki" : { },
"api" : { },
"announcements" : { },
"issues" : { }
}
}

Wiki. Web parts can take the name of a particular page as a parameter, in this case the page named "somepage":

<MyProject>/<MyFolder>/project-getWebPart.api?webpart.name=Wiki&name=somepage

Assay List. Some web part names have spaces. You can find the valid form of web part names in the Select Web Part drop-down menu. A web part with a space in its name:

<MyProject>/<MyFolder>/project-getWebPart.api?webpart.name=Assay%20List



Example: Access APIs from Perl


You can use the client-side language of your choice to access LabKey's HTTP Interface.

The callQuery.pl Perl script logs into a server and retrieves the contents of a list query called "i5397." It prints out the results decoded using JSON.

Note that JSON 2.07 can be downloaded from http://search.cpan.org/~makamaka/JSON-2.07/ .

Please use the callQuery.pl script attached to this page (click the link to download) in preference to copy/pasting the same script below. The wiki editor is known to improperly escape certain common perl characters. The code below is included for ease of reference only.

#!/usr/bin/perl -w
use strict;

# Fetch some information from a LabKey server using the client API
my $email = 'user@labkey.com';
my $password = 'mypassword';

use LWP::UserAgent;
use HTTP::Request;
my $ua = new LWP::UserAgent;
$ua->agent("Perl API Client/1.0");

# Setup variables
# schemaName should be the name of a valid schema.
# The "lists" schema contains all lists created via the List module
# queryName should be the name of a valid query within that schema.
# For a list, the query name is the name of the list
# project should be the folder path in which the data resides.
# Use a forward slash to separate the path
# host should be the domain name of your LabKey server
# labkeyRoot should be the root of the LabKey web site
# (if LabKey is installed on the root of the site, omit this from the url)
my $schemaName="lists";
my $queryName="MyList";
my $project="MyProject/MyFolder/MySubFolder";
my $host="localhost:8080";
my $labkeyRoot = "labkey";
my $protocol="http";

#build the url to call the selectRows.api
#for other APIs, see the example URLs in the HTTP Interface documentation at
#https://www.labkey.org/Documentation/wiki-page.view?name=remoteAPIs
my $url = "$protocol://$host/$labkeyRoot/query/$project/" .
"selectRows.api?schemaName=$schemaName&query.queryName=$queryName";

#Fetch the actual data from the query
my $request = HTTP::Request->new("GET" => $url);
$request->authorization_basic($email, $password);
my $response = $ua->request($request);

# use JSON 2.07 to decode the response: This can be downloaded from
# http://search.cpan.org/~makamaka/JSON-2.07/
use JSON;
my $json_obj = JSON->new->utf8->decode($response->content);

# the number of rows returned will be in the 'rowCount' propery
print $json_obj->{rowCount} . " rows:n";

# and the rows array will be in the 'rows' property.
foreach my $row(@{$json_obj->{rows}}){
#Results from this particular query have a "Key" and a "Value"
print $row->{Key} . ":" . $row->{Value} . "n";
}