Let's see how we can easily use Kinvey to rapidly build a microservice that helps us store, query and update our friends’ names and ages.
Progress Kinvey is a High Productivity app platform, which offers a serverless cloud backend for rapidly building enterprise apps and experiences at consumer scale. Developer productivity is dramatically increased using open source frontend frameworks integrated with a low-code backend that enables out-of-the-box integrations with enterprise and legacy systems.
Kinvey Flex Services are low-code, lightweight Node.js microservices, that are used for data integrations and functional business logic. Flex Services utilize the Flex SDK and can consist of FlexData for data integrations, FlexFunctions for trigger-based data pre/post-hooks or custom endpoints, and FlexAuth for custom authentication through Mobile Identity Connect (MIC).
Data is a critical component of many applications. On the surface, data access appears simple—you have a store for your data, whether that be a traditional RDBMS, a modern NoSQL store, or local storage. The reality, however, is much more complex. The data abstraction provided by the Kinvey Platform serves as a framework for dealing with these complexities, providing developers tools that simplify the development of rich, data-driven apps. The core data abstraction of Kinvey is the collection. A collection is simply a group of related data entities. Kinvey makes no assumptions about the makeup or schema of a collection (other than a few pre-defined system properties).
If you are still not a Kinvey customer, head to Kinvey Serverless Cloud Platform to learn about all the possibilities. In addition, this tutorial assumes some knowledge about SOA (Service Oriented Architecture) andData Querying/Manipulationusing GraphQL.
This document goes through all the steps, including setting up a Flex Service locally, as well as making sure that the necessary service is set up in the Kinvey Console—Kinvey’s backend management UI. You will need to have a Kinvey account to be able to go through those steps. In case you do not have an account yet, please use the following link to sign-up for one: https://console.kinvey.com/sign-up.
The GitHub repository used in this tutorial is available at: https://github.com/bilger-progress/flex-graphql-article
During the next couple of minutes, we will be building a microservice that helps us store our friends’ names and ages. It will expose a single query, which can reveal to us what the age of someone is. If there's no age set for this person, then we will get the appropriate message for that. There will also be a single mutation, which we will use to set (or change) the age of a person.
Kinvey Console
Start by creating a Kinvey Application and a Flex Service using the Kinvey Console.
First, log in to https://console.kinvey.com/ using your Kinvey account and create a new application. We will call ours flex-graphql-article.
After creating the application, please navigate to Services from the upper navigation bar and add a new service of type Flex with subtype Flex Services Runtime. Give it a suitable name like flex-graphql-article-service and then choose the app you just created to grant it access to the service. Since Kinvey Flex Services make use of environments, as soon as you initialize the service, you need to save the auto-generated (initial) environment for your service. Use the image below as a reference.
Due to the fact that we will be dealing with data, it's time to create a Collection in our Kinvey app. We can do that by navigating to the Collections section of our application’s left-hand side navigation. Let's call the collection FriendsAges.
Setting Up the Flex Service Locally (NodeJS project)
At this point, we are ready to initialize our Flex Service, which is basically a Node.js project located on our development machine. To start up with the service, create a new folder and initialize a new Node.js project inside it (using NPM). You will need to install two dependencies to this Node.js project. They are as follows:
- graphql (https://www.npmjs.com/package/graphql)
- kinvey-flex-sdk (https://www.npmjs.com/package/kinvey-flex-sdk)
The graphql module makes it easy to rapidly create a GraphQL service that validates queries and mutations. The kinvey-flex-sdk module will be needed to initialize and develop our Kinvey Flex Service. Check the repository for the required versions of those packages.
Having added those two dependencies (packages), let's create a new JavaScript file and call it index.js. Inside this file we will be adding our Flex Service's code. For the most up-to-date version of the code, check out the following address: https://github.com/bilger-progress/flex-graphql-article/blob/master/flex-graphql-article/index.js
Let's talk about how this code works.
Initially, because the Kinvey Flex SDK uses a callback pattern, we will make sure to promisify those callback executions. The function, which we will call promisify(), wraps callback executions inside promises.
function promisify(func) {
return (...args) => {
return new Promise((resolve, reject) => {
func(...args, (error, data) => {
if (error) {
return reject(error);
}
return resolve(data);
});
});
};
}
Having understood that, it's time to continue with the implementation of two functions that will be used to deal with our friends' ages. The first function, getAge(), fetches all User data from the Kinvey Collection and prepares the correct message based on that. The second function, setAge(), also fetches all the User data from the Kinvey Collection but then updates the needed fields.
function getAge(name, context) {
return fetchFriendData(name, context)
.then((data) => {
if (!data || !data.age) {
return `Sorry. You still have not set age for your friend - ${name}. You can do that now.`;
}
return `Your friend - ${name}'s age is ${data.age}.`;
})
.catch(error => logPromiseError(error, context));
};
function setAge(name, age, context) {
return fetchFriendData(name, context)
.then((data) => {
const savePromisified = promisify(context.modules.dataStore().collection(COLLECTION_NAME).save);
if (!data) {
return savePromisified({ name, age });
}
data.age = age;
return savePromisified(data);
})
.then(data => data.age)
.catch(error => logPromiseError(error, context));
};
function fetchFriendData(name, context) {
const findPromisified = promisify(context.modules.dataStore().collection(COLLECTION_NAME).find);
return findPromisified(new context.modules.Query().equalTo("name", name))
.then(data => data[0]);
}
Looking further down below, you will see the schemas of the GraphQL query and mutation implementations. The query will be connected to the getAge() function, while the mutation will be making use of the setAge() function.
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: "RootQueryType",
fields: {
getAge: {
args: { name: { name: "name", type: new GraphQLNonNull(GraphQLString) } },
type: GraphQLString,
resolve(parent, args, context) {
return getAge(args.name, context);
}
}
}
}),
mutation: new GraphQLObjectType({
name: "RootMutationType",
fields: {
setAge: {
args: {
name: { name: "name", type: new GraphQLNonNull(GraphQLString) },
age: { name: "age", type: new GraphQLNonNull(GraphQLInt) }
},
type: GraphQLString,
resolve(parent, args, context) {
return setAge(args.name, args.age, context);
}
}
}
})
});
Last but not least, we do the initialization of the Kinvey Flex Service. There is a single function registered, which is called graphql(). On execution of that function, a call to the method exposed by the graphql package is triggered, passing the already declared schema and the body parameters coming with the request.
flex.functions.register("graphql", (context, complete, modules) => {
/**
* Since Flex functions get executed within different contexts (app environments),
* the information carried within the "context" and "modules" might
* differ. So, for each GraphQL request the respective function call's context needs
* to be prepared.
*/
const graphqlArguments = {
schema,
source: context.body.query,
contextValue: { flex, context, modules }
};
// FIRE!
graphql(graphqlArguments)
.then(data => complete().setBody(data).ok().next())
.catch(error => complete().setBody(error).runtimeError().done());
});
Kinvey CLI
Cool! At this point, we have everything we need to run a Flex Service. All we need to do is to tie together the Node.js project and the Flex Service we created using Kinvey Console. This is done using the Kinvey CLI command-line utility that we will install next. Open a terminal window and type the following:
npm install -g kinvey-cli
After it finishes installing, open a terminal window inside the project directory and run the following:
kinvey init
Use the same credentials that you use to log in to Kinvey Console when prompted. You also need to name the profile that Kinvey CLI will create for you. We’ll call our profile development because it's on our local machine. If you are a Kinvey customer, you might have a dedicated Kinvey Instance. If that's the case, enter the correct instance ID. If you do not have a dedicated Kinvey Instance, you can leave this option empty. You might also be asked about 2FA token, if two-factor authentication has been enabled for your account.
Having done that, let's now tell Kinvey CLI that we would like to be using that specific development profile, which we just created. To do so, please run the following:
kinvey profile use development
Next, we want to connect the Node.js project with the service from the Kinvey Console. To do so, run the following from the project folder:
kinvey flex init
The command prompts you to choose the application to use the service with, as well as the service you created. Here you will also have the possibility to choose on which service environment to deploy to. It uses the provided information to create a Flex Profile which it stores in a .kinvey file inside the project directory.
If you’ve reached this point and everything is alright, you can go ahead and deploy the service. Again, it’s important to run the command from the project folder.
kinvey flex deploy
The output should contain a message to the effect that a deploy job has been initiated. Uploading the code and provisioning server resources to your service may take a minute or two, that’s why you need to monitor the progress before you move forward. You can monitor the progress of the job by running the following:
kinvey flex status
The status will start at NEW then switch to UPDATING and finish at ONLINE. There will be no automatic notifications when the deploy is finished. You will need to manually check the service deployment status via the command given above, even if it means running it several times until you see the Online status.
On the image from above, you can see that initially the service was deployed with version 8.0.0. The version number is quite high, since I've done some deployments until I got it on a final state. Once we requested a new deploy, the new version was already visible on the deploymentVersion attribute of the log message. You can see that I've called the status command twice (with a timeframe of about 4 minutes), until I've seen the new version deployed and online.
Once the deploy job has finished, you can go to Kinvey Console, navigate to Services, choose the service you deployed to using Kinvey CLI, and after you click the FlexFunction Handlers tab, you can verify that you see the "graphql" handler defined in our code. This means our service is online.
Setting Up the Endpoint
As a next step, we will set up a Custom Endpoint. We do that by navigating to the Apps section of Kinvey Console, selecting the correct app (click the environment name that you are using for this tutorial), and then going to Custom Endpoints in the left-hand side navigation.
Then we create an endpoint, which should be backed by a microservice, preferably with the same name as the function—"graphql."
From the next window, we select the Flex Service we created, followed by the handler that we’ve registered.
Testing the Service
At this point, we are ready to test our GraphQL API! Let's now head to the API Console which you’ll also find in the left-hand side navigation of your app. Let's then choose the "graphql" endpoint and a request type POST. Now we can go ahead and proceed with the following actions:
We can start with asking for the age of a friend of ours. Let's shape-up the request body as follows:
{
"query":"query{getAge(name:\"Nick\")}"
}
This should result in a message, telling us that we haven't set age for them.
Now we can proceed and set the age for Nick. Let's shape-up the request body as follows:
{
"query":"mutation{setAge(name:\"Nick\",age:30)}"
}
Let's see how that reacts...
Okay, let's now verify that it worked! We'll execute the same query as we did before.
Woooow! At this point we've seen how the API behaves. We can successfully read and update data from the Kinvey Collection using GraphQL.
I hope you enjoyed the article and created your first amazing GraphQL API with the help of the Kinvey Platform!
I would appreciate any comments and questions! Thank you!
Bilger Yahov
Bilger is an AWS Certified Solutions Architect, currently supporting customer software engineers of Kinvey in the process of designing the best possible software solutions for enterprise mobile and web applications. His goal is to see Progress Kinvey as a leading worldwide serverless cloud backend provider, and he enjoys building software solutions on it that increase developer productivity.