Building a client database of people in React
Tags: javascript, nextjs, react, webdev
Published: 2021-10-11 22:47:34

Ever wondered how to get access to a whole lot of information about people on the internet? Like, any information about anyone?

> as you proceed reading this article, you'll come across a section that talks about protecting your API key on the server. If you want to learn more about how you can do that to your API endpoints, you should take a look at [this piece](https://meje.dev/blog/mask-api-urls-with-api-routes)

In this article, we’ll be building a client-side application with ReactJS on the web that’ll integrate [Kelvin Data API](https://www.kelvindata.com/) at the frontend. The Kelvin Data is an API platform that allows you to access the profile of people on the web.

You can search for a specific person, either with their email address, LinkedIn profile (here, you’ll have to provide the person’s LinkedIn URL. i.e. https://linkedin.com/in/example-person ), or their phone numbers.

Now, let’s see how we can create an app that we’ll consume this API with. But, before you read this article any further, you should have a basic knowledge of:


- React,
- Data fetching with Hooks in React,
- Conditional rendering in React,
- String/template Literals in JavaScript,
- React components and props 


## The KelvinData dashboard.

When you signup on to the platform, you’ll have access to a personalized dashboard that you can use to watch your subscriptions, manage your API keys, and do a lot more.


![kelvinData dashboard](https://paper-attachments.dropbox.com/s_02939414880CFC840FE2DC108AA323D4FBC7B5589C807448FBDF6362BD42B96D_1633695407517_file.jpeg)


A search playground is also on the dashboard where you can test the features of the API.

You can decide to search for anyone, either with their names, email addresses, LinkedIn profiles, or phone numbers. This article is going to cover how you can search for people with their full name alone.


## Getting Started

For the scope of this article, we’ll be using NextJS to bootstrap our app. This does not mean that the [create-react-app](https://create-react-app.dev/) library wouldn’t work. You can make use of anyone that you find convenient. We’re using nextjs because of its simplicity. You can read more about NextJS [here](https://nextjs.org/docs/getting-started)

Let us start by installing the dependencies that we need in this project. We’d start by creating a nextjs app. The command below does that for us.

```bash
npx create-next-app [name-of-your-app]
```

We’ll make use of the `"styled-components"`  library for styling our app, and the `"axios"` library to fetch data from the API. We wouldn’t be covering much of the styling aspect in this article. You can find the full app styles here.

Let’s get the dependencies above by typing the command below into our terminal.

```npm
npm install axios styled-components react-icons
```

Let us have a look at the file structure of the app below. We’ll focus on the important files that we need in this app, so it’ll be concise.


    |--pages
    |   |-- api
    |   |   |-- users.js  
    |   |-- _app.js
    |   |-- index.js
    |--src
    |   |-- components
    |   |     |-- Card.js
    |__ .env.local


## Overview of the components in our Next.js app

In this section, we are going to see the different files that make up the architecture of this project, and their respective functions below.

The `pages` directory is where all the routing of the app takes place. This is an out-of-the-box feature of Nextjs. It saves you the stress of hard hard-coding your independent routes.

- `pages/api`: the api directory enables you to have a backend for your nextjs app, inside the same codebase, instead of the common way of creating separate repositories for your REST or GraphQL APIs and deploying them on backend hosting platforms like Heroku, and so on.

With the `api` directory, every file is treated as an API endpoint. If you look at the `api` folder, you'll notice that we have a file called `user.js` in it. 

That file becomes an endpoint, which means an API call can be performed using the path to the file as the base URL.

```javascript
const getData = async() => {
  axios.get("/api/users")
   .then(response => response())
   .then(response => console.log(response.data))
   .catch(err => console.log(err)
}
```
- `pages/_app.js`:  is where all our components get attached to the DOM. If you take a look at the component structure, you’ll see that all the components are passed as `pageProps` to the `Component` props too. 

It is like the `index.js` file when using Create-React-App. The only difference here is that you are not hooking your app to the DOM node called “root”

```jsx
React.render(document.getElementById("root), <App />)
```
    
- `index.js` is the default route in the pages folder. That is where we'll be doing most of the work on this project. When you run the command below, it starts up a development server and the contents of `index.js` are rendered on the web page.

```npm
npm run dev
```

- `Card.js`: is the component that holds displays the data we get from the API on the webpage


- `.env.local`: is where we’re storing the API key that’ll enable us to consume this API.


## Writing the server-side API call.

In the previous section, we saw the files that we'll be interacting with and their specific functions. In this section, we would have a look at how we can consume the API.

The reason why we're writing the API call at the server-side is for securing our API key, and Nextjs already makes it an easy task for us. 

With the API routes in Nextjs, we can perform our API calls without the fear of our API keys being revealed on the client-side. 

You may have been wondering what the essence of the environment variable in the `.env` file is, in this scenario. 

The environment variable (which is our API key) can only be available in `development` mode. That is why we can do something like `process.env.api_key`, and get access to the environment variable. 

But, the moment you deploy your app to platforms like netlify or vercel, the mode changes to `production`, which makes the nodejs `process` object unavailable on the client-side. 

Now that you have seen the reason why need to write a server-side API call. Let's get to it right away.
```javascript
// users.js
import axios from "axios"
   
export default async function users(req, res) {
    const {
      query: { firstName, lastName },
    } = req;
    
    const baseUrl = `https://api.kelvindata.com/rest/v1/search-v2?    lastName=${lastName}&firstName=${firstName}&apiKey=${process.env.KEY}`;
    const response = await axios.get(baseUrl);
    res.status(200).json({
    data: response.data,
  });
}
```
In the snippet above, we created an asynchronous function called, `users`. It takes in two arguments, `req` which stands for “request” in full, and `res` which is “response” in full.

The `req` argument has some properties, (or “middlewares” as the Nextjs docs calls it) that can be accessed when we’re consuming our API, one of them is `req.query`. 

You’ll notice that we destructured the `query` property in the snippet above, so we would be able to pass those variables as values to the query properties of the API endpoint. Take a look at it below. 

You can read more about the in-built middlewares that comes with the `req` argument [here](https://nextjs.org/docs/api-routes/api-middlewares).

```javascript
const {
  query: { firstName, lastName },
} = req;
```
The base URL takes the destructured query properties as values and the `apiKey` is gotten from the `.env` file via the nodejs `process` object.

The destructured query properties are taken as requests that will be sent from the input values of the form component (which we’ll be creating in the next section) to the API, once it is received, we get a response that corresponds with the request we made.
```javascript
const baseUrl = `https://api.kelvindata.com/rest/v1/searchv2?  lastName=${lastName}&firstName=${firstName}&apiKey=${process.env.KEY}`;
```
The next process the function has to complete is the response from the asynchronous API call. The snippet below assigns the API call which we are perfoming with the `axios`  library to a variable, `response`.

On the next line, the `res` argument uses the `status` method which is used to send a JSON response to us, then we can assign the response variable as a property of `data`

You can read more about the various HTTP status codes [here](https://dillionmegida.com/p/http-status-codes/)

```javascript
const response = await axios.get(baseUrl);
res.status(200).json({
  data: response.data,
}); 
```
## Building the form component

In the previous section, we saw how we can write our API calls on the server-side. we’ll be using that API call in this section as we create the form component that will send the first and last name values from the input fields to API query parameters.

We’ll be keeping the code snippets short so that this article doesn’t get too long. Let’s start by taking a look at the content of `index.js` below.
```javascript
import React from "react";
import styled from "styled-components";
import axios from "axios";
import Card from "../../components/Card";
    
const Wrapper = styled.section`
  padding: 0 100px 0 100px;
  height: 100%;
  width: 100%;
    
  // remaining style goes here
`;
    
const UserAPIComponent = () => {
const [userData, setUserData] = React.useState([]);
const [firstName, setFirstName] = React.useState("");
const [lastName, setLastName] = React.useState("");
    
const getuserData = async () => {
  // api call goes here
};
    
const handleSubmit = (e) => {
   e.preventDefault();
   getuserData();
};
    
return (
   <Wrapper>
     <h3>Search for Anyone</h3>
     <form onSubmit={handleSubmit}>
        <label htmlFor="firstname">First name</label>
        <input
          type="text"
          name="firstname"
          value={firstName}
          placeholder="First Name"
          onChange={(e) => setFirstName(e.target.value)}
        />
        <label htmlFor="lastname">Lastname</label>
        <input
          type="text"
          name="lastname"
          value={lastName}
          placeholder="Lastname"
          onChange={(e) => setLastName(e.target.value)}
        />
        <div className="btn-container">
           <Button>Search</Button>
        </div>
      </form>
      <div className="results-container">
        {userData ? <Card result={userData} /> 
        : "loading..."}
      </div>
  </Wrapper>
 );
};

export default UserAPIComponent;
```
Since this is a React component that is receiving data from an API endpoint, it should have an internal state of its own. The snippet below shows how we defined the different state variables with React Hooks.

```javascript
const [userData, setUserData] = React.useState([]);
const [firstName, setFirstName] = React.useState("");
const [lastName, setLastName] = React.useState("");
```

The `firstName` and `lastName` variables receive the text values that are typed into the input field by anyone.

The `userData` state variable helps us store the response that we get from the API call in an array, so we can use the JavaScript `map()` method to render the response on the webpage.

Notice how we’re using `axios` to get data from the API endpoint, and how the base URL is not a typical `https://` URL, instead, it is the path to the file where we made the server-side API call before.

```javascript
const getuserData = async () => {
axios.get(`/api/usersfirstName=${firstName}&lastName=${lastName}`, {
       headers: {
         Accept: "application/json",
         "Access-Control-Allow-Origin": "*",
       },
})
  .then((response) => response)
  .then((response) => {
    setUserData(response.data.data); 
  })
  .catch((err) => console.log(err));
};
```   

We repeat almost the same process in the `user.js` file, but this time around with the necessary fetch headers and assignment of the state variables to the API query parameters.

In the second `.then()` method, we ensured that the response from the API call is treated as an array, hence the need for `response.data.data`. If we had stopped at `setUserData(response.data)`, JavaScript will throw a type-error whenever we try to do the following: 
```javascript
{
  userData.map((users, index) => {
    return (
      // some JSX
    )
  })
}
```
This is because `response.data` is having an object data-type, and the `map()` operation does not work on JavaScript objects, only arrays. 

The  `handleSubmit` handler ensures that the webpage isn’t reloaded at every API call, upon the click of the search button.

```javascript
const handleSubmit = (e) => {
  e.preventDefault();
  getuserData();
};
```
## Building the card component

The card component serves as the presentational component of the app. Data gets passed down to it through the usage of props in React. 

Once again, for the sake of brevity, we’ll not be taking a look at all the major content of the card component. Let’s take a look at the modified structure below

```jsx
import React from "react";
import { FiUser } from "react-icons/fi";
import styled from "styled-components";
    
const Wrapper = styled.div`
  height: 56%;
  width: 32%;
  margin: 0 15px 30px 0;
  background: #fff;
  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.05);
  border-radius: 8px;
  padding: 0 15px 0 15px;
`;
    
const Card = ({ result }) => {
  return (
     <>
      {result.map((users, index) => {
        return (
           <Wrapper className="users-card" key={index}>
             <p>
               <span>
                 <FiUser />
               </span>
                 {users.name.full !== null ? 
                   users.name.full 
                   : "no name data" }
             </p>
             <p>Title: {users.employments[0].title}</p>
             <p>
               Organization:
                {
              users.employments[0].organization.name !== null
              ? users.employments[0].organization.name
              : "no employment info"}
             </p>
          </Wrapper>
        );
      })}
   </>
  );
};
    
export default Card;
```
The `result` prop is passed to the `Card` component, which in turn, gets utilized in the App component (in `index.js`). 

The ternary operator checks for the validity of `userData`, if it is `true`, the `Card` component is rendered. If it isn’t, the `loading…` string is displayed on the webpage.

```jsx
<div className="results-container">
  {userData ? 
    <Card result={userData} /> 
    : "loading..."
  }
</div>
```
You’ll also notice how we’re performing conditional rendering with the ternary operator in the “Organization” paragraph below. 

If there isn’t any data that corresponds with a user’s organization details, the `"no employment info"` string is displayed. If there is, the user’s organization is displayed.

```jsx
<p>
  Organization:
  {users.employments[0].organization.name !== null
  ? users.employments[0].organization.name
  : "no employment info"}
</p>
```
## Conclusion

The video below shows the end result of what we have been building all along from the beginning of this article. You can always check your browser’s dev tools, move to the network tab, to see if the API key is showing or not.

![kelvin data demo app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hyrryqxgkud38fffeg7.gif)

If you want to have a look at the code base, here’s the [link](https://github.com/Caleb335/article-example-projects/blob/master/src/container/users/index.js) to it. 

The link points to the specific file (of this article) in the repository. You can check out my other article demos [here](https://exdemo.netlify.app) and also have a look at the repository as a whole.

If you read this article up till this point, thank you for doing so, and please don’t forget to share it.