Developers require different tools to help in their development cycle. There are countless options when it comes to softwares or platforms and choosing one is often difficult. With a never-ending supply of new resources to try and libraries for almost everything released daily, everyone has their own tool preferences.
In this article, we will focus on NextJS and break down the setup with Strapi.
I will walk you through 5 simple steps to set-up an online store with product colour variation using the two tools mentioned above. It’s simple if you follow along! Let’s get started.
What is NextJS
NextJS is an open-source React framework created by Vercel that enables functionality such as server-side rendering and generating static websites for React based web applications.
The Project
We will be decoupling our project into frontend (NextJS) and backend (Strapi). Let’s begin by installing our NextJS packages into our frontend folder.
STEP 1 : Setup NextJS
yarn add next react react-dom @apollo/cilent
Inside the NextJS app, create a folder called pages and create a file index.tsx. Populate it with the code below:
import React from 'react'
const index = () => {
return (
<div>
'Hello World'
</div>
)
}
export default index
Next, add the typescript support for this project. First, create your tsconfig file with the command
Touch tsconfig.json
Then run yarn dev so NextJS can automatically install all the required packages to finish your setup.
You will also need to install bootstrap by installing
yarn add reactstrap bootstrap
In order to implement bootstrap, add a global stylesheet or layout component to the project.
Create a _app.tsx under pages and put the code given below you in it. This will allow us to add a custom stylesheet and certain headers that we need in our project. We will also add our apollo provider and client for us to connect in our strapi.
import type { AppProps } from 'next/app'
import Head from 'next/head'
import Layout from "../components/Layout"
import {InMemoryCache, ApolloClient } from '@apollo/client'
import { ApolloProvider } from '@apollo/client';
function MyApp({ Component, pageProps }: AppProps) {
const API_URL = "http://localhost:1337"
const client = new ApolloClient({
uri: `${API_URL}/graphql`,
cache: new InMemoryCache()
});
return (
<>
<ApolloProvider client={client}>
<Head>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossOrigin="anonymous"
/>
</Head>
<Layout>
<Component {...pageProps} />
</Layout>
</ApolloProvider>
</>
)
}
export default MyApp
Outside the pages folder, create a folder named components and create a Layout.tsx file. In this file, we will add the navigation header and meta tags.
import React from 'react'
import Head from 'next/head'
import Link from 'next/link'
import {Container, Nav, NavItem} from 'reactstrap'
const Layout = (props) => {
const title = 'Welcome to HOV'
return (
<div>
<Head>
<title>{title}</title>
<meta http-equiv="X-UA-Compatible" content="ie=edge" charSet="utf-8"/>
<meta http-equiv="X-UA-Compatible" name="viewport" content="initial-scale=1.0"/>
</Head>
<header>
<style jsx>
{`
a {
color: white;
}
`}
</style>
<Nav className="navbar navbar-dark bg-dark">
<NavItem>
<Link href="/">
<a className="navbar-brand">Home</a>
</Link>
</NavItem>
</Nav>
</header>
<Container>{props.children}</Container>
</div>
)
}
export default Layout
Now we are ready to create items in our strapi dashboard!
STEP 2 : Setting up Strapi
What is Strapi
Strapi is a nodeJS based headless cms that will save you a lot of API development time through a user-friendly admin panel anyone can use
Before you install any dependencies, make sure you have at least NodeJS v12 and NPM v6 in your machine.
Now lets create our backend folder by using this command:
yarn create strapi-app backend-strapi
After running this command, strapi will let us choose what database we want to use. For this project, select MongoDB then fill all the database credentials. Default values should work if we have installed all the database drivers in our machine. We can also add a flag –quickstart which will use SQLite for the database.
We can now start our strapi project by running the command
yarn develop
You should see this screen show up in our browser; let’s fill it up with our credentials!
Now let’s create our content:
Select the Text field for the product name, Rich Text for the description and Media for all images.
Pro tip: For the description field, add minimum characters of 50 and max characters to 250 to avoid lengthy descriptions.
For the Name and Images fields we need to add a required parameter to make sure the data for these fields are not empty.
Now lets add entries on our Apparel Collection. Don’t forget to save and publish when you’re done.
We should now have 3 items on our collection that we will display in our frontend.
If we go to http://localhost:1337/apparels, you will see the url is still blocked with a 403 forbidden error.
This is a good practice by strapi to make sure our data is secured. To fix this, change the permissions rule under settings in the top right third section of the dashboard. Click roles under Users and Plugin section and edit the Public role. Allow find and findOne in the permissions.
Now go back to the url and you should be able to see the data we created.
Since we are using graphql apollo in NextJS, in order for us to accept graphql queries, we need to add graphql plugin in strapi marketplace
After we download the graphql plugin, restart the server by running yarn develop
Now if we try to get to the apparel collection using the url http://localhost:1337/graphql, you can see our entries in the query
STEP 3 : Displaying our Entries
Now let’s display the created entries into NextJS.
Create a ApparelList.tsx file in your components folder and populate with this code snippet.
import React from "react";
import { useQuery, gql } from "@apollo/client";
import {
Card,
CardBody,
CardImg,
CardText,
CardTitle,
Row,
Col,
} from "reactstrap";
import Link from "next/link";
const GET_APPARELS = gql`
query getApparels {
apparels {
id
name
description
image {
url
}
}
}
`;
const ApparelList = (props: Record<string, any>) => {
const { loading, error, data } = useQuery(GET_APPARELS);
const filterApparels =
data &&
data.apparels.filter((item) => {
return item.name.toLowerCase().includes(props.search);
});
if (loading) {
return <div>Loading...</div>;
}
if (error) {
console.log("Error");
}
return (
<Row>
{filterApparels &&
filterApparels.map((res) => (
<Col xs="6" sm="4" key={res.id}>
<Card style={{ margin: "3rem 0.5rem 20px 0.5rem" }}>
<CardImg
top={true}
style={{ height: "100%" }}
src={`${"http://localhost:1337"}${res.image[0].url}`}
/>
<CardBody>
<CardTitle>{res.name}</CardTitle>
<CardText>{res.description}</CardText>
</CardBody>
<div className="card-footer">
<Link
as={`/apparels/${res.id}`}
href={`/apparels?id=${res.id}`}
>
<a className="btn btn-primary">View</a>
</Link>
</div>
</Card>
</Col>
))}
<style jsx global>
{`
a {
color: white;
}
a:link {
text-decoration: none;
color: white;
}
a:hover {
color: white;
}
.card-columns {
column-count: 3;
}
`}
</style>
</Row>
);
};
export default ApparelList;
In the code above, we added a filterApparels variable that we will use for filtering any entries. We used a Link component from nextJS that will be used in navigating into selected items.
Go back to the index file under pages folder and import ApparelList.tsx file. Create an input field to search for any entries.
import React, { useState } from "react";
import { Col, Input, InputGroup, InputGroupAddon, Row } from "reactstrap";
import ApparelList from "../components/ApparelList";
const Home = () => {
const [query, updateQuery] = useState("");
return (
<div className="container-fluid">
<Row>
<Col>
<div className="search" style={{ margin: "3rem 0.5rem 20px 0.5rem" }}>
<InputGroup>
<InputGroupAddon addonType="append"> Search</InputGroupAddon>
<Input
onChange={(e) => updateQuery(e.target.value.toLowerCase())}
value={query}
/>
</InputGroup>
</div>
<ApparelList search={query}></ApparelList>
</Col>
</Row>
</div>
);
};
export default Home;
Accessing the url http://localhost:3000/, you should now able to see entries and a search field for to filter.
STEP 4 : Adding Variations to Items
By clicking the view button, we receive a white screen error. This is because we haven’t added entries for each item yet. To fix this, go back to the strapi dashboard and add the colour availability for each item. For example, if we navigate into t-shirt there will be a variety of colors to choose from.
To do this, create a new content type called colors. Since we already know how to create a content, just repeat the steps we did earlier with properties name(required), description, price(required), image(required).
We will add a special field called garments with a type of relation. Select the one-to-many-relation where every color added should have a relation with our apparel list.
Now we are ready to add a variation to our apparels! Let us add black and white variation for each item.
STEP 5 : NextJS Dynamic Routing
Go back to our code and display our variations. We will now use NextJS dynamic routing with route /apparels/id
Inside the pages folder, create another folder called apparels. Then create a dynamic file [id].tsx. This will match any route like /apparels/1 or /apparels/random-id
Now populate the dynamic file with this code snippet
import { useQuery, gql } from "@apollo/client";
import { useRouter } from "next/router";
import {
Button,
Card,
CardBody,
CardImg,
CardText,
CardTitle,
Col,
Row,
} from "reactstrap";
const GET_APPAREL_COLORS = gql`
query($id: ID!) {
apparel(id: $id) {
id
name
colors {
id
name
description
price
image {
id
url
}
}
}
}
`;
const Colors = () => {
const router = useRouter();
const { data, loading, error } = useQuery(GET_APPAREL_COLORS, {
variables: { id: router.query.id },
});
if (error) return "Error Loading Colors";
if (loading) return <h1>Loading ...</h1>;
if (data) {
const { apparel } = data;
return (
<>
<h1>{apparel.name}</h1>
<Row>
{apparel.colors.map((res) => (
<Col xs="6" sm="4" style={{ padding: 0 }} key={res.id}>
<Card style={{ margin: "0 10px" }}>
{res.image.map((img) => {
return (
<CardImg
key={img.id}
top={true}
style={{ height: 250 }}
src={`${"http://localhost:1337"}${img.url}`}
/>
);
})}
<CardBody>
<CardTitle>{res.name}</CardTitle>
<CardText>{res.description}</CardText>
</CardBody>
<div className="card-footer">
<Button outline color="primary">
+ Add To Cart
</Button>
<style jsx>
{`
a {
color: white;
}
a:link {
text-decoration: none;
color: white;
}
.container-fluid {
margin-bottom: 30px;
}
.btn-outline-primary {
color: #007bff !important;
}
a:hover {
color: white !important;
}
`}
</style>
</div>
</Card>
</Col>
))}
</Row>
</>
);
}
};
export default Colors;
The view button should work now! You can also see all the colour variations.
That’s it! We’re now done building out the functionality of the app.
Conclusion
The main objective of this article was to show you how to build apps in NextJS and Strapi.
You’ll see that most of the implementation was pretty easy because of the flexibility and structured layout that NextJS provides.
Use this as a base to build your own NextJS application in the future. If you found it helpful, share it around and tag us in your creations!
More from
Engineering
Importance of Design QA workflow
Marvin Fernandez, Engineering Manager
SQA questions to ponder
Joy Mesina, QA
Writing a Software Test Plan
Ron Labra, Software Quality Analyst