Roman Klimenko
DA

Using CluedIn GraphQL API to automate UI actions

As a Master Data Management system, CluedIn lets users work with data through a UI and low-code tools. You can complete the full data lifecycle, from ingestion through modeling, transformation, cleaning, enrichment, deduplication, and export, without writing a line of code.

Some work is still easier to automate. A small script can spare business users repetitive UI tasks, especially when you need to keep development, staging, and production instances in sync through a CI/CD pipeline.

In this article, we'll build basic automation without knowing the API in advance. Our starting point is that the CluedIn UI communicates with the server through a GraphQL API.

Two GraphQL API endpoints

CluedIn provides two GraphQL API endpoints:

  • /api/api/graphql: The endpoint used to query data.
  • /graphql: The endpoint used for UI interactions.

Authentication

CluedIn uses JSON Web Tokens (JWT) for authorization.

There are two kinds of tokens in CluedIn: API Tokens and Access Tokens.

API Tokens are used to extract data from CluedIn or ingest data into it. You can create or copy one from Administration -> API Tokens.

Access Tokens are generated when you log in to CluedIn as a user.

You need an API Token to use the /api/api/graphql endpoint.

The /graphql endpoint only accepts Access Tokens, so you must log in with your email and password to obtain one.

The article Using Postman to interact with the CluedIn API explains how to obtain an Access Token with Postman.

For data queries with the Python SDK, see Search Entities with CluedIn Python SDK.

Exploring GraphQL API

We'll automate an action normally performed in the UI by using the CluedIn GraphQL API and CluedIn Python SDK.

Suppose you need to synchronize Vocabularies from another system. You could create each one in the CluedIn UI, but this is a good task to automate.

Start by creating a test Vocabulary in the browser and watching the API requests. You can use the Network tab or GraphQL Network Inspector. I find GraphQL Network Inspector easier.

I'll show both approaches. First, I create a test CluedIn Vocabulary while the Network tab is open:

Vocabulary Network tab

Among the GraphQL requests, I can see a call to the createVocabulary mutation:

Network tab

GraphQL Network Inspector makes the call easier to find:

GraphQL Inspector

Either way, we can now copy the GraphQL query:

mutation createVocabulary($vocabulary: InputVocabulary) {
  management {
    id
    createVocabulary(vocabulary: $vocabulary) {
      ...Vocabulary
      __typename
    }
    __typename
  }
}

fragment Vocabulary on Vocabulary {
  vocabularyId
  vocabularyName
  keyPrefix
  isCluedInCore
  entityTypeConfiguration {
    icon
    entityType
    displayName
    __typename
  }
  isDynamic
  isProvider
  isActive
  grouping
  createdAt
  providerId
  description
  connector {
    id
    name
    about
    icon
    __typename
  }
  __typename
}

The request also includes these variables:

{
  "vocabulary": {
    "vocabularyName": "Test",
    "entityTypeConfiguration": {
      "new": false,
      "icon": "Profile",
      "entityType": "/IMDb/Name",
      "displayName": "IMDb Name"
    },
    "providerId": "",
    "keyPrefix": "test",
    "description": ""
  }
}

Python SDK

We can now use the CluedIn Python SDK to create a Vocabulary.

I start by creating a file with my CluedIn credentials. You can provide them through environment variables instead:

{
  "domain": "172.167.52.102.sslip.io",
  "org_name": "foobar",
  "user_email": "admin@foobar.com",
  "user_password": "mysecretpassword"
}

Then I install the CluedIn Python SDK:

%pip install cluedin

Next I log in to CluedIn to get an Access Token:

import cluedin

ctx = cluedin.Context.from_json_file('cluedin.json')
ctx.get_token()

The ctx object now contains the Access Token and can be used to create a Vocabulary:

def create_vocabulary(ctx, name, prefix):
  query = """
mutation createVocabulary($vocabulary: InputVocabulary) {
  management {
    id
    createVocabulary(vocabulary: $vocabulary) {
      ...Vocabulary
    }
  }
}
fragment Vocabulary on Vocabulary {
  vocabularyId
  vocabularyName
  keyPrefix
  entityTypeConfiguration {
    icon
    entityType
    displayName
  }
  providerId
  description
}
"""

  variables = {
    "vocabulary": {
      "vocabularyName": name,
      "entityTypeConfiguration": {
        "new": False,
        "icon": "Profile",
        "entityType": "/IMDb/Name",
        "displayName": "IMDb Name"
      },
      "providerId": "",
      "keyPrefix": prefix,
      "description": ""
    }
  }

  return cluedin.gql.org_gql(ctx, query, variables)

Call the function:

print(create_vocabulary(ctx, 'Foo Bar', 'foo.bar'))

Output:

{
  "data": {
    "management": {
      "id": "management",
      "createVocabulary": {
        "vocabularyId": "e4528e92-f4ad-406a-aeab-756acc20fd01",
        "vocabularyName": "Foo Bar",
        "keyPrefix": "foo.bar",
        "entityTypeConfiguration": {
          "icon": "Profile",
          "entityType": "/IMDb/Name",
          "displayName": "IMDb Name"
        },
        "providerId": null,
        "description": ""
      }
    }
  }
}

The new Vocabulary appears in the UI:

New Vocabulary

I've used the same approach in real projects, for example to: