Leveraging Qlik Users API - Building a PWA Dashboard with Nextjs, Typescript & Chakra-UI
Tags: datascience, machinelearning, typescript, webdev
Published: 2021-10-04 23:21:07

#What is Qlik APIs
Qlik APIs for SaaS editions are public APIs that enables to build, extend and deploy powerful and engaging analytics into your applications, you can also build custom data-driven apps that's blazing fast and deliver high quality software for automations, aviation and education industries.

![qlik APIs plaform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rwf24hax0x412w1jeiz.png)

The platform delivers realtime data which is scaleable and maintainable in various form such us object store, data warehouse, streaming services and relational & non-relational repositories.

**You can read more about the API platform here: https://qlik.dev/apis**

##Introduction
With this Article we are going to focus and start using the Users API and build a powerful and scaleable dashboard platform. The platform will be build as Progressive Web App(PWA) that is installable in any device that supports modern browsers such us Chrome web browser. The framework that we will be building the platform is Nextjs which is a blazing fast framework built on top of Reactjs. For the UI components we will be using Chakra-UI component library which is light weight, super easy design system implementation library.

To understand and read more about PWA, Nextjs and Chakra-UI refer to the following links:

**PWA**
A progressive web application is a type of application software delivered through the web, built using common web technologies including HTML, CSS and JavaScript. It is intended to work on any platform that uses a standards-compliant browser, including both desktop and mobile devices.
Read more here: 
https://web.dev/what-are-pwas/

**Nextjs**
Next.js is an open-source development framework built on top of Node.js enabling React based web applications functionalities such as server-side rendering and generating static websites.
Read more about here: 
https://nextjs.org/learn/basics/create-nextjs-app?utm_source=next-site&utm_medium=homepage-cta&utm_campaign=next-website

**Chakra-UI**
Chakra UI is a simple, modular and accessible component library that gives you the building blocks you need to build your React applications.
I find Chakra-UI the best #React component framework https://chakra-ui.com Provides just enough to get started, implements sensible defaults, but is also very extensible and customisable because it uses styled system and emotion css.
 
https://chakra-ui.com/docs/getting-started


**Alright, enough of introduction let's focus on building the platform**

This is the app that we will be building:
![dashboard app screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9smem785c9s9q2nc8twp.png)

##Getting Started

In order to save you all some work, I have already setup a starter template, thats configured to the following configurations, remember again don't be confused and I will explain each packages that is used:

Here is the project starter template on github, download it and save it in your computer direcotry:
https://github.com/mirwaissh/starter-template


The template is A TypeScript starter for Next.js that includes all you need to build amazing projects 🔥

📏 ESLint — Pluggable JavaScript linter
💖 Prettier - Opinionated Code Formatter
🐶 Husky — Use git hooks with ease
📄 Commitizen - Conventional commit messages CLI
🚓 Commitlint - Lint commit messages
🖌 Renovate - Dependency update tool
🚫 lint-staged - Run linters against staged git files
👷 PR Workflow - Run Type Check & Linters on pull requests
🗂 Absolute import - Import folders and files using the @ prefix

Remember the goal with these configuration and packages are so we can have a solid and scaleable platform, all they are is just configuration and you can start looking at npm package managers for more information for each package. I will explain these packages later in the article, for now bear with me and we have not written any code yet. 


**To start the application:**

Once you have downloaded the template, go on and run the following command to install the packages that is required in _package.json_

```
yarn
```

After a successful packages installation run the following command to start the platform on dev mode:
```
yarn dev
```

the server now runs on:
**http://localhost:3000/**



### Building the UI Components

As mentioned before we will be using Chakra-UI for building our component, so go on and run the following command to install the packages:

```
yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
```

now that we have the packages installed, let's go and do some clean up and create our components directory structure

 header over to 
```
src/pages/index.tsx
```
and get rid of the entire div from top to bottom, so the Home page will return nothing at this moment. To clearify, it should look like following:

```
import Head from 'next/head';
import Image from 'next/image';

import styles from '@/styles/Home.module.css';

export default function Home() {
  return (

  );
}
```

create a new directory called components 
```
src/componets
```

3. inside the components directory, create a new component called Header.tsx 
```
src/componets/Header.tsx
```

and add the following code:
```
import React from 'react';
import { Box, Text } from '@chakra-ui/layout';

const Header: React.FC<any> = (): React.ReactElement => {
  return (
    <Box
      padding="2rem"
      color="blue"
      fontSize="1.3rem"
      fontWeight="bold"
      backgroundColor="yellow"
    >
      <Text textAlign="center">Dashboard</Text>
    </Box>
  );
};

export default Header;

```
This a simple React component that returns a text with "Dashboard". So remember in plain html, we had div and p tag, however in chakra-ui we have box and Text, that the only difference. One really cool feature about chakra is you can type css in js, save you time and effort.

**We are good for now.**

 header over to 
```
src/pages/index.tsx
```

and update it with following code
```
import Head from 'next/head';
import Header from '@/Components/Header';
import { Box } from '@chakra-ui/layout';
import styles from '@/styles/Home.module.css';

export default function Home() {
  return (
    <Box>
      <Head>
        <title>Qlik cloud users</title>
      </Head>
      <Header></Header>
    </Box>
  );
}
```

We are adding the Header Component to render in the Index, and also adding a title to the web page, inside the Head of the page. This is how you update webpage title in Nextjs.


**Cool**

Now Lets go and create Our UserList module inside the component directory
```
src/pages/UserList.tsx
```

and update it with following code
```
import React from 'react';
import { Box, Text } from '@chakra-ui/layout';
import {
  ListItem,
  UnorderedList,
  Image,
} from '@chakra-ui/react';

interface UserProps {
  users: Array<any>;
}

const UserList: React.FC<any> = ({ users }: UserProps) => {
  return (
    <Box>
      <Box>
        <Text marginBottom="2rem" fontSize="0.9rem" textAlign="center">
          Active Users
        </Text>
      </Box>
      <UnorderedList
        padding="0"
        margin="0"
        listStyleType="none"
        display="flex"
        flexDirection="column"
        alignItems="center"
      >
        {users.map((user) => (
          <ListItem>
            <Box width="100px" height="100px">
              <Image
                width="100%"
                height="100%"
                borderRadius="10px"
                src={user.imageSrc}
              ></Image>
            </Box>
            <Box>
              <Text textAlign="center" textTransform="capitalize">
                {user.name}
              </Text>
            </Box>
          </ListItem>
        ))}
      </UnorderedList>
    </Box>
  );
};

export default UserList;

```
This components accepts and Array of users and render a list item for each user. Remember this users array comes as props, we will be passing in the next step.

great... so far so good.

Now again, Now Lets go and create Our HomeComponent module inside the component directory
```
src/pages/HomeComponent.tsx
```
and add the following code:
```
import React, { useState, useEffect, useCallback } from 'react';
import UserList from './UserList';
import { Box } from '@chakra-ui/layout';


const HomeComponent: React.FC<any> = (): React.ReactElement => {
  const [users, setUsers] = useState<object[]>([]);
  const [loading, setLoading] = useState<null | boolean>(null);
  const [requestError, setRequestError] = useState<string>('');

  return <Box>{!loading && <UserList users={users}></UserList>}</Box>;
};

export default HomeComponent;
```

at this stage we want to have the users data fetched from the Qlik Users API so we can send it as a props to UserList Component. We see that we have three different states, users;which is the data that we will save, loading; to show a spinner while the data is fetched from the server and requestError to show and error message if there is an erorr.



***But hold on, before going to data fetching, we still have some work to do in the UI part.***


header over to component directory and create a new component called 'Footer.tsx'

and add the following code:

```
import React from 'react';
import { Box, Text } from '@chakra-ui/layout';

const Footer: React.FC<any> = (): React.ReactElement => {
  return (
    <Box position="absolute" bottom="0" width="100%">
      <Text fontSize=".8rem" textAlign="center">
        &copy; 2021 myCompany
      </Text>
    </Box>
  );
};

export default Footer;
```

We are almost there...


navigate back to 'src/pages.index' and import 'HomeComponent' and 'Footer', render HeaderComponent under Header and then Footer at last. The code should look like this:
```
import Head from 'next/head';
import HomeComponent from '@/Components/HomeComponent';
import Header from '@/Components/Header';
import Footer from '@/Components/Footer';
import { Box } from '@chakra-ui/layout';
import styles from '@/styles/Home.module.css';

export default function Home() {
  return (
    <Box>
      <Head>
        <title>Qlik cloud users</title>
      </Head>
      <Header></Header>
      <HomeComponent></HomeComponent>
      <Footer></Footer>
    </Box>
  );
}

```

***Awesome, we are done with UI building***



### Building the API Connect Functionality

Create a new directory in the root directory
```
./api
```

headover to './api' and create a new module called 'connect.ts'
```
./api/connect.ts
```

inside 'connect.ts', create a string constant with the name of APIKEY that will store the API which you will get from your Qlik tenant account once you have signed for a subscription. You will find this API in your account setting.

After that, create another string constant that will hold the url of your tenant called apiURL. This URL is unique for your account once you subscribe to the platform.

so the code should look like this:
````
const APIKEY: string =
  'gf2634985326856r234gbk23daslfbcksagfk9326yrigfcjasjfcksafcbkasbcakccvkasbcksabckasgbkc';
  
const apiURL: string = 'https://your-tenant.us.qlikcloud.com/api/v1';
````

at this stage we are interested to make a call to the API and get the users. In order to call to in an API, we will be using a very nice package called axios, let's and install it:
```
yarn add @axios
```


***We need to understand a concepts here:***

In order to prevent repeating our self and also reuse the API call logic, let's create a nice function that will call the API for as with different url parameter, however, with the same base url.

This function will accept the baseURL and the APIKEY in the headers key, as Authorization type of Bearer.

Now you might be asking, sorry what? yes I got you. just to make your life easier, it's a standard way of calling to any API which requires you some sort authentication via a concept called JSON Token, or your APIKEY, same name. It's basically your password, but not exactly a password, it's some sort of cryptic long character secured letters and number just to verify that you are allowed to make those API request.

You can read about these concepts here:
https://community.auth0.com/t/how-to-use-a-token-with-axios/63171/6

Okay, so the code should look like this:

````
import axios from 'axios';

const APIKEY: string =
  'gf2634985326856r234gbk23daslfbcksagfk9326yrigfcjasjfcksafcbkasbcakccvkasbcksabckasgbkc';
  
const apiURL: string = 'https://your-tenant.us.qlikcloud.com/api/v1';

export const authAxios = axios.create({
  baseURL: apiURL,
  headers: {
    authorization: `Bearer ${APIKEY}`,
  },
});

````

Remember we have set the base url to 'https://your-tenant.us.qlikcloud.com/api/v1'

anything that will come after apiURL string, will response a different data, and that's what we want.

you can read more and find about the url structure for the Users API in the following link:
https://qlik.dev/apis/rest/users

Okay great, we are done setting up our API connection, now lets go and make api calls in the HomeComponent component.


###Back to UI, to Make API Calls

Its time to make sense of the UI and API Data. First import authAxios function which we created, in to HomeComponent.

Inside HomeComponent, lets create a function called fetchUsers with the following code:

````
  const fetchUsers = useCallback(async () => {
    setLoading(true);
    try {
      const users = await authAxios(`${apiURL}/users`);
      setUsers(data);
      setLoading(false);
    } catch (e) {
      setRequestError(e.message);
    }
  }, []);
````

this is an asynchronous function that uses useCallback hook just to cache the data. It's main functionality is to to make a request '/users' end point and return the response using await keyword.

the response and data schema looks like following:
````
{
  "links": {
    "self": {
      "href": "string"
    },
    "next": {
      "href": "string"
    },
    "prev": {
      "href": "string"
    }
  },
  "data": [
    {
      "id": "string",
      "tenantId": "string",
      "subject": "string",
      "status": "active",
      "inviteExpiry": 0,
      "name": "string",
      "created": "2021-10-04T22:43:51.472Z",
      "lastUpdated": "2021-10-04T22:43:51.472Z",
      "picture": "string",
      "email": "string",
      "roles": [],
      "zoneinfo": "string",
      "locale": "string",
      "preferredZoneinfo": "string",
      "preferredLocale": "string",
      "links": {
        "self": {
          "href": "string"
        }
      }
    }
  ]
}
````


this is the response from the api call. At this moment we are interested in data key, which an array of object of users information.

We then update our state, so we can render the data into UI.

the final code should like the following:
````
import React, { useState, useEffect, useCallback } from 'react';
import UserList from './UserList';
import { Box } from '@chakra-ui/layout';
import { authAxios, apiURL } from 'api/connect';


const HomeComponent: React.FC<any> = (): React.ReactElement => {
  const [usersData, setUsers] = useState<object[]>([]);
  const [loading, setLoading] = useState<null | boolean>(null);
  const [requestError, setRequestError] = useState<string>('');

  const fetchUsers = useCallback(async () => {
    setLoading(true);
    try {
      const users = await authAxios(`${apiURL}/users`); 
      setUsers(users.data);
      setLoading(false);
    } catch (e) {
      setRequestError(e.message);
    }
  }, []);

  useEffect(() => {
    fetchUsers();
  }, []);

  return <Box>{!loading && <UserList users={usersData}></UserList>}</Box>;
};

export default HomeComponent;

````

### Configuring for the PWA installable
 
We have a last thing to do, in order to make this app a valid pwa application, we need to add a manifest.json configuration file that in the public directory of nextjs app.

the manifest.json contains the following configuration:
````
{
    "name": "dashboard",
    "short_name": "dash app",
    "icons": [
      {
        "src": "/icon.svg",
        "sizes": "1024x1024 any",
        "type": "image/svg"
      }
    ],
    "theme_color": "#FFFFFF",
    "background_color": "#29A6A6",
    "start_url": "/",
    "display": "fullscreen",
    "orientation": "portrait"
  }
````

by adding this configuration, your app will be installable in any supported chrome devices, it will be have as native mobile app.


#Conclusion

The aim of this application was to showcase, how to build a simple application around Qlik Powerful and smart based on AI and Machine learning platform APIs. There are a lot of great information that is right there for you to use and build creative applications. I strongly recommend to start playing with these APIs and the motivation and creativity will come by itself.