Skip to content

API and subscriptions

This section describes general principles how the data within the Platform can be accessed and modified. We provide an overview of the API structure in this part of the document. For the detailed information on the exact query calls and specific description of the parameters for those calls please refer to the corresponding section of the documentation Pixel Core GraphQL API Specification.

Pixel Core utilises GraphQL query language to provide access to Platform data structures, functions and data feeds. This is the only standard way to access data which is stored and processed in the Platform. GraphQL is used by all Platform components to create, retrieve, update, delete or subscribe to data updates. One still can use direct access to PostgreSQL database backing the Platform and issue SQL queries directly, but we strongly don’t recommend going this path and only do this if it is not possible to implement what you are looking for via standard GraphQL API.

Pixel Core GraphQL API as a regular GraphQL API consists of 3 types of the queries:

  • Queries
  • Mutations
  • Subscriptions

Authorization

To be able to access the Platform API one needs to pass through the authorisation process. Authorization in PixelCore is token based and supports two types of tokens: refresh and access token which is a commonly used pattern.

Refresh token

Refresh token is generated in return to the presented valid login/password. Refresh token has relatively long validity duration (default is 30 days) and can be used to get access token. Refresh token doesn’t allow one to get access to API except authorisation functions. The validity of a refresh token is expressed in days and can be in the range of 1 to 100 and can be configured per User using Admin UI or API. Once a user successfully obtains a refresh token it can initiate another query to get access token which opens up full access to the API.

POST request to http://your-domain.com/graphql

Request:
mutation RefreshToken{
  authRefreshToken(
    input: {
      userLogin: "admin",
      userPassword: "jNuYeIBrKLXzLjXAaYBOHslda1SVifP-"
    }
  ){
    clientMutationId
    refreshToken {
      token
      id
    }
  }
}
Response:
{
  "data": {
    "authRefreshToken": {
      "clientMutationId": null,
      "refreshToken": {
        "token": "YjhmNGNiNTMxMmI3MzM0MWZkYzZlNzBiNzQ5MzFlNjU=",
        "id": "21"
      }
    }
  }
}

Important

There are two type of Users in the Platform: User and App. Apps can have only one valid refresh token at a time. That means that multiple (or few instance of the same) Apps are not supposed to reuse same login/password pair. During Refresh token authorisation for an App, the Platform would delete all existing Refresh tokens for that App (including valid ones) present in the Platform, before generating a new one. That would automatically close all open subscription connections for such App as well. This logic is not applied to Users of type User. Users are allowed to have multiple valid Refresh tokens.

Access token

Access token is generated in return to the presented valid refresh token. Usually validity duration of access token is significantly shorter than lifetime of refresh token (default is 5 mins). That means that the same refresh token can be used to get multiple access tokens in a row. At the same time refresh token being stored in the Platform can be revoked and this can be used to force related users to go through full scale login procedure. At the moment the refresh tokens are automatically cancelled based on some changes with PixelCore Users, like change of password and disable of a User. The validity of an access token is expressed in minutes and can be in the range of 1 to 599 and can be configured per token via API on each access token request.

Beside refresh token and required access token validity, one can provide an optional parameter to indicate which application user is trying to get access to. This information would be used by PixelCore to set up a User Application Profile (please refer to the corresponding section of the documentation for further details on profiles).

POST request to http://your-domain.com/graphql

Request:
mutation AuthToken{
  authAccessToken(
    input: {
      userRefreshToken: "YjhmNGNiNTMxMmI3MzM0MWZkYzZlNzBiNzQ5MzFlNjU=",
      application: "admin",
      accessTokenExpiration: 599
    }
  ){
    clientMutationId
    jwtToken
  }
}
Response:
{
  "data": {
    "authAccessToken": {
      "clientMutationId": null,
      "jwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXBwbGljYXRpb24iLCJ1c2VyX2lkIjoiMDRjMTMzNDAtYzFkZS00YzQ5LWI1NWItMjQ2MDE0ODkxYTBhIiwiZ3JvdXBfaWQiOiJ7NWQ5NjNlYTEtY2RmMi00ZTY2LThmOTgtYmMwN2Q1ZjNlYTA3fSIsImV4cCI6MTYxNDIyMTU0MSwiaWQiOiIxNjUiLCJhcHBsaWNhdGlvbiI6ImFkbWluIiwicHJvZmlsZV9pZCI6IjRmYWJmNmNiLTQzNzItNDNiYy04MTg1LTBkZmFkNDNmNmY0YyIsInJlZnJlc2hfdG9rZW5faWQiOiIyMSIsImlhdCI6MTYxNDE4NTYwMSwiYXVkIjoicG9zdGdyYXBoaWxlIiwiaXNzIjoicG9zdGdyYXBoaWxlIn0.wx4JKCt4uoPaY6AhvJns4zLT_2MHV--IpdGMrh7nNVs"
    }
  }
}

Once access token is obtained, a user can have full access to PixelCore API.

Add a header to your request.

Authorization Bearer jwtToken_value

Essentially within short time the access token would expire and a user would need to request another access token using the original refresh token. That cycle can be repeated until the refresh token would expire as well. Once the refresh token expires (or gets cancelled) a user would need to go through the standard login/password authorization process to obtain another refresh token.

Queries

Pixel Core GraphQL Queries are composed of numerous queries which allow one to request all types of the data from the Platform. Due to GraphQL nature, query results can be highly customized to meet the need of the requester in the specific data. Also if there are any relationships between the data present in the database, this information also can be leveraged in queries and in one single query one can request all connected data structures as well. That significantly simplifies use of the Platform from applications and modules development perspective.

Each type of the data described in the Platform is usually presented with 3 GraphQL queries named in a standard way. These queries can be used in different use case scenarios. For example, data entity “notification”, which is used to store and process application’s notifications has 3 corresponding GraphQL queries:

All your requests must have a header. Authorization Bearer jwtToken_value

  1. This query provides you with a list of notifications with pagination support built into the query results. This type of queries with “Connection” suffix typically used when some webpage needs to show a paginated list of corresponding data types.

    query{
      notificationsConnection(
        first: Int,
        last: Int,
        offset: Int,
        before: Cursor,
        after: Cursor,
        orderBy: PRIMARY_KEY_ASC [NotificationsOrderBy!],
        condition: NotificationCondition,
        filter: NotificationFilter
      ){
        nodes
        edges
        pageInfo
        totalCount
      }
    }
    
  2. This query provides you with a list of notifications without pagination support, however all other features (filtering, ordering, offset) are still present. This type of queries is typically used inside non-UI oriented modules and software components .

    query{
      notifications(
        first: Int,
        offset: Int,
        orderBy: [NotificationsOrderBy!],
        condition: NotificationCondition,
        filter: NotificationFilter
      ){
        nodeId
        id
        actorType
        actor
        actorName
        tags
        message
        createdAt
        by
        userByBy
      }
    }
    
  3. This query as a result provides you with detailed description of specified data type (notification in this case) identified with provided UUID.

    query{
      notification(
        id: UUID!
      ){
        nodeId
        id
        actorType
        actor
        actorName
        tags
        message
        createdAt
        by
        userByBy
      }
    }
    

All other data types present in the Platform and described in sections above have corresponding GraphQL queries associated with it based on the approach described above.

Mutations

Pixel Core GraphQL Mutation queries are used to modify data presented in the Platform. Mutations are also used to represent other functions (API methods) which allow applications or modules to call those specific functions.

Data modifications

All data types presented in the Platform can be modified using create, update and delete mutations. Create, update and delete mutations present in two implementations: single data mutation and multiple data mutation. Multiple data mutations are useful for bulk processing (for example for bulk delete) but multiple data mutations are present only for certain data types. Single data mutations can operate only with a single instance of the data type. For example, data type “notification”, which is used to store and process application’s notifications has following GraphQL mutations:

All your requests must have a header. Authorization Bearer jwtToken_value

  1. Creates a single Notification.

    mutation{
      createNotification(
        input: CreateNotificationInput!
      ){
        clientMutationId
        notification
        query
        userByBy
        notificationEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    
  2. Updates a single Notification using a unique key and a patch.

    mutation{
      updateNotification(
        input: UpdateNotificationInput!
      ){
        clientMutationId
        notification
        query
        userByBy
        notificationEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    }
    
  3. Deletes a single Notification using a unique key.

    mutation{
      deleteNotification(
        input: DeleteNotificationInput!
      ){
        clientMutationId
        notification
        deletedNotificationNodeId
        query
        userByBy
        notificationEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    }
    

“User” data type beside single mutations has a multiple mutations per below:

  1. Creates one or many Users.

    mutation{
      mnCreateUser(
        input: mnCreateUserInput!
      ){
        clientMutationId
        user
        query
        userGroupByEditorgroup
        userGroupByUsergroup
        userGroupByReadergroup
        userByBy
        userEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    }
    
  2. Updates one or many Users using a unique key and a patch.

    mutation{
      mnUpdateUser(
        input: mnUpdateUserInput!
      ){
        clientMutationId
        user
        query
        userGroupByEditorgroup
        userGroupByUsergroup
        userGroupByReadergroup
        userByBy
        userEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    }
    
  3. Deletes one or many Users a unique key via a patch.

    mutation{
      mnDeleteUser(
        input: mnDeleteUserInput!
      ){
        clientMutationId
        user
        deletedUserNodeId
        query
        userGroupByEditorgroup
        userGroupByUsergroup
        userGroupByReadergroup
        userByBy
        userEdge(
          orderBy: PRIMARY_KEY_ASC
        )
      }
    }
    

Bulk or multiple mutations have “mn” prefix and can take data arrays as arguments.

Beside data modification mutations there are also some specific functions exported as GraphQL mutations as well. Those mutations are regular function calls which provide certain functionality. For example, one of these functions is authentication function, which allows one to get authentication token to access the Platform:

mutation{
  getRefreshTokenId(
    input: GetRefreshTokenIdInput!
  ){
    clientMutationId
    string
    query
  }
}

Authenticate with login and password.

Subscriptions

PixelCore utilises GraphQL Subscription mechanism to generate a live stream of events happening within the Platform. GraphQL Subscriptions are implemented on top of a Websocket connection and provide a structured stream of data to which standard GraphQL query language constructions can be applied. There is only one single query in this section which is used to establish connection (to subscribe):

subscription{
  listen(
    topic: String!
  ){
    query
    relatedNode
    relatedNodeId
  }
}

There are several topics at the moment supported by the Platform which one can subscribe to. Before subscribing one needs to get authorized via authenticate GraphQL Mutation. Below you may find the list of available topics:

  • Objects (objects). This topic is used to publish updates on all changes happening to Objects (all types) and to Object Properties. All subscribers eligible to see data of corresponding objects would receive the message.
  • Notifications (notifications). This topic is used to publish updates on all changes happening to Notifications and Notification Deliveries. All subscribers eligible to see notifications on corresponding objects would receive the message.
  • Controls (controls). This topic is used to publish updates on all changes happening to Controls (RPC calls). RPC calls are unicast (one-to-one) messages so only one receiver (or none) would receive the corresponding call information.
  • Miscellaneous (misc). This topic is used to publish updates on all changes happening to several data entities within the Platform. At the moment following data entities are included: Users, User Groups.

Topic names

To be able to subscribe to one of the topics above you would need to provide a valid topic String which should be used as an argument for “listen” GraphQL Subscription query. One would need to decide which topic you want to subscribe to based on the description in the previous section.

Below you may find the list of available topic names which can be used to compose a valid topic name for subscription:

  • objects
  • notifications
  • misc
  • controls

All topic names have to be complemented with a unique RefreshToken ID (thus composing full topic name) which would create a unique communication channel for every authorized user. The need for things to be organized that way is that PixelCore supports data access permissions model and changes of the same Object (for example) not necessarily have to be propagated to all subscribers. To be able to implement this we need to maintain unique communication channels with each authorized user. This is achieved with using following topic name format:

<topic>:<refresh_token_id>

where topic is one of the available topics above and RefreshTokenID can be acquired via getRefreshTokenID GraphQL API call. Below you may find few examples of valid topic names for reference:

controls:1841, subscription to controls, getRefreshTokenID returned 1841
objects:138, subscription to objects, getRefreshTokenID returned 138
notifications:1931, subscription to notifications, getRefreshTokenID returned 1931
misc:781, subscription to misc, getRefreshTokenID returned 781