Build your own content catalogue interface (using GraphQL)

Enable your customers to discover and select the content they want to deliver to their team, by building your own content catalogue interface using our GraphQL API.

Overview

This guide explores how to create your own content catalogue interface – with the purpose of surfacing the Go1 library within your application using the Discover and Search GraphQL endpoints.

Building a content catalogue like experience within your application is core to how your users will discover and interact with Go1 content. There are various use-cases the content catalogue you build may support, some examples include:

  • For Admins, a curation storefront for customers to discover & select the content they would like to add to your platform.
  • For Learners, a direct user-facing content library, for learners to explore and enrol in self-directed learning.

The solution you build will depend on the integrated experience you are looking to create within your platform. The steps in this guide will provide you with the necessary knowledge you need to support your scenario of choice.

The benefit to building your own content catalogue interface via the GraphQL API (as appose to using the Embeddable Go1 Catalogue) is the flexibility you have to customise the user experience and interface you present to users within your application.

Using GraphQL vs the Rest API

GraphQL is a query language created by Facebook in 2012 and it is intended to provide an alternative to conventional REST API architecture. It uses a query language that describes how to request data (called a Schema) and what the expected returns should include. The core difference is that GraphQL is designed to have one endpoint per page (front-end interface), instead of one for each microservice. This reduces complexity and development effort tremendously. Most of the business logic has been abstracted away into the GraphQL layer and the client only needs to worry about how to display the data.

GraphQL has many benefits over the traditional REST APIs. One of the key advantages is that clients are able to describe precisely what they expect from the server and are able to access the data in a consistent manner. Only data that is requested, will be returned, saving loading time. Retrieve many resources in a single request and the GraphQL server will return a JSON string, containing all the data necessary to render the screen. Go1's GraphQL endpoint enables the rapid development of integrations.

For further reading on the GraphQL spec see the documentation below:

How it works

The purpose of our GraphQL API is to enable you to rapidly surface Go1 content within your application. We'll explore how this works using our GraphQL endpoints and documentation below.

We'll also walk through some example implementation steps below, that you can follow as a guide to building your own catalogue. The steps we'll walk through are as follows:

  1. Building a content discovery landing page
  2. Adding search
  3. Adding pagination
  4. Adding sorting preference
  5. Adding filters

You should consider these steps as an entry-level guide to get you started with our GraphQL API. Ultimately, the interfaces you create with the GraphQL API may differ from these guides, depending on your use case and the user experience you are looking to create within your application.

Endpoints available with GraphQL

There are two endpoints available within our GraphQL API - discover() and search(). We'll be touching on each of these endpoints further in the implementation steps of this guide. If you want to learn more about these endpoints and how they work, select the heading links below.

discover()
The discover endpoint provides a way to display content recommendations grouped by categories and topics. It is commonly used to surface a content discovery landing page with topic carousels, to provide an overview and entry point to browse the content offering.

search()
The search endpoint provides a mechanism to search and filter the content library. It returns a list of learning objects and their metadata as well as available filtering and sorting options.


GraphQL API Reference & Test Playground

To review the entire API Reference for our GraphQL API and to test the endpoints in real-time, you can access our Apollo Playground, which is an open environment connected to our GraphQL server: https://api.go1.com/v2/graphql/query.

null

To use the Playground environment to send requests and see the API Schema, you'll first need to enter a valid access_token to the Playground tool. To do this, copy the code snippet below to the "HTTP HEADERS" tab in the bottom left corner, including your access_token. For guides on how to retrieve an access token, see our Authentication page. Note, your access token will require the following scopes - user.read, user.write, enrollment.read, enrollment.write.

{ 
  "Authorization": "Bearer <ACCESS_TOKEN>" 
}

Once you have added your token, you will be able to access the Schema tab on the left-hand side of the page to see the entire API Reference for the GraphQL API. To see some examples of the queries you can make within the Playground tool, see our discover() and search() documentation.

Implementation Steps

The following steps provide an example of how you can build your own catalogue using the GraphQL discover() and search() endpoints. The purpose of these steps is to provide an example and guideline that you can follow, however, your implementation of these endpoints may differ depending on your scenario and the user experience you are looking to create in your application.

Step 1. Building a content discovery landing page

This step will discuss using the discover() endpoint to create a discovery landing page - as a way to display content recommendations grouped by categories and topics. The discovery landing page acts as the entry point for users to browse the content library through a series of topic carousels.

Here is an example screenshot of the discover landing page interface that you can build using this GraphQL endpoint:

null

Here is the example request used to create this interface:

query {
  discover(
    blocks:[
      {type: TopicCarousel, data: L1_TOPICS},
      {type: TopicCarousel, data: TOP_TOPICS},
      {type: LearningCarousel, data: USE_FILTERS, filters: {topic: "Project Management"}, names:"Top learning in Project Management", sort: {field:POPULAR, direction:DESC} },  
      {type: LearningCarousel, data: USE_FILTERS, filters: {topic: "Leadership"}, names:"Top learning in Leadership", sort: {field:POPULAR, direction:DESC} },
      {type: LearningCarousel, data: USE_FILTERS, filters: {}, names:"Popular content", sort: {field:POPULAR, direction:DESC} },
      {type: LearningCarousel, data: USE_FILTERS, filters: {}, names:"New content", sort: {field:CREATED, direction:DESC} }
    ]
    context: { appId: "partnerName", language: "en", region: GLOBAL }
  ) {
   blocks {
      ...on TopicCarousel {
        title
        items {
          id
          parentId
          name
          level
        }
      },
      ...on LearningCarousel {
        title
        metadata {
          name
          topic {
              id
              name
          }
        }
        response(first:5) {
          edges {
            node {
              ... on CourseCard {
                  id
                  image
                  title
                  type
                  duration
                  provider {
                    name
                  }
                }
            }
          }
        }
      }
    }
  }
}

Let's examine the request above in more detail. Firstly, the discover query expects two arguments, blocks and context. Let's explore these below.

blocks: The blocks segment determines the 'blocks' or 'carousels' you want to display on the page. Each 'block' has a combination of 'type'  and 'data' which allows us to specify the information returned in the request. The blocks we recommend using are as follows:

  • {type: TopicCarousel, data: L1_TOPICS}, returns a carousel with Level 1 Topics, as seen in the first block of the screenshot.
  • {type: TopicCarousel, data: TOP_TOPICS}, returns a carousel of the most popular topics (ranked by the number of learning objects in each topic), as seen in the second block of the screenshot above.
  • {type: LearningCarousel, data: USE_FILTERS}, returns a learning object carousel (a list of learning objects) based on the filters provided in the request. eg,
    - {type: LearningCarousel, data: USE_FILTERS, filters: {topic: "Project Management"}, names:"Top learning in Project Management", sort: {field:POPULAR, direction:DESC} }, this returns a list of learning objects filtered to the topic 'Project Management', sorted with the most popular learning objects displaying first. See the third block in the screenshot above as an example. For a list of all available topics -
    - {type: LearningCarousel, data: USE_FILTERS, filters: {}, names:"Popular content", sort: {field:POPULAR, direction:DESC} }, this returns all learning objects available, sorted by the most popular objects returning first. See the 5th block in the screenshot above.
    - {type: LearningCarousel, data: USE_FILTERS, filters: {}, names:"New content", sort: {field:CREATED, direction:DESC} }, this returns all learning objects available, sorted by the newest content added to the library first. See the 6th block in the screenshot above.

context: The context segment provides context for the search and is used to improve search results to be more relevant to the individual. Here you can specify the language and the region the content is relevant to.

The additional elements that are important to understand and consider within the discover() request are as follows (reference the code snippet above for how these elements are displayed within the request):

  • ...on TopicCarousel, ...on LearningCarousel, ... on CourseCard - here you can specify how the data structures that should be returned for each block type, and what fields you would like returned. For example, in the CourseCard element, we request the Learning Object ID, image, title, type, duration and provider name. You can customise this section to only return the information you need to build your interface.
  • response(first:5) - here we can specify the number of learning objects returned within each of the LearningCarousels, to a maximum of 50 learning objects. In this example, we are requesting 5 learning objects.

To explore the full schema further, see the full API Reference via the GraphQL Playground. With these details in hand, you should now be able to construct a request that will suit your needs for the discovery landing page you want to create.

Once this request is made via the GraphQL API, the response returned will look similar to the following (note. most of the objects have been removed to shorten the response for this example):

{
  "data": {
    "discover": {
      "blocks": [
        {
          "title": "Browse by topics",
          "items": [
            {
              "id": "21",
              "parentId": "0",
              "name": "Personal Development",
              "level": 1
            }
          ]
        },
        {
          "title": "Popular topics",
          "items": [
            {
              "id": "20",
              "parentId": null,
              "name": "Health and Safety",
              "level": 0
            }
          ]
        },
        {
          "title": "Top learning in Leadership",
          "metadata": {
            "name": "Top learning in Leadership",
            "topic": null
          },
          "response": {
            "edges": [
              {
                "node": {
                  "id": "2645470",
                  "image": "https://res.cloudinary.com/go1/image/upload/q_auto,f_auto,h_720/q_auto,f_auto/v1567062600/o25fykp6xz4u08khppb5.jpg",
                  "title": "Emotional intelligence: Self-management",
                  "type": "course",
                  "duration": 20,
                  "provider": {
                    "name": "Interaction Training"
                  }
                }
              }
            ]
          }
        },
        {
          "title": "Top learning in Project Management",
          "metadata": {
            "name": "Top learning in Project Management",
            "topic": null
          },
          "response": {
            "edges": [
              {
                "node": {
                  "id": "10883506",
                  "image": "https://res.cloudinary.com/go1/image/upload/v1572422928/yrasfltkjnpkczv0pf9z.png",
                  "title": "Lean Management Course",
                  "type": "interactive",
                  "duration": 60,
                  "provider": {
                    "name": "Intellelearn"
                  }
                }
              }
            ]
          }
        },
        {
          "title": "Popular learning content",
          "metadata": {
            "name": "Popular learning content",
            "topic": null
          },
          "response": {
            "edges": [
              {
                "node": {
                  "id": "16615483",
                  "image": "https://res.cloudinary.com/go1/image/upload/v1595338529/tqibnomnqmpym2coryoa.jpg",
                  "title": "Infection Prevention and Control (Australia)",
                  "type": "interactive",
                  "duration": 20,
                  "provider": {
                    "name": "Sentrient"
                  }
                }
              }
            ]
          }
        },
        {
          "title": "Newest learning content",
          "metadata": {
            "name": "Newest learning content",
            "topic": null
          },
          "response": {
            "edges": [
              {
                "node": {
                  "id": "36266405",
                  "image": "https://res.cloudinary.com/go1/image/upload/v1632287955/lmybo8hxbrclzdycllch.jpg",
                  "title": "[Hospitality] Tasting & Recommending Wine",
                  "type": "interactive",
                  "duration": 75,
                  "provider": {
                    "name": "Small Batch Learning "
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

You can see each of the 6 requested blocks returned, and the objects within those blocks. You can then render this response in your application within your own UI.

Step 2. Adding search

Once you have the initial discovery landing page in place, where a user can browse content by categories - the next logical step is to introduce the ability for users to search for content they are interested in. This step will explore using the search() endpoint to enable users to search the library for content based on a given keyword.

For this step, we recommend implementing a search-bar component to your discovery page, and a search results page to display the learning objects that a user searches for, see the example screenshots below.

A search bar that has been added to the discovery landing page, allowing users to input search keywords:

null

A search results page, that will load the results of the user's search:

null

Here is the example request used to create the search results interface:

query {
  search(
    filters: {
      keyword: ""
      contentSet: [SUBSCRIBED]
    }
    sort: { field: RELEVANT, direction: DESC }    
    context: { appId: "partnerABC", language: "en", region: GLOBAL }
  ) {
    blocks {
      ... on SearchResult {
        response(first: 20, after: "EI_0") {
          edges {
            node {
              ... on CourseSlat {
                id
                title
                description
                rating
                tags
                duration
                image 
              }
            }
          }
        }
      }
    }
  }
}

Let's examine the search request in more detail. Firstly, the search query expects three arguments - filters, sort and context. We'll explore each of these further below.

filters: This is where we define what we want to search for and the parameters to filter our search results. There are several filtering options available, which we will discuss further in step 5 of this guide. For now, in our code snippet example above, the filter argument includes the following filters:

  • keyword, this is where a user's given search term can be input, and our API will return a list of Learning Objects relevant to your specified keyword.
  • contentSet, this specifies which content set within the customers portal to search. The available options are SUBSCRIBED, which will search the entire Go1 Library that is available to the customer, or PORTAL_SELECTION, which will search only the customers curated My Library collection. In most scenarios, you'll use SUBSCRIBE. To learn more about the curated collections of content, if this is required for your use-case, reach out to our team.

sort: The sort parameter influences how your search result is sorted. There are various ways the results can be sorted, we will discuss these sorting options further in step 4 of this guide. Whenever a keyword search is used via the API, you should set the sort field to RELEVANT (as it is in the code snippet example above) to ensure that the results returned will be sorted by relevance to the keyword.

context: The context segment provides context for the search and is used to improve search results to be more relevant to the individual. Here you can specify the language and the region the content is relevant to.

After you have defined filters, sort & context, ie. what you are searching for, the next step is to define the Learning Object metadata fields you would like returned from the server. You do this using the ... on CourseSlat element. Within the CourseSlat element, you can specify which learning object fields you would like returned. In our example code snippet, we are retrieving the learning object id, title, description, rating, tags, duration and image.

Here is an example response to this request (with a single learning object returned):

{
  "data": {
    "search": {
      "blocks": [
        {
          "response": {
            "edges": [
              {
                "node": {
                  "id": "11165703",
                  "title": "Client Acquisition & Engagement Skills",
                  "description": "<p><strong>Course Overview</strong></p><p>This workshop will provide a bucketful of simple, practical and usable client engagement tools designed to make business a natural consequence of your process and referrals a natural consequence of business.</p><p>The client engagement skills content will ensure results at each stage of the process, thereby maximising the conversion rates of invitations extended to appointments made, first appointments seen to second appointments made and second appointments seen to long term clients obtained.</p><p>The client acquisition skills content will outline a simple 3 step system that will make referrals a natural consequence of business.</p>",
                  "rating": 0.5,
                  "tags": null,
                  "duration": 316,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1564536841/pfvi38wtocpr0yfrdepe.jpg",
                  "createdAt": "2019-07-31T01:33:59Z",
                  "updatedAt": "2020-02-13T08:59:09Z"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

This response can be used to display the returned learning objects within your Search results page - reference the screenshot at the top of this step as an example. In the next step, we'll discuss paginating through the returned search results.

Step 3. Adding pagination

In this step, we'll discuss how to paginate through the returned search results using the search() endpoint. The search endpoint has the potential to return thousands of learning objects from any search - however, each response from the server can only return up to a maximum of 50 results per request. This is where pagination can be used to fetch the next page of learning objects should you need to display these in your application - ie. when the user wants to see more than the first set of 50 learning objects returned.

To add pagination to your search() request, we'll implement the following code into your request:

      ... on SearchResult {
        response(first: 20, after: "EI_0") {
          pageInfo {
            startCursor
            endCursor            
            hasNextPage
            totalCount
            hasPreviousPage
          }

Let's examine these elements further:

  • first: 20, this determines the number of learning objects you want returned from your request. This supports a maximum of 50 learning objects. Eg. you can pass in first: 50, to retrieve 50 learning objects from your request.
  • after: "EI_0", this field is used to specify which learning objects are returned from the entire set. Here is some example:
    - response(first: 20, after: "EI_0") {, this will return learning objects 1-20.
    - response(first: 20, after: "EI_20") {, this will return learning objects 21-40.
    - response(first: 20, after: "EI_40") {, this will return learning objects 41-60.
  • pageInfo, when you send the pageInfo fields in your request, the server will respond with some information about the page of learning objects you have just requested. Here is an example:
    - "startCursor": "EI_1", this field describes the first learning object in your response.
    - "endCursor": "EI_20", this field describes the last learning object in your response.
    - "hasNextPage": true, this field indicates whether there are more learning objects that can be retrieved from the search.
    - "totalCount": 84489, this field indicates the total number of learning objects that match your search.
    - "hasPreviousPage": false, this field indicates if there was a previous learning objects, other than the set you have currently requested.

Below is an example request which incorporates the pagination elements. The request is performing a search using the keyword leadership, and is requesting only 2 learning objects:

query {
  search(
    filters: {
      keyword: "leadership"
      contentSet: [SUBSCRIBED]
    }
    sort: { field: RELEVANT, direction: DESC }    
    context: { appId: "partnerABC", language: "en", region: GLOBAL }
  ) {
    blocks {
      ... on SearchResult {
        response(first: 2, after: "EI_0") {
          pageInfo {
            startCursor
            endCursor            
            hasNextPage
            totalCount
            hasPreviousPage
          }
          edges {
            node {
              ... on CourseSlat {
                id
                title
                description
                rating
                tags
                duration
                image 
                createdAt
                updatedAt
              }
            }
          }
        }
      }
    }
  }
}

Here is the example response:

{
  "data": {
    "search": {
      "blocks": [
        {
          "response": {
            "pageInfo": {
              "startCursor": "EI_1",
              "endCursor": "EI_2",
              "hasNextPage": true,
              "totalCount": 4305,
              "hasPreviousPage": false
            },
            "edges": [
              {
                "node": {
                  "id": "20791523",
                  "title": "Leadership",
                  "description": "<p><span style=\"font-size:11pt;\"><span style=\"font-family:Calibri, sans-serif;\"><span style=\"font-family:Arial, sans-serif;\">Leaders have a tremendous impact on a group’s success in reaching its goals. </span><span style=\"font-family:Arial, sans-serif;\">In this course, you’ll discover what leadership is, as well as the traits of successful leaders. You’ll also learn how you can develop leadership skills in case you ever find yourself in a leadership position.</span></span></span></p>",
                  "rating": 0.4,
                  "tags": null,
                  "duration": 48,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1590568870/cndpqqaxsn4kz4exsyui.jpg",
                  "createdAt": "2020-05-27T08:41:10Z",
                  "updatedAt": "2020-07-03T06:02:42Z"
                }
              },
              {
                "node": {
                  "id": "13407146",
                  "title": "Leadership & Management - Team Leadership (MiQuick)",
                  "description": "<p><strong>Course Overview</strong></p><p>Mi Quick - the One Minute Video: Are you a motivator or a manipulator?</p><br />",
                  "rating": 0.8333333333333334,
                  "tags": null,
                  "duration": 2,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1592975645/ma6nhfv9b1cl9ocbvjom.jpg",
                  "createdAt": "2019-11-07T07:04:39Z",
                  "updatedAt": "2020-06-24T05:14:06Z"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Take note of the pageInfo returned from this request - there is a total of 4305 learning objects that match this keyword. To fetch the next 2 results, you would now make a second request updating the value, after: "EI_2".

You can now apply these pagination principles to the catalogue you are building. Simply choose the number of results you wish to display per page (maximum of 50), and use subsequent requests to fetch the additional pages as required.

Step 4. Adding sorting preference

Adding sort options to your interface via the search() endpoint allows your users to specify the order in which the set of queried learning objects will be returned.

There are 4 primary sort options available, and these options can be specified in the sort argument of your request:

  • TITLE - sorts result in alphabetical order based on the learning object title.
  • RELEVANT - when searching by keyword, sorts results based on our relevance algorithm.
  • POPULAR - sorts results based on the most used content.
  • CREATED - sort results by creation date.

You may also wish to add the ... on SortBlock section to your request, which will return the available sorting options to you in the response. This can be used to build a selectable 'Sort' field in your interface, see the example screenshot below:

null

Example request with SortBlock:

query {
  search(
    filters: {
      keyword: "communication"
      contentSet: [SUBSCRIBED]
    }
    sort: { field: RELEVANT, direction: DESC }    
    context: { appId: "partnerABC", language: "en", region: GLOBAL }
  ) {
    blocks {
      ... on SortBlock {
        options {
          label
          field
          direction
        }
      }
      ... on SearchResult {
        response(first: 2, after: "EI_0") {
          pageInfo {
            startCursor
            endCursor            
            hasNextPage
            totalCount
            hasPreviousPage
          }
          edges {
            node {
              ... on CourseSlat {
                id
                title
                description
                rating
                tags
                duration
                image 
                createdAt
                updatedAt
              }
            }
          }
        }
      }
    }
  }
}

Example response:

{
  "data": {
    "search": {
      "blocks": [
        {
          "options": [
            {
              "label": "Most relevant",
              "field": "RELEVANT",
              "direction": "DESC"
            },
            {
              "label": "Popular",
              "field": "POPULAR",
              "direction": "DESC"
            },
            {
              "label": "Latest",
              "field": "CREATED",
              "direction": "DESC"
            },
            {
              "label": "Alphabetical",
              "field": "TITLE",
              "direction": "ASC"
            }
          ]
        },
        {
          "response": {
            "pageInfo": {
              "startCursor": "EI_1",
              "endCursor": "EI_2",
              "hasNextPage": true,
              "totalCount": 4305,
              "hasPreviousPage": false
            },
            "edges": [
              {
                "node": {
                  "id": "20791523",
                  "title": "Leadership",
                  "description": "<p><span style=\"font-size:11pt;\"><span style=\"font-family:Calibri, sans-serif;\"><span style=\"font-family:Arial, sans-serif;\">Leaders have a tremendous impact on a group’s success in reaching its goals. </span><span style=\"font-family:Arial, sans-serif;\">In this course, you’ll discover what leadership is, as well as the traits of successful leaders. You’ll also learn how you can develop leadership skills in case you ever find yourself in a leadership position.</span></span></span></p>",
                  "rating": 0.4,
                  "tags": null,
                  "duration": 48,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1590568870/cndpqqaxsn4kz4exsyui.jpg",
                  "createdAt": "2020-05-27T08:41:10Z",
                  "updatedAt": "2020-07-03T06:02:42Z"
                }
              },
              {
                "node": {
                  "id": "13407146",
                  "title": "Leadership & Management - Team Leadership (MiQuick)",
                  "description": "<p><strong>Course Overview</strong></p><p>Mi Quick - the One Minute Video: Are you a motivator or a manipulator?</p><br />",
                  "rating": 0.8333333333333334,
                  "tags": null,
                  "duration": 2,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1592975645/ma6nhfv9b1cl9ocbvjom.jpg",
                  "createdAt": "2019-11-07T07:04:39Z",
                  "updatedAt": "2020-06-24T05:14:06Z"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Note, the response now includes the available sort options, which can be used to populate the sorting filter that you build within your application.

Step 5. Adding filters

With over 80,000 pieces of learning content in the Go1 library - it's important to enable end-users to find the content they need as quickly and as easily as possible. To assist users in discovering the most relevant content, we recommend implementing our set of filters within the search() request.

In this example, we'll cover the following filters; Topics, Providers and Duration. In your build, you may wish to consider additional filters that we have available, such as Content-Type, Language and more. Please reference the entire API Reference to see your options.

Here is an example of what you could build to enable this experience:

null

To get started, here is an example request that incorporates all of these filter options:

query {
  search(
    filters: {
      keyword: ""
      contentSet: [SUBSCRIBED]
      topic: ["Leadership"]
      provider: ["10362298"]
      duration: [{min:1,max:30}]
    }
    sort: { field: RELEVANT, direction: DESC }    
    context: { appId: "partnerABC", language: "en", region: GLOBAL }
  ) {
    blocks {
      ... on SearchFilterBlock {
        filters(types:[TOPIC, PROVIDER, DURATION]) {
          ... on ListFilter {
            type
            label
            options {
              label
              value
              count
            }
          }
          ... on TreeFilter {
            label
            options {
              parentId
              id
              count
              label
            }
          }
        }
      }
      ... on SortBlock {
        options {
          label
          field
          direction
        }
      }
      ... on SearchResult {
        response(first: 2, after: "EI_0") {
          pageInfo {
            startCursor
            endCursor            
            hasNextPage
            totalCount
            hasPreviousPage
          }
          edges {
            node {
              ... on CourseSlat {
                id
                title
                description
                rating
                tags
                duration
                image 
                createdAt
                updatedAt
              }
            }
          }
        }
      }
    }
  }
}

Let's examine this request in more detail. Firstly, you'll notice that within the filters argument towards the top of the request, we've added in the topic, provider and duration filters. This is an example of how a user may wish to curate their search using all of these filter options at once.

To support this experience, you'll need to provide a flexible interface that allows a user to dynamically pick the filters they wish to apply. To do this you will need to retrieve all of the available filtering options from our server. This is done by adding the SearchFilterBlock. This block includes all available filter options you can require the server to return. In our example, we have requested options for TOPIC, PROVIDER, DURATION.

Below is an example response that would include all of the TOPIC, PROVIDER and DURATION filter options that can be applied. Note, we have stripped out all but one topic and provider in this example response to keep it short. There would in reality be multiple providers and topics returned that can be used.

{
  "data": {
    "search": {
      "blocks": [
        {
          "filters": [
            {
              "label": "Topics",
              "options": [
                {
                  "parentId": "0",
                  "id": "64",
                  "count": 41749,
                  "label": "Technology Skills"
                }
              ]
            },
            {
              "type": "DURATION",
              "label": "Duration",
              "options": [
                {
                  "label": "< 15 min",
                  "value": "1.0-15.0",
                  "count": 49023
                },
                {
                  "label": "15 – 30 min",
                  "value": "15.0-30.0",
                  "count": 16677
                },
                {
                  "label": "30 – 60 min",
                  "value": "30.0-60.0",
                  "count": 8724
                },
                {
                  "label": "> 60 min",
                  "value": "60.0-*",
                  "count": 9979
                }
              ]
            },
            {
              "type": "PROVIDER",
              "label": "Providers",
              "options": [
                {
                  "label": "CreativeLive",
                  "value": "4878185",
                  "count": 26589
                }
              ]
            }
          ]
        },
        {
          "options": [
            {
              "label": "Most relevant",
              "field": "RELEVANT",
              "direction": "DESC"
            },
            {
              "label": "Popular",
              "field": "POPULAR",
              "direction": "DESC"
            },
            {
              "label": "Latest",
              "field": "CREATED",
              "direction": "DESC"
            },
            {
              "label": "Alphabetical",
              "field": "TITLE",
              "direction": "ASC"
            }
          ]
        },
        {
          "response": {
            "pageInfo": {
              "startCursor": "EI_1",
              "endCursor": "EI_2",
              "hasNextPage": true,
              "totalCount": 84489,
              "hasPreviousPage": false
            },
            "edges": [
              {
                "node": {
                  "id": "16599902",
                  "title": "Mental Health",
                  "description": "<p>What you do to keep your cup full is up to you, but it should include regular physical activity, a good diet, supportive relationships, maybe some meditation or mindfulness, and making the time to have some fun.    </p><p>If you are doing it tough, seek professional help or chat to a mate. Just don’t go it alone.</p><p>Take part in the Mental Health module to learn more.</p>",
                  "rating": 0.6,
                  "tags": null,
                  "duration": 15,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1584010446/t85nhwytctwyufhekjoj.png",
                  "createdAt": "2020-03-12T10:36:11Z",
                  "updatedAt": "2021-01-14T23:30:09Z"
                }
              },
              {
                "node": {
                  "id": "16601175",
                  "title": "Dealing with Change",
                  "description": "<p>When change happens in your life, remember; Feelings such as fear and sadness are completely normal. Denial may also kick in but remember not to get stuck here.  Seek out a friend or family member and talk through what you’re experiencing honestly. Be prepared to be challenged.</p><p>When change occurs in our lives, the biggest challenge and the greatest reward is in changing ourselves.</p><p>Take part in the Dealing with Change module to learn more.</p>",
                  "rating": 0.6,
                  "tags": null,
                  "duration": 10,
                  "image": "https://res.cloudinary.com/go1/image/upload/f_auto,q_auto,w_350/v1584011930/ghsa8ziahncco9gcb9nn.png",
                  "createdAt": "2020-03-12T11:18:47Z",
                  "updatedAt": "2021-01-14T23:30:46Z"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

This response can be used to build the filtering options in your interface, whereby a user can browse and select the filters they wish to apply. When you apply these filters, you simply add the selected filter option to the filter argument at the top of the request, as we have shown in the example.

Ideas for building your own catalogue

The steps above are designed to act as an introduction to the GraphQL API endpoint, which you can use to create your own catalogue experience within your application. Ultimately, how the catalogue is built and surfaced to users in your platform is up to you to design - this typically depends on the user experience you are looking to create. Below are a few examples of user experiences we have seen be successful in the past.

A curation storefront for Admin

The catalogue you build can be used as a tool for administrators in your platform to find and select the content they would like to import. This is particularly useful if your application has an existing course-ware object that Go1 content would need to be imported as. This is also useful to provide your customers with the choice of which content they want to provide to their organisation. To support this approach, consider adding the following features to the catalogue you build:

  • Add an import state & button on each LO you display in your catalogue, allowing users to easily import content they find to your platform.
  • Building on the above point, provide a mechanism for users to shortlist content and import their list in bulk.

null

A learning-facing content library

You might also consider building the catalogue as a way to help end-learners engage directly with learning. Providing your learners with the ability to explore and conduct self-directed learning can be a great value to an existing product offering. To support this experience, consider how you might allow users to access and play the content directly via the catalogue - see our Play Content concept which explores this further.