Build Serverless API with GraphQL and Azure— Part I

Shamique
ITNEXT
Published in
5 min readJan 25, 2021

--

Serverless architecture is the current trend in the software industry, which allows you to run applications in cost effective ephemeral services. With GraphQL, you can reduce the number of service calls to single endpoint. Using these two technologies, we can build cost effective and efficient API.

In this article series, I am gonna guide you on how to integrate GraphQL API and Azure functions together (Part I). Also, how we can secure this API using oAuth2 authentication (Part II).

Below is the high-level diagram of what we are going to cover in this article,

I presume you have already worked with Azure technologies and GraphQL. So I am not going into a detailed explanation on each term on each section.

Prerequisites

Create Azure Function in local

We have the option to write an Azure function in different languages such as C#, NodeJS, python etc. I will select NodeJS in this article.

First, let’s create our Azure function project. Open your console and run below command:

func init graphql-functions --worker-runtime node
cd graphql-functions

Then, run the following command to generate HTTP Trigger template.

func new --template "Http Trigger" --name graphql

This will generate two pre-built templates inside “graphql” folder as function.json and index.js. We’ll be writing our business logic inside this index.js.

Now open this function project using VS Code or your favorite IDE and edit function.json. Here we need to replace `HTTP out` binding to "$return" as follow:

{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}

Setup GraphQL Endpoint

Let’s install Apollo server integration for Azure Functions using npm:

npm install --save apollo-server-azure-functions

Now open “graphql/index.js” file. We are going to write our logic in this file. First, let’s write a simple GraphQL schema with “Hello World” response.

Replace the existing code with below code:

Ok, so our initial GraphQL setup is done. Let’s run the function:

func host start

You should see similar output in your console.

Copy the GraphQL and paste in browser. You should see below GraphQL playground as follow:

Alright, now we have integrated Azure function with GraphQL. Now we can start writing our actual business logic. For this article, I will be using Cosmos DB.

Set up Cosmos DB in Azure

I have already set up a simple Cosmos DB in my Azure subscription.

NOTE: Better maintain all your resources (cosmos DB, function app) in one resource group. So then it’s easier to do the cleanup at the end.

Following is the structure of a document. You may add some dummy records as the following structure in your Cosmos container.

{
"id": "1",
"first_name": "Tony",
"last_name": "Stark",
"email": "tonystark@shield.com"
}

Once you setup your Azure Cosmo DB, copy the connection string:

  • Log in to the Azure portal and navigate to your Cosmos DB
  • Select ‘Keys’ from left-hand panel
  • Copy the primary connection string and paste it in a notepad.

Writing code for Cosmos

Install Cosmo DB npm package for our project. Run following command in the console:

npm install --save @azure/cosmos

Then, open index.js file and import Cosmos client.

const { CosmosClient } = require('@azure/cosmos');

And then define the following variables and set the values.

const connectionString = "ADD_YOUR_CONNECTION_STRING";
const databaseName = "ADD_DATABASE_NAME";
const containerName = "ADD_CONTAINER_NAME";

Note: Since this is just for a demo, adding the connection string in the code. The recommended way is to store the connection string in a config file or store it in Key vault.

Now, let’s create the connection to our Cosmo DB.

const client = new CosmosClient(connectionString);

Then replace the existing GraphQL schema with the following schema:

const typeDefs = gql`
type User {
id: Int,
first_name: String
last_name: String,
email: String
},
type Query {
user(id: Int!): User,
users: [User]
}
`;

As you can see, we have defined our user schema with id, first name, last name and email, which is similar to our Cosmos document structure. Also, we have introduced two queries. One query is to get the user by Id & other method is to retrieve all the users in our DB.

Then, let’s replace our resolver method with the following:

const resolvers = {
Query: {
user: getUser,
users: getAllUser
}
};

We have assigned relevant function to each query in the resolver. Now, we can write getUser and getAllUser business method.

getUser = async (_, { id }) => {
let query = "SELECT * FROM c WHERE c.id = @userId";
let params = [{ name: "@userId", value: id.toString() }];
let { resources: items } = await client.database("gql-db").container("gql-container")
.items.query({ query: query, parameters: params }).fetchAll();
if (items.length > 0) {
return items[0];
}
return null;
};
getAllUser = async () => {
let { resources: items } = await client.database("gql-db").container("gql-container")
.items.query({ query: "SELECT * from c" }).fetchAll();
return items;
};

Once you have done above steps, your complete code should look like this:

Now run the function again in local & perform some query in the playground.

If the function is working as expected, it’s ready to SHIP!!!

Let’s further discuss on how to deploy this Serverless application into the cloud and apply authentication in Part II.

--

--

Senior Software Engineer at 99x / Microsoft Certified Azure Developer / Photographer