Tutorial

Access MongoDB using a GraphQL interface

Build a GraphQL API with IBM API Connect using the MongoDB Atlas Data API

By

Carlos Eberhardt

MongoDB Atlas is a powerful, multi-cloud application data platform used by millions of developers. Millions of developers also recognize that GraphQL is a fantastic way to access data, because it provides a single, flexible API from which they can access all their databases and data APIs.

MongoDB gives you two options:

  1. Work with MongoDB Atlas’s GraphQL API. It is a super easy way of getting a working GraphQL API on top of MongoDB. Many developers would like to customize the GraphQL API, and that does take additional custom code.
  2. Work with MongoDB Atlas’s Data API. The Data API is REST-like and super flexible, which means you can create your own hosted GraphQL API server, with the Data API serving as the layer communicating to the database. However, this requires writing and deploying a lot of code, as well as managing infrastructure.

Learning objectives

In this tutorial, we will learn to use GraphQL to access data stored in MongoDB. Deploy built-in GraphQL API with the flexibility of hand-coded GraphQL API. Build our custom MongoDB GraphQL API without having to write and maintain code. And furthermore, add other data sources and APIs to our GraphQL API.

We will build out a GraphQL API with IBM API Connect Essentials (formerly StepZen) using the MongoDB Atlas Data API without writing any code. We’ll customize the generated GraphQL schemas and even mix an additional REST API into our custom GraphQL API.

Notice: StepZen was acquired by IBM in 2023 and renamed to API Connect Essentials. Some artifacts still use the StepZen name.

Prerequisites

Users should have experience with building GraphQL APIs (learn more in this article, "What is GraphQL?").

For MongoDB explore more this getting started guide.

Estimated time

It should take approximately 20 minutes to complete the tutorial.

Steps

Step 1. Enable Data API in MongoDB

MongoDB Atlas provides an easy way to host and manage your data in the cloud. If you do not already have a MongoDB Atlas account, follow the getting started documentation here to create an account and deploy a free cluster. Then, follow the instructions on the sample data page to load the cluster with some sample datasets.

Navigate to the Data API page to enable the Data API:

Mongo DB Atlas Data API image

Step 2. Create API Key

Click the "Create API Key" button to create an API Key. Copy it somewhere safe, as you'll need it later. You will also need to refer to the "URL Endpoint" listed here as well.

Thereafter, click on the green “Test Your API” button to validate the API is working with your new key. Pick the cluster, database and collection. We will be using the listingsAndReviews collection in the sample_airbnb database, but you can use anything. Make sure the API call returns data.

Test Your API image

Now that you have enabled the Data API and verified access, we can start to build our GraphQL API using API Connect Essentials.

Step 3. Create and run a GraphQL query in API Connect Essentials

Go to API Connect Essentials Signup to create your free account. We need to install the API Connect Essentials CLI and log in.

npm install -g stepzen

Login using the account and admin key which you can find on the API Connect Essentials dashboard.

stepzen login

Now you are ready to configure and deploy your GraphQL API.

Create a working directory. Give it any name you like, and cd into that directory.

mkdir mongodb
cd mongodb

Define the GraphQL schema and configuration for your API Connect Essentials GraphQL API. Create a file called index.graphql and paste the following into it:

scalar MongoFilter
scalar MongoProjection
scalar MongoSort

type Query {
  mongo(
    dataApikey: String!
    dataSource: String!
    collection: String!
    database: String!
    filter: MongoFilter
    projection: MongoProjection
    sort: MongoSort
    limit: Int
    skip: Int
  ): JSON
    @rest(
      endpoint: "https://data.mongodb-api.com/app/<Data API App ID>/endpoint/data/beta/action/find"
      method: POST
      headers: [{ name: "api-key", value: "$dataApikey" }]
    )
}

Edit the endpoint URL to match the URL Endpoint listed on your Data API page. The Data API endpoint contains a unique id specific to each cluster. You will replace <Data API App ID> with something that looks like "data-xqgfu". Unlike a typical GraphQL schema definition, there are no types. There is a single query defined that takes a few parameters and returns JSON. That query has a API Connect Essentials custom directive, @rest, which instructs the API Connect Essentials server to make an http request to the given endpoint using the POST method. Refer to the following URL.

endpoint: "https://data.mongodb-api.com/app/data-xqgfu/endpoint/data/beta/action/find"

Save that file, and in your terminal run the stepzen deploy CLI command. The command will prompt you to name the endpoint of your API Connect Essentials GraphQL API, and then deploy it. The deployed endpoint is displayed in the terminal with a pattern of ***.stepzen.net/api/folder-name/__graphql. The CLI then watches the endpoint for changes in the schema. The start command instructs the CLI to validate and upload your schema and deploy it. Similarly, your API is live on API Connect Essentials' scalable service and ready to call. The CLI continues to watch the directory for changes to your schema files, uploading and deploying any changes as they happen.

You can try the GraphQL API right away by running a query in the API Connect Essentials dashboard.

Copy and paste the following query and run it:

query MyQuery(
  $dataApikey: String!
  $datasource: String!
  $database: String!
  $collection: String!
) {
  mongo(
    dataApikey: $dataApikey
    collection: $collection
    database: $database
    dataSource: $datasource
    limit: 10
  )
}

Be sure to set the query variables appropriately, refer the following code snippet:

{
  "database": "sample_airbnb",
  "dataApikey": "YOUR_API_KEY",
  "datasource": "Cluster0",
  "collection": "listingsAndReviews"
}

If you try the operation from the API Connect Essentials or a tool like GraphiQL you should see results like the following image:

Simple JSON Results

Step 4. Add the ability to select types

At this point you have a working GraphQL endpoint, deployed on API Connect Essentials, protected by an API key. However, it’s not quite done yet, since we cannot select the fields we want in typical GraphQL. Recall that our schema did not have any types defined, and our query simply returned JSON. Let’s add the ability to select types now. You can use the JSON to SDL tool to create the types for your schema.

  1. Copy the entire output of the query.
  2. Paste the output into the JSON to SDL tool, it will be automatically converted.
  3. Copy the Output SDL from the JSON to SDL tool and paste it into the bottom of the index.graphql file you created in the first step.
  4. Clean up the types a bit to return the documents from the database

    • Delete the types Root, Data, and Mongo, and change the mongo query to return [Document] instead of JSON.
    • Data API returns all documents under a documents object, we will need to add one additional attribute to the @rest directive called resultroot. This attribute tells API Connect Essentials where to look for the results in the API response:
    resultroot: "documents[]"
    

Your index.graphql file should look like the following code snippet:

scalar MongoFilter
scalar MongoProjection
scalar MongoSort

type Query {
  mongo(
    dataApikey: String!
    dataSource: String!
    collection: String!
    database: String!
    filter: MongoFilter
    projection: MongoProjection
    sort: MongoSort
    limit: Int
    skip: Int
  ): [Document]
    @rest(
      endpoint: "https://data.mongodb-api.com/app/data-xqgfu/endpoint/data/beta/action/find"
      method: POST
      headers: [{ name: "api-key", value: "$dataApikey" }]
      resultroot: "documents[]"
    )
}

type Location {
  coordinates: [Float]
  is_location_exact: Boolean
  type: String
}
... continued ...

Save the file, and the API Connect Essentials CLI will redeploy your schema. Once it completes, reload the local proxy browser, and now you can select fields to return in your query. Refer following code snippet to run the query:

query MyQuery(
  $dataApikey: String!
  $datasource: String!
  $database: String!
  $collection: String!
  $filter: MongoFilter
) {
  mongo(
    dataApikey: $dataApikey
    collection: $collection
    database: $database
    dataSource: $datasource
    filter: $filter
    limit: 10
  ) {
    name
    beds
    bedrooms
    address {
      market
    }
  }
}

With the following variables:

{
  "database": "sample_airbnb",
  "dataApikey": "YOUR_API_KEY",
  "datasource": "Cluster0",
  "collection": "listingsAndReviews",
  "filter": { "address.market": "Istanbul" }
}

Now, you will be able to use the API Connect Essentials GraphQL API to run queries against MongoDB Atlas using the Data API without the need to write any resolvers.

Step 5. Customizing the GraphQL API

Further customization of the GraphQL API is two add following changes:

Change type names and field names using setters argument for an @rest call. Mix in any external API (for example, that might keep some relevant but current data that would not be in MongoDB).

Step 6. Change type names and field names

Let us say that you don't want the reviews object to be visible. Delete the field from type Document. That field will no longer be available to end users, and API Connect Essentials will not map it from the REST API.

If you want to rename the field beds to number_of_guests, change the field name in type Document to number_of_guests, and add a parameter setters to the @rest call, as follows:

type Query {
  mongo(
    dataApikey: String!
    dataSource: String!
    collection: String!
    database: String!
    filter: MongoFilter
    projection: MongoProjection
    sort: MongoSort
    limit: Int
    skip: Int
  ): [Document]
    @rest(
      endpoint: "https://data.mongodb-api.com/app/data-xqgfu/endpoint/data/beta/action/find"
      method: POST
      headers: [{ name: "api-key", value: "$dataApikey" }]
      resultroot: "documents[]"
      setters: [{ field: "number_of_guests", path: "beds" }]
    )
}

Step 7. Add an external API

The MongoDB listing database only lists country codes, names etc. But each country has a rich set of other information, that we can use to enhance the returned data. So, we will use REST Countries to enhance it.

Create a new GraphQL endpoint for REST Countries. Add the following lines to the bottom of the index.graphql that contains your MongoDB query.

type Query {
  restCountry(country_code: String!): JSON
    @rest(endpoint: "https://restcountries.com/v2/alpha/$country_code")
}

Once the API Connect Essentials CLI uploads your changes (in case of an error, just run stepzen deploy again in your working directory), you will see that you have a new query available in your GraphQL API.

query RestCountries {
  restCountry(country_code: "TR")
}

We'll repeat the steps to generate the GraphQL types for the countries API. Take the output of the query and convert it using the JSON to SDL tool. Copy the SDL into the bottom of index.graphql. Delete type Root and type Data and change the query restCountry to return RestCountry as opposed to jSON.

type Query {
  restCountry(country_code: String!): RestCountry
    @rest(endpoint: "https://restcountries.com/v2/alpha/$country_code")
}

Now, we have two, fully functional GraphQL queries in our API, mongo and restCountry.

With this country information, it is trivial in API Connect Essentials to add it to the data being returned from mongo. Add the following code snippet to the bottom of index.graphql and save the file.

extend type Address {
  country_info: RestCountry @materializer(query: "restCountry")
}

API Connect Essentials is instructed to make RestCountry available under a field named country_info in the Address type. You can run a query like the following code snippet:

query MyQuery(
  $dataApikey: String!
  $datasource: String!
  $database: String!
  $collection: String!
  $filter: MongoFilter
) {
  mongo(
    dataApikey: $dataApikey
    collection: $collection
    database: $database
    dataSource: $datasource
    filter: $filter
    limit: 10
  ) {
    name
    number_of_guests
    bedrooms
    address {
      market
      country_info {
        capital
        population
      }
    }
  }
}

Consider including the following variables:

{
  "database": "sample_airbnb",
  "dataApikey": "YOUR_API_KEY",
  "datasource": "Cluster0",
  "collection": "listingsAndReviews",
  "filter": {}
}

Your result should look like the following code snippet:

{
  "data": {
    "mongo": [
      {
        "name": "Ribeira Charming Duplex",
        "number_of_guests": 5,
        "bedrooms": 3,
        "address": {
          "market": "Porto",
          "country_info": {
            "capital": "Lisbon",
            "population": 10305564
          }
        }
      },
      {
        "name": "Horto flat with small garden",
        "number_of_guests": 2,
        "bedrooms": 1,
        "address": {
          "market": "Rio De Janeiro",
          "country_info": {
            "capital": "Bras�a",
            "population": 212559409
          }
        }
      },
      {
        "name": "Ocean View Waikiki Marina w/prkg",
        "number_of_guests": 1,
        "bedrooms": 1,
        "address": {
          "market": "Oahu",
          "country_info": {
            "capital": "Washington, D.C.",
            "population": 329484123
          }
        }
      },
... etc.

Summary

In this tutorial, you've learned to:

  1. Use MongoDB's Data (REST) API and instantly created a GraphQL endpoint from using API Connect Essentials.
  2. Change the names of the types, fields etc. using simple declarative constructs.
  3. Add an external API (REST Countries) to the same GraphQL schema in API Connect Essentials, creating additional functionality.
  4. Link the two APIs together with just 4 lines of code.

Now, you can have one GraphQL API that accesses data from two separate sources in a single API call, demonstrating how powerful a declarative, configuration-driven GraphQL API can be. Next, you can learn to securely store your configuration data (like API keys) and how to structure your project so it’s easy to maintain.

We'd love to hear what you're building using GraphQL and IBM API Connect Essentials! Join our Discord Community and let us know.