Skip to main content

Syntax

Under development

The GraphQL API is currently under development, so some features of the language and system may not be available.

To interact with the GraphQL API in the most efficient way, it is necessary to understand the structure and syntax of queries. To fully understand all the capabilities and limitations of the language, it is recommended to read the GraphQL specification. This article describes the main query components and examples of their application based on the ALOR Broker GraphQL API schema.


Query structure

Required components

Query structure of GraphQL API operates with two main entities: Operations and Fields.

  • Operation — a method of interacting with data stored in the system.
  • Field — a data unit requested from the system or a path pointer to it.
Request example
query {
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
currencyInformation {
nominal
settlement
}
}
}

Where:

  • query is the operation type
  • instrument, basicInformation, currencyInformation and others are fields indicating the path to the requested data
note

The parameters symbol, exchange and board are required arguments of the instrument field, without which a request to it cannot be executed. See Optional components for more information about arguments.

Details about each of the components:

Operations

GraphQL API of the ALOR Broker trading system supports only one type of operations — query.

Messages of this operation type provide a one-time interaction with the server and are used to retrieve data from the system. HTTP is used as a transport protocol for this type of operations. In terms of functionality, operations of this type are similar to GET requests to HTTP API, but actually sending as POST requests.

To specify the type of operation, add it to the root level of the request.

Requirements, restrictions, recommendations
  • You may not specify the operation type if the request body contains only one operation that does not use variables and directives. Otherwise, the operation type must be specified
  • To add arguments (e.g., variable declarations) to the root of the request, the operation must be named

Fields

Fields are the basis of a GraphQL query. Fields describe both the data itself, to which the query is addressed, and the path to them. For convenience, you can categorize them as follows:

  • Data field — a field that directly indicates the data that can be requested from the system
  • Path field — path pointer to the data field according to the schema structure
Request example
query {
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
currencyInformation {
nominal
settlement
}
}
}

Both types of fields are presented in the query above:

  • instrument, basicInformation and currencyInformation - path fields that have their own attachments and specify the path to the data according to the schema structure
  • description, shortName and others - data fields defining the data itself to be returned by the server.

In the schema, fields can be represented as type, object or interface (or their contents) depending on the role of the field in the data structure.

So, for example, the query above includes interface Instrument, type BasicInformation, type CurrencyInformation and their contents.

Requirements, restrictions, recommendations
  • At least one data field must be specified in the body of the query
  • All path fields that constitute a path to a data field must be specified in the body of the query according to the following scheme

Optional components

In addition to the required components that describe the structure of the requested data, GraphQL also supports a number of additional parameters that simplify the work with the system:

  • Operation name — the ability to assign a unique name to an operation. Naming operations not only helps to distinguish different operations from each other in the system, but is also required to use some other language features, such as variables assignment.
  • Argument — an additional query parameter that specifies data search or limits its output.
  • Alias — the name of a field, object or interface specified by the sender of the request, under which the system will return the requested data instead of the one defined by the system.
  • Variable — a parameterization feature that allows to specify and pass argument values not directly in the operation body, but using a special variable dictionary.
  • Fragment — a programmer's tool allowing to reuse fields, objects and interfaces in several queries without having to specify them for each query separately.
  • Directive — a dynamic query management tool that defines the actions and conditions to be performed within an operation according to the data passed.
Required optional component

In some cases arguments may be required to execute a request. If an object, interface or operation in the schema has arguments with an exclamation mark ! after the value format - this argument is required and the request will not be executed without it.

Request example
query customQueryName($customSymbolName1: String!, $customSymbolName2: String!, $getBasicInfo: Boolean!, $getCurrencyInfo: Boolean!) {
CustomInstrument1: instrument(symbol: $customSymbolName1, exchange: "MOEX", board: "TQBR") {
basicInformation @include(if: $getBasicInfo) {
...basicInfoSelectionSet
}
currencyInformation @include(if: $getCurrencyInfo) {
...currencyInfoSelectionSet
}
}
CustomInstrument2: instrument(symbol: $customSymbolName2, exchange: "MOEX", board: "TQBR") {
basicInformation @include(if: $getBasicInfo) {
...basicInfoSelectionSet
}
currencyInformation @include(if: $getCurrencyInfo) {
...currencyInfoSelectionSet
}
}
}
fragment basicInfoSelectionSet on BasicInformation {
description
shortName
type
market
}
fragment currencyInfoSelectionSet on CurrencyInformation {
settlement
nominal
}
Variable dictionary example
{
"customSymbolName1": "SBER",
"customSymbolName2": "VTBR",
"getBasicInfo": true,
"getCurrencyInfo": false
}

Where:

  • $customQueryName is the name of the operation
  • $customSymbolName1, $customSymbolName2, $getBasicInfo and $getCurrencyInfo - variables whose values are substituted into the text of the request when it is processed by the system. The values of the variables are specified in a special variable dictionary in JSON format
  • CustomInstrument1 and CustomInstrument2 - aliases of instrument interface, allowing to get data on the same fields for different instruments in one request.
  • basicInfoSelectionSet and currencyInfoSelectionSet - fragments allowing to reuse strings included in BasicInformation and CurrencyInformation objects in several interfaces
  • @include(if: $getBasicInfo) and @include(if: $getCurrencyInfo) - directives indicating the addition of BasicInformation and CurrencyInformation objects depending on the values of the $getBasicInfo and $getCurrencyInfo variables
  • Everything enclosed in parentheses are arguments of the involved objects, interfaces and operations

More details about each of the components:

Operation name

You can assign a unique name to each operation in a message sent to the system. Assigning a name to an operation is useful when you want to:

  • Declare variables in an operation that should be set as arguments to the operation name
  • Pass multiple operations in one document which can be identified by their name

Variable declaration is described below, so here we will focus on identifying multiple operations in a single document.

A document in GraphQL is a message body that contains all the payload that the server should process, except for variable values, which are transmitted in a separate dictionary.

A single document can contain several unrelated operations that can be transmitted one at a time or all at once. Assigning a unique name to an operation allows it to be identified among others and only those operations that meet the current needs can be passed.

Operation names are not dependent on the schema and should be defined by the user. The names of operations predefined in the scheme should be considered by the user as a necessity caused by the scheme structure or as a variant of designation of a specific operation.

To give a name to an operation, simply specify it after the operation type:

Request example
query Instrument {
instrument(symbol: SBER, exchange: MOEX, board: TQBR) {
basicInformation {
...
}
}
}

Where Instrument is the operation name

Requirements, restrictions, recommendations
  • Each operation name must be unique for a document
  • The number of operation names per document is not limited.
  • The given name must not repeat the names of other GraphQL query components, schema or service elements (e.g. type).

Arguments

Arguments allow you to specify additional parameters for an operation or field. In the case of fields, such additional parameters allow you to specify or limit the data returned by the system, while for operations, arguments allow you to declare the variables used in the query. The closest analog of arguments in GraphQL is Query-parameters in requests to HTTP API.

For fields, the list of available arguments is defined by the schema and is enclosed in parentheses:

Schema example
instrument(symbol: String!, exchange: String!, board: String!): Instrument

Where:

  • Instrument — the interface whose fields will be used when the system searches for data and composes a response
  • instrument — alias, which is used to call the interface. This alias acts as a field in the query
  • symbol, exchange, board — arguments of the alias to refine the query
  • String — data format to which the passed value should correspond.

According to the scheme, a query with arguments will look as follows:

Request example
{
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
...
}
}
}

The format in which the arguments are written in the schema does not matter:

Schema example
instruments(
includeOld: Boolean! = false
includeNonBaseBoards: Boolean! = false
first: Int
after: String
last: Int
before: String
where: InstrumentModelFilterInput
order: [InstrumentModelSortInput!]
): InstrumentsConnection

Where:

  • InstrumentsConnection — the type whose fields will be used when the system searches for data and composes a response
  • instruments — alias by which the type is called
  • includeOld, includeNonBaseBoards, first, after, last, before, where and order — arguments of the alias for query refinement

All arguments in the query can be set to a single line as well:

Request example
{
instruments(includeOld: false, includeNonBaseBoards: false, last: 50, order: ) {
totalCount
nodes {
basicInformation {
...
}
}
}
}

Arguments can be either required or optional. Without required parameters, the query will not be executed as the system will not receive enough data to compose a response. Optional parameters allow you to refine a functional query or apply additional sorting or filtering settings to it.

The required nature of the argument is indicated in the scheme by an exclamation mark ! when specifying the data format of the expected value. If it is not present — the argument is optional.

So, for example, in the schema above, the arguments includeOld and includeNonBaseBoards are required, when arguments such as before and after can be ignored.

Predefined values

Some arguments in the schema may be given a default value, specified after the equal sign =. Such arguments are still required, but they do not have to be specified in the query — in this case the predefined value will be used.

For example, the argument includeOld: Boolean! = false is required, but it has a default value. If the pre-defined value is appropriate for the task, this argument can be omitted.

Requirements, restrictions, recommendations
  • The argument name must be specified in the query in full conformance with the spelling in the schema. Before and before are different arguments
  • Arguments can be assigned to fields and operations only. Aliases do not have their own arguments
  • Arguments with an exclamation mark ! are required and a value must be specified for them in order to execute the query
  • An argument can be given a default value, allowing the argument to be omitted from the query if the predefined value is appropriate for the task.

Aliases

Aliases allow you to give a custom name for a field under which the system will return the requested data. This can be useful when the same field occurs several times in the same request, or when the client application that sent the request expects to receive data under specific names in the response.

Aliases are not directly schema-dependent and are user-defined. The aliases predefined in the schema should be treated by the user as regular fields.

Suppose there is a task to get data on the same fields for SBER and VTBR instruments simultaneously within one operation. If we simply duplicate the object instrument:

Request example
query {
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
instrument(symbol: "VTBR", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
}

When receiving data, an error of merging the received data will happen. The reason is the same instrument name for both tickers.

In this case, you can give each of the instrument fields an alias, making them unique:

Request example
query {
Instrument1: instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
Instrument2: instrument(symbol: "VTBR", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
}

Where:

  • instrument — invoked field
  • Instrument1 and Instrument2 — user-defined aliases to split data of the instrument field

So, by giving the object with ticker SBER the alias instrument1 and the object VTBR the alias instrument2, objects with unique names were created whose data would not conflict when merged.

Requirements, constraints, recommendations
  • The number of aliases in one query is not limited
  • Each alias must be unique
  • The alias must not repeat component names that already appear in the schema or service names of GraphQL components (e.g. type).

Fragments

Some field sets may be used multiple times in the same document, which causes an increase in network load from bigger data packets being transmitted, and also makes it difficult to read and modify the document. Fragments allow you to optimize the body of the document by replacing the duplication of the entire field set with a single pointer to the set outside the operation area.

To declare a new fragment, you must take it out of any operations in the document, declare it using the fragment operator, name it, give it an origin, and specify its contents.

For example, to create a fragment from the basicInformation field included in Instrument and some of its constituent fields, the following object must be added to the body of the request:

Fragment example
fragment basicInfoFragment	on	Instrument {
basicInformation {
description
shortName
type
market
}
}

Where:

  • fragment - operator that declares an object in the document as a fragment
  • basicInfoFragment - unique fragment name
  • Instrument - interface-referenced field that will contain the fragment
  • basicInformation, description, shortName, type, market - fields that make up the fragment

To use the created fragment in an operation, add the fragment name with the prefix ... to the body of the operation:

Fragment pointer example
query {
instrument1: instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
...basicInfoFragment
}
}

So a document with repeating fields like this (681 bytes UTF-8):

Request example
query {
instrument1: instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
instrument2: instrument(symbol: "VTBR", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
instrument3: instrument(symbol: "TCSG", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
instrument4: instrument(symbol: "SVCB", exchange: "MOEX", board: "TQBR") {
basicInformation {
description
shortName
type
market
}
}
}

Using a fragment can be converted like this (581 bytes UTF-8):

Fragmented request example
query {
instrument1: instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
...basicInfoFragment
}
instrument2: instrument(symbol: "LKOH", exchange: "MOEX", board: "TQBR") {
...basicInfoFragment
}
instrument3: instrument(symbol: "TCSG", exchange: "MOEX", board: "TQBR") {
...basicInfoFragment
}
instrument4: instrument(symbol: "SVCB", exchange: "MOEX", board: "TQBR") {
...basicInfoFragment
}
}
fragment basicInfoFragment on Instrument {
basicInformation {
description
shortName
type
market
}
}

When declaring a fragment, it is important to structurally designate the order of fields to be substituted in the query. Thus, if the hierarchy of the extracted fields is a nesting of the field instrument, when declaring a fragment, the target for it should be declared as this field.

In addition, GraphQL supports the creation of compound fragments, in which one fragment refers to another. For example:

Request example
query GetBasicInfo {
instrument(symbol: "SBER", board: "TQBR", exchange: "MOEX") {
...getBasicInfoFragment
}
}
fragment getBasicInfoFragment on Instrument {
basicInformation {
symbol
...getDescriptionFragment
...getMarketFragment

}
}
fragment getDescriptionFragment on BasicInformation {
shortName
description
}
fragment getMarketFragment on BasicInformation {
market
type
}

Where:

  • getBasicInfoFragment — the fragment used in the body of the operation and containing the lower-level fragments within it
  • getDescriptionFragment and getMarketFragment — low-level fragments included in getBasicInfoFragment and containing data fields
  • symbol — data field placed in the getBasicInfoFragment fragment along with low-level fragments.
Requirements, limitations, recommendations
  • The number of fragments in one document is not limited
  • Each fragment must have a unique name
  • The fragment name must not repeat the names of components that already appear in the schema, or service names of GraphQL components (for example, type or on).
  • The fragment must be composed and placed in the body of the operation according to the hierarchy defined by the schema structure.
  • The fragment must not be used in objects to which its contents do not correspond
  • A fragment must contain a type, object or interface. Fragments consisting only of data fields must not be created.
  • A fragment can contain arguments of its fields, but it cannot be assigned with its own arguments.
  • You can use variables in fragments, but you cannot use variables to set the fragment name.
  • A fragment declared in a document must be used in at least one operation
  • Compound fragments must not form a loop by recursively referring to each other.

Variables

Specifying data statically in a query is sufficient when it concerns test interactions or single shot queries. In practical use it becomes more difficult to change the values in the entire operation every time new inputs need to be passed.

Instead of statically specified data, you can use variables whose values will be substituted into the query automatically.

To specify a variable:

  1. Declare a variable with the required data format for the value to be passed in the operation arguments
  2. Place the variable in the operation body
  3. Declare the value of the variable in the variable dictionary
Prefix

Variable dictionary contains only the name of the variable. In the name and body of the operation, this name must be prefixed with $.

To declare a variable in an operation, give it a unique name and in the arguments to it, declare the name of the variable to be added and the data format to which the value should correspond:

Request example
query QueryWithVariable($symbolvar: String) {
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
...
}
}

Where $symbolvar: String is the symbolvar variable with String data format

GraphQL accepts the following options as possible data formats:

  • String
  • Int
  • Float
  • Boolean

Like the predefined arguments in the schema, variables declared in the operation name can be made required - the operation will not be executed if the variable is not assigned a value matching the specified data format:

Request example
query QueryWithVariable($symbolvar: String!) {
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
...
}
}

Where $symbolvar: String! is the symbolvar variable with String data format and ! pointer indicating that this variable is required.

Variables and arguments

If a variable replaces the value of an argument from a schema with the value of an argument, the properties of the argument must be fully inherited by that variable. For example, if the argument expects String!, the variable cannot be set to String.

To place a variable in the body of an operation, add its name with a prefix instead of a static value:

Request example
query QueryWithVariable($symbolvar: String!) {
instrument(symbol: $symbolvar, exchange: "MOEX", board: "TQBR") {
...
}
}

Where:

  • $symbolvar: String! — declaration of a variable with a data format in the operation's arguments
  • symbol: $symbolvar — placement of the variable as a value for the symbol argument

The variable dictionary is a separate entity whose format depends on the selected transport protocol (most often JSON). To declare a variable in the dictionary, add its name with a new line and specify its value:

Variable in dictionary
{
"symbolvar": "SBER"
}
Requirements, limitations, recommendations
  • The number of variables in one document is not limited
  • Each variable must have a unique name
  • The variable name must not repeat the names of components that already appear in the schema or service names of GraphQL components.
  • If a variable is used to pass an argument value, it must inherit all properties of the expected argument value from the schema
  • A variable declared in a dictionary must be used at least once in the body of an operation.
  • Variables can be used inside fragments, but cannot be used to pass the fragment name
  • Variables placed in unused fragments are considered unused.
  • Variables can be used to pass integer objects, but should not be considered as a substitute for fragments.

Directives

Some tasks may require temporarily changing a set of fields in an already generated query. Such tasks can be solved by creating several separate operations or by introducing directives into the operation body.

Directives allow you to create alternative scenarios for executing the same operation without having to manually modify the entire operation body. GraphQL currently supports two types of directives:

  • @include - include the contents of the directive in the query
  • @skip - exclude the contents of the directive from the query

To declare a directive, add its key together with the execution condition as an argument to the operation body:

Request example
query { 
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation @include(if: $getBasicInfo) {
...
}
currencyInformation @skip(if: $getCurrencyInfo) {
...
}
}
}

Where:

  • @include and @skip — directive keys
  • if: $getBasicInfo and if: $getCurrencyInfo — conditions of directives execution

Variables are used as a condition for executing a directive and must be declared in accordance with the rules applied to them. A correctly composed operation body will look like this:

Request example
query QueryWithDirectives($getBasicInfo: Boolean!, $getCurrencyInfo: Boolean!) { 
instrument(symbol: "SBER", exchange: "MOEX", board: "TQBR") {
basicInformation @include(if: $getBasicInfo) {
...
}
currencyInformation @skip(if: $getCurrencyInfo) {
...
}
}
}
Variable dictionary
{
"getBasicInfo": true,
"getCurrencyInfo": false
}

In the example above, the contents of the basicInformation and currencyInformation fields will be included in the response, since the condition is met for @include (control variable value true) and not for @skip (variable value false).

Requirements, restrictions, recommendations
  • The number of directives in one document is not limited
  • Variables are used to manage directives, which obey their own requirements to the fullest extent
  • Directive keys are schema-dependent and cannot be declared by the user independently
  • Directives can be placed in fragments, as well as fragments can be set as contents of directives.
  • You cannot place multiple directives for the same field, nor can you specify multiple arguments for a single directive. Variants of writing basicInformation @include(if: $getBasicInfo) @include(if: $getCurrencyInfo) or basicInformation @include(if: $getBasicInfo, $getCurrencyInfo) will be reported as a syntax error
  • A single variable can control multiple directives at the same time

What's next?

Additionally, we recommend reading the following related articles: