Developer API Reference
The LabHQ GraphQL API provides a powerful and flexible approach to working with the data in the system. It can be used for performing operations such as reading, creating, updating, and deleting resources.
See the GraphQL Documentation for more information.
Contents
Working with GraphQL
Overview
Working with GraphQL offers a powerful and flexible approach to querying and manipulating data. Unlike traditional REST APIs, GraphQL enables clients to request exactly the data they need with a single query, reducing over-fetching and under-fetching issues. The GraphQL Documentation provides comprehensive guidance on how to craft queries, mutations, and subscriptions, and offers insights into schema design and best practices. By leveraging GraphQL’s introspection capabilities, developers can explore and understand the API schema, making it easier to build efficient and responsive applications.
User Interface
To interact with our GraphQL API, you can use the Altair UI, available at Altair GraphQL Client. Altair provides an intuitive interface for crafting and testing GraphQL queries, mutations, and subscriptions. It also supports features like schema exploration, query history, and variable management, making it an ideal tool for both beginners and experienced developers. Using Altair, you can quickly experiment with different queries and mutations, view the API’s schema, and efficiently debug your requests.
Understanding Responses
Unlike traditional APIs where HTTP status codes often indicate errors, our GraphQL API consistently returns an HTTP status code of 200 for all responses, except for 401 Unauthorized errors and 400 Bad Request errors.
In GraphQL, error handling is distinct. Although the HTTP status code is 200 - OK, this does not ensure that the query was processed correctly. If an error occurs during query execution, the response will include an errors array detailing the issue.
Examples
200 OK
{ "errors":[ { "message":"Operation failed: Unhandled HTTP status code: InternalServerError", "extensions":{ "code":"OPERATION_FAILED", "codes":[ "OPERATION_FAILED" ], "details":"GraphQL.ExecutionError: Operation failed: Unhandled HTTP status code: InternalServerError" } } ], "data":{ "jobs":null } }
In this example:
message
:"Operation failed: Unhandled HTTP status code: InternalServerError"
- Describes the error that occurred.extensions
:code
:"OPERATION_FAILED"
- Indicates the type of error.codes
:["OPERATION_FAILED"]
- An array containing related error codes.details
:"GraphQL.ExecutionError: Operation failed: Unhandled HTTP status code: InternalServerError"
- Provides additional context about the error.data
:jobs
:null
- Indicates that thejobs
field could not be populated due to the error.
401 Unauthorized
{ "errors":[ { "message":"Access denied for schema.", "extensions":{ "code":"ACCESS_DENIED", "codes":[ "ACCESS_DENIED" ], "details":"GraphQL.Server.Transports.AspNetCore.Errors.AccessDeniedError: Access denied for schema." } } ] }
In this example:
message
:"Access denied for schema."
- A description of the error.extensions
:code
:"ACCESS_DENIED"
- Indicates the error type.codes
:["ACCESS_DENIED"]
- An array of related error codes.details
: Additional context about the error.
400 Bad Request
For 400 Bad Request errors, such as incorrect query syntax or invalid fields, you might see a response like this:
{ "errors":[ { "message":"Cannot query field 'id123' on type 'TestMethodInputType'.", "locations":[ { "line":11, "column":9 } ], "extensions":{ "code":"FIELDS_ON_CORRECT_TYPE", "codes":[ "FIELDS_ON_CORRECT_TYPE" ], "number":"5.3.1", "details":"GraphQL.Validation.Errors.FieldsOnCorrectTypeError: Cannot query field 'id2121' on type 'TestMethodInputType'." } } ] }
In this example:
message
:"Cannot query field 'id123' on type 'TestMethodInputType'."
- Describes the error.locations
: Indicates where in the query the error occurred (line 11, column 9).extensions
:code
:"FIELDS_ON_CORRECT_TYPE"
- Indicates the nature of the error.codes
:["FIELDS_ON_CORRECT_TYPE"]
- Error codes associated with the issue.number
:"5.3.1"
- An internal reference number for the error.details
: Provides additional context about the error.
API Reference
Jobs
In LabHQ, a job is a group of samples that are processed through the lifecycle together. A job may consist of samples for any number of products. For more information, see Submit Job.
Getting Jobs
To get a list of jobs, use the jobs
endpoint.
The jobs loaded are limited to a maximum of 100. The query accepts a filter property which filters on the Job’s identifier, batch number, description and client name properties.
Query Example
An example query for getting a list of jobs:
{ jobs(top: 100, skip: 0, filter: "job filter") { items { id identifier description batchNo clientId status submittedBy submittedOn createdBy createdOn updatedBy updatedOn customFieldValues { position title value } samples { id identifier index label description comment batchNo jobId dueDate status createdBy createdOn updatedBy updatedOn receivedBy receivedOn approvedBy approvedOn customFieldValues { position title value } } } totalCount } }
Responses
200 (OK)
:- Jobs returned in an array
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Creating Jobs
To create a new job, use the lifecycleCreate
mutation endpoint.
The mutation accepts job and sample data as well as associated client, product, test and custom field data.
Once successful, the job will have a status of "Submitted" and be available for further lifecycle processing.
Custom Field Values
📒 Custom fields are a premium feature. Please click here for more information.
Custom field values must align with the corresponding field’s position configured in LabHQ. If the position doesn’t match, the value will be ignored.
Custom field values should be submitted as a string (See example below). For date custom fields, ensure the format follows the ISO 8601 standard: yyyy-MM-ddThh:mm:ssZ
. Date values not in this format may cause the date to be invalid.
Mutation Example
An example mutation for creating a new job:
mutation { lifecycleCreate(job: { clientId: "123e4567-e89b-12d3-a456-426614174000", batchNo: "ABC123", description: "This is a detailed description of the Job, which can be up to 2000 characters in length.", customFieldValues: [ { position: 1, value: "text"}, { position: 2, value: "1991-10-14T00:00:00Z"}, { position: 3, value: "3" } ], samples: [ { productId: "123e4567-e89b-12d3-a456-426614174001", batchNo: "BATCH01", description: "Sample description, which can be quite lengthy, up to 2000 characters.", label: "Sample Label up to 300 characters", comment: "Sample comment up to 2000 characters", customFieldValues: [ { position: 1, value: "text"}, { position: 4, value: "1991/10/14T00:00:00Z"} ], tests: [ { id: "b734c2c0-b59c-4575-bb31-4ba1ba2add51", }, { id: "904738b7-1cce-4259-9386-bf3fb1b7967d", } ] } ] }) { id } }
Responses
200 (OK)
:- If the job was successfully created, the response includes the job
id
within the data field. - If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
- If the job was successfully created, the response includes the job
Error Codes
Below is a list of errors that can occur with the lifecycleCreate
mutation in conjunction with the standard error codes provided by GraphQL:
INVALID_REQUEST
: Signifies the request structure is incorrect. This could be but not limited to malformed JSON, incorrect query syntax, or missing required data.RESOURCE_NOT_FOUND
: This error is returned when a referenced resource (ie: client ID) does not exist.INTERNAL_ERROR
: Represents an error that occurred within the server.
Example Successful Response
{ "data": { "lifecycleCreate": { "job": { "id": "123e4567-e89b-12d3-a456-426614174000" } } } }
Example Response with Errors
{ "errors": [ { "message": "Client not found", "extensions": { "code": "RESOURCE_NOT_FOUND", "codes": [ "RESOURCE_NOT_FOUND" ], "details": "GraphQL.ExecutionError: Client not found" } } ], "data": { "lifecycleCreate": null } }
Deleting Jobs
To delete an existing job, use the deleteJob
mutation endpoint.
This deletes the job and all related lifecycle data from the system including job, sample, test and result data.
Once successful, the job will no longer be available for use in the lifecycle.
Mutation Example
An example mutation for deleting a job:
mutation { deleteJob( id: "123e4567-e89b-12d3-a456-426614174001", reason: "Reason for deleting the Job" ) }
Responses
200 (OK)
:- If the Job was successfully deleted, the response returns
true
within the data field. - If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
- If the Job was successfully deleted, the response returns
Error Codes
Below is a list of errors that can occur with the deleteJob
mutation in conjunction with the standard error codes provided by GraphQL:
INVALID_REQUEST
: This can occur when the value for the reason field is not long enough.RESOURCE_NOT_FOUND
: This error is returned when the job ID does not exist.INTERNAL_ERROR
: Represents an error that occurred within the server.
Example Successful Response
{ "data": { "deleteJob": true } }
Example Response with Errors
{ "errors": [ { "message": "Job not found", "extensions": { "code": "RESOURCE_NOT_FOUND", "codes": [ "RESOURCE_NOT_FOUND" ], "details": "GraphQL.ExecutionError: Job not found" } } ], "data": { "deleteJob": false } }
Samples
In LabHQ, a sample represents a group of tests that are processed through the lifecycle together.
Getting Samples
To get a list of samples, use the samples
endpoint.
The samples loaded are limited to a maximum of 100. The query accepts a filter property which filters on the sample’s identifier, batch number, label and description properties.
Query Example
An example query for getting a list of samples:
{ samples(top: 100, skip: 0, jobId: "93d140ae-7f13-4850-b684-479d3780159b", filter: "sample filter") { items { id identifier index label description comment batchNo jobId dueDate status createdBy createdOn updatedBy updatedOn receivedBy receivedOn approvedBy approvedOn customFieldValues { position title value } } totalCount } }
Responses
200 (OK)
:- Samples returned in an array
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Receiving Samples
To receive samples in the lifecycle, use the lifecycleReceive
mutation endpoint.
This processes the given Sample IDs and moves them to the next stage in the lifecycle.
Once successful, the samples will have a status of In Test
.
Mutation Example
An example mutation for receiving samples:
mutation { lifecycleReceive(ids: [ "9aeafc51-1099-4903-8619-701d8af0cb19", "9aeafc51-1099-4903-8619-701d8af0cb19" ]) }
Responses
200 (OK)
If there was an issue with the request, the response includes an errors
field detailing the problems encountered and an error code.
Error Codes
Below is a list of errors that can occur with the lifecycleReceive
mutation:
INVALID_REQUEST
: The sample ID(s) have already been received.RESOURCE_NOT_FOUND
: The sample ID(s) have not been foundINTERNAL_ERROR
: Represents an error that occurred within the server.
Setting Sample Specifications
To set the specification for a sample in the lifecycle, use the updateSampleSpecification
mutation endpoint.
The specification must belong to the product associated with the sample.
Mutation Example
An example mutation for updating a sample specification:
mutation { updateSampleSpecification( sampleId: "9aeafc51-1099-4903-8619-701d8af0cb19", specificationId: "8395f9f5-c0b9-4cd5-8ff7-d4bb226846b2") }
The specificationId
is optional. If unset, the specification will be removed from the sample.
mutation { updateSampleSpecification( sampleId: "9aeafc51-1099-4903-8619-701d8af0cb19") }
Responses
200 (OK)
If there was an issue with the request, the response includes an errors
field detailing the problems encountered and an error code.
Error Codes
Below is a list of errors that can occur with the updateSampleSpecification
mutation:
RESOURCE_NOT_FOUND
: The sample ID or the specification ID has not been found.
Tests
To get a list of tests, use the tests
endpoint.
Tests are limited to a maximum of 100 per page. the query supports filtering tests by test ID.
Query Example
An example query for getting a list of tests:
{ tests(top: 100, skip: 0, id: "0abbeb11-bc1a-4073-95d1-4df072b9ae61") { items { id status repeatIndex outputs { id indexNo name resultCalculation roundedResult displayCalculation displayResult rounding units } } totalCount } }
Responses
200 (OK)
:- Tests returned in an array
- Total count of tests
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Products
Product information is required to submit jobs in LabHQ, the below reference can be used to get product information in various ways.
Get Products
To get products, use the getProducts
endpoint.
The query accepts multiple possible filters including: "name", "id" and "clientId". (See example below)
The query will return data items for associated clients, test suites, specifications (test methods and outputs) and a total count of products returned.
Query Example
An example query for getting a product:
query GetProducts { products( top: 10, skip: 0, name: "Product", id: "6e778062-6608-4932-b3ef-a3395f5b05f2", clientId: "24b6df0b-9d26-4ba3-994b-a5c6e9b4b42d") { items { id name version clients { id name } testSuites { id name } specifications { id name description testMethods { id name outputs { id name description } } } } totalCount } }
Responses
200 (OK)
:- Products returned in an array
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Error Codes
Below is a list of errors that can occur with the getProducts
endpoint in conjunction with the standard error codes provided by GraphQL:
INVALID_REQUEST
: Signifies the request structure is incorrect. This could be but not limited to malformed JSON, incorrect query syntax, or missing required data.INTERNAL_ERROR
: Represents an error that occurred within the server.
Example Successful Response
{ "data": { "products": { "items": [ { "id": "6e778062-6608-4932-b3ef-a3395f5b05f2", "name": "Product A", "version": 6, "clients": [ { "id": "24b6df0b-9d26-4ba3-994b-a5c6e9b4b42d", "name": "Client A" } ], "testSuites": [ { "id": "eb60cf98-c5a6-464e-9ae1-e47797facf22", "name": "Test Suite A" } ], "specifications": [ { "id": "624353ab-ce36-4090-b0dc-3b7fa5d2f724", "name": "Default specification", "description": "Specification description", "testMethods": [ { "id": "6f89ae68-943a-45f9-8d5c-045083d80b40", "name": "TM1", "outputs": [ { "id": "3cd40c65-8107-4984-8b8a-e7b45d5a531c", "name": "Output 1", "description": "Output 1 description" }, { "id": "f02137d6-18a3-4069-80c1-e46360763653", "name": "Output 2", "description": "Output 2 description" } ] } ] } ] } ], "totalCount": 1 } } }
Test Methods
Get Test Methods
To get test methods, use the testMethods
endpoint.
The query accepts an 'id' and a 'name' filter
The query will return data items for inputs, outputs and a total count of test methods returned.
Query Example
An example query for getting a test method:
query testMethods { testMethods( top: 100 skip: 0 name: "Test method 1" ) { items { id name version inputs { id indexNo identifier units fieldType mandatory } outputs { id indexNo name units rounding resultCalculation displayCalculation } } totalCount } }
Responses
200 (OK)
:- Test methods returned in an array
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Error Codes
Below is a list of errors that can occur with the testMethods
endpoint in conjunction with the standard error codes provided by GraphQL:
INVALID_REQUEST
: Signifies the request structure is incorrect. This could be but not limited to malformed JSON, incorrect query syntax, or missing required data.INTERNAL_ERROR
: Represents an error that occurred within the server.
Example Successful Response
{ "data": { "testMethods": { "items": [ { "id": "4e7b065f-1999-4a2e-a461-e03a08369573", "name": "TM1 Weight", "version": 1, "inputs": [ { "id": "3f5ca996-27de-4813-8258-3d8b46fbb8c1", "indexNo": 1, "name": "Weight 1", "identifier": "$1", "units": "g", "fieldType": "numeric", "mandatory": true } ], "outputs": [ { "id": "35e88de1-70f1-48cc-a82e-e82f3cd7803e", "indexNo": 1, "name": "Weight 1", "units": "g", "rounding": null, "resultCalculation": "($1+$2+$3)/3", "displayCalculation": "$R" } ] } ], "totalCount": 1 } } }
Clients
Get Clients
To get clients, use the clients
endpoint. Clients are paginated with a maximum of 100 clients per page.
The query accepts multiple optional filters: id
, name
, isCustomer
.
- IsCustomer: A client is a customer when the client has associated products.
Below is a table outlining how the isCustomer
filter functions.
isCustomer |
Return data |
---|---|
Not set | All clients |
true | Clients who are customers |
false | Clients who are not customers |
Query Example
An example query for getting a client:
{ clients( top: 100, skip: 0, id: "a83bac98-c2e8-4ee7-b52f-5dfcaad7bdfa", name: "client", isCustomer: true) { items { id name address town county country postcode telephone notes isCustomer contactEmails } totalCount } }
Responses
200 (OK)
:- Clients returned in an array
- If there was an issue with the request, the response includes an
errors
field detailing the problems encountered and an error code.
Example Successful Response
{ "data": { "clients": { "items": [ { "id": "24b6df0b-9d26-4ba3-994b-a5c6e9b4b42d", "name": "Client", "address": "address", "town": "Town", "county": "county", "country": "country", "postcode": "postcode", "telephone": "0123456789", "notes": "Note", "isCustomer": true, "contactEmails": [ "a@a", "b@b" ] } ], "totalCount": 3 } } }