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
In this article, we’ll be building a client-side application with ReactJS on the web that’ll integrate Kelvin Data API 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.
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 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
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.
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 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.
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 aspageProps
to theComponent
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”
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 ofindex.js
are rendered on the web page.
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.
// 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.
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.
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
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.
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.
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.
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:
{
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.
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
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.
<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.
<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.
If you want to have a look at the code base, here’s the link to it.
The link points to the specific file (of this article) in the repository. You can check out my other article demos here 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.
Top comments (6)
Great read!
Thank you! 😊
It was amazing .
I'm glad you found it helpful @arkadeepnag 🍷
Nice a Blog
Thank you.🍷