In this tutorial, we will create a React app for a small business that organises meetups in a several cities and deploy it to IBM Cloud. Each event has a list of attendees and practical informations including the address that we will display using the popular JS library Leaflet! You'll find the code for this tutorial in my gihub repo.
The app must enable the user to view the upcoming events and their details and to sign up for them. Here is what the app architecture will look like by the end of this tutorial:
The client will request (1) the site statically served and stored in a Cloud Object Storage bucket. The app will call functions (4) for interacting (5) with a Cloudant database (that we will populate) through public API endpoints (2 and 3).
Set up your IBM Cloud account for free
For anyone getting started with Cloud Infrastructure, IBM Cloud is an amazing service to work with. First, suscribe! It’s free and good news you won’t have to enter any credit card details, you even get 200$ for free if you sign up for a paid account! Go to https://cloud.ibm.com/registration and follow the steps below:
Set up your serverless app in IBM Cloud
So far so good, now that our IBM Cloud is set up, we can dive into the interesting part. First, let's create the database for storing the events and all of their attributes. As you can imagine, an event has its own host, location, date, programme, etc. The most important here is the attendees attribute that will be represented as a list containing all the people that signed up for the event.
To create a database, we go to Catalog and type Cloudant in the search bar. Then click on Cloudant service. You automatically land on the creation page as follows:
All we have to do to get started is to fill in a name for our instance and the location. Remember, choose one region and stick to it or you may end up with unwanted errors when connection your Cloudant instance to your Functions. We of course are working with our free Lite plan for this tutorial. Then, press Create. IBM Cloud will set up everything for you for the next step.
Go to your instance, if you cannot find it, just type its name in the searchbar at the top of the dashboard. You should see something like this:
Click on Launch Dashboard, it will open your instance dashboard in another tab. The great thing with that view is that you can visualise, monitor and secure your database with great ease. Now, we need to store our events somewhere. To do so, click on Create Database on top of the page. Choose a name such as meeto for example, select non-partitioned and create your database. In my case, to speed up things up, I simply populated the database with 11 documents representing events.
Great! We now have a database ready. Let's add functions to actually manipulate and read those data. To do so, we are going to create some actions: actions are simple functions specifically designed to deal with IBM Cloud services. This is an stunningly easy way to deal with data in serverless apps.
Let's go in Functions: as before, just type the name in Catalog and click on the service icon. Once you get on the presentation page, just click on Create function to get started and you should see this:
You might wonder which card you should click on. No worries, actually the basic block of those options are the actions: this is simply a function that is called in a runtime environment of your choice (in our case, nodejs). Sequences are chains of successive actions and will be very useful to format and return the data as we want them. Moreover, sequences are powerful in the sense that they can connect our actions to other IBM Cloud services instances.
Let's go back to our app: we want the user to view the list of meetups and click to show his interest for one of them. Therefore, we need 2 things: a way to get all of the entries and a way to update them individually.
Let's start with the former and first create an action called set-read-input and create a package (just by giving it a name):
Replace the default code with:
function main(params) {
return {
params: {
include_docs: true
}
};
}
This just indicates that we want our future API to return the data when a request is made.
Now, we want to put this action into a sequence. So, click on Enclosing Sequences on the left and add a new sequence (e.g read-events-sequence). Again, choose the same package you just created (you will quickly find out that everything must be consistent).
Great, our sequence is initialised! No we want to link it to our Cloudant instance. Click on the recently created sequence and click on Add. Now, choose Use Public and Cloudant. In the select dropdown, choose list-documents to tell the service what we want to do with the data. Finally, create a binding names bindings-for-meeto.
Now, the same way, add a new action (e.g format-events) that will handle the data and send them to the client later.
And replace the code with:
function main(params) {
return {
entries: params.rows.map((row) => { return {
id: row.doc._id,
rev: row.doc._rev,
image: row.doc.image,
title: row.doc.title,
topic: row.doc.topic,
location: row.doc.location,
description: row.doc.description,
date: row.doc.date,
attendees: row.doc.attendees,
host: row.doc.host,
currency: row.doc.currency,
duration: row.doc.duration,
price: row.doc.price,
programme: row.doc.programme,
gps: row.doc.gps
}})
};
}
As you can see, all the attributes are returned. This is the place to do some preprocessing if you want to or even some sanity checks!
Our sequence is now complete! Let's focus on the update part now:
Exactly as before, start by creating an action (e.g prepare-event-for-save) and replace the code with:
function main(params) {
if (!params.params.id) {
return Promise.reject({ error: 'Missing event id.' });
}
if (!params.params.attendees) {
return Promise.reject({ error: 'Missing attendees.'});
}
return {
doc: {
_id: params.params.id,
_rev: params.params.rev,
attendees: params.params.attendees,
image: params.params.image,
title: params.params.title,
topic: params.params.topic,
location: params.params.location,
description: params.params.description,
date: params.params.date,
attendees: params.params.attendees,
host: params.params.host,
currency: params.params.currency,
duration: params.params.duration,
price: params.params.price,
programme: params.params.programme,
gps: params.params.gps
}
};
}
You surely got this part: the params are actually coming as part of the body from a HTTP request and is used to update the document in Cloudant. Note that the rev and id are necessary here to tell Cloudant which document is concerned. Again, enclose your newly created action into a new sequence. Then, reproduce the steps above to create a new connection between the sequence and Cloudant.
The final Functions dashboard should look like this for your 2 sequences:
Final touch for the serverless part of this tutorial: the API! We do have functions but they're basically useless if we can't call them. Let's remedy that!
For each sequence, click on Web Action and check the box as follows:
Now, head into the API Management tab in Functions and start creating an API. Simply give it a name and a base path (e.g meeto and /meeto): so every time you call it, you start your API urls with "/meeto/". Now, create an operation: choose GET for the first sequence as we just ask for data and POST for the second as we are pushing data to the database. The pathname is yours to choose but you should make it consistent with its purpose so anyone can understand it. Careful now, choose the package name and the corresponding action. You now understand how everything is connected: those endpoints you just created will connect to your functions!
Great, you are set up! Copy the API url, you'll need it in a moment!
Setup your React client
Finally, we've come to the final part: the client. Since this is not a tutorial about React, we are not going to focus on the implementation details. So simply clone my gihub repo and change the API Url in src/api/events.js.
You'll notice how simple our client code is for dealing with APIs!
export const getEvents = () => axios.get(apiUrl + "/events");
export const updateEvent = (data) => axios.post(apiUrl + "/attend", { params: data, headers: {"Access-Control-Allow-Origin": "*"} });
Of course, please feel free to look into the React code to see how data are collected and rendered dynamically.
Deploy your app
If you made it to that point, congrats! This is the final chapter of our tutorial. You'll see how easy it is to serve your static website using the Cloud Object Storage Service.
First go to COS (you should know the trick by now) and create a new instance. Now, click on Create a bucket and choose to customise it. Needless to say, choose an unique name for your bucket and select Resiliency Regional (feel free to take a look at the other options, we just don't need them for the purposes of this tutorial). Important: in Location, select the one you've been using it for Cloudant. Scroll down to the Static website hosting part and add a new rule (this is the fun part): keep the routing rules as they are and type index.html. This index.html will be the entry point of our app when ready for deployment. Make sure that Public access is on or you won't be able to reach your app!
Now, go back into the repo and simply run the commands npm install and then npm run build: this will install all the dependencies the project is built on and create a production build for our app. Once this is done, simply drag and drop the newly created build folder into your bucket. Go into the Configuration tab and look for the static website hosting endpoints: you can now access to your app online! Congratulations!
The grid of events is dynamically rendered once the data have been retrieved from our Cloudant database through our Functions API! Click on GO! on one of the events to access its details page:
All the informations about the event are shown, in particular the list of attendees. Note how the location (gps attribute in Cloudant) is beautifully displayed in a map using the great Leaflet wrapper for React, react-leaflet! Try to add your name in the form below the map: your name will be directly added in the database and rendered in the list!
Conclusion
This was just an introduction about some of the most widely used services IBM Cloud offers. There are a lot more of them, including Kubernetes, Machine Learning services (the famous IBM Watson for instance!), ... and you should definitely check them out!
A next post is en route to introduce AppID: this is a great service for authenticating users on websites but also securing pretty much every resource in IBM Cloud. I cannot stress enough that anyone in possession of your API URL can mess up your database. We'll see in that post how you can restrict your resources to authorised users using AppID.
I do hope you enjoyed this tutorial and found it very useful for your upcoming projects!
















Top comments (1)
Hi @djerb , great post. Really useful, got me up and running. When can we expect the post on AppID?