/writing/full stack development/how-to-create-a-full-stack-application-with-next-js
§ full stack development·12 min read·October 20, 2023

How to Create a Full-Stack Application with Next.js?

Can Next.js be used for full stack development? This article will help to understand the concept of next.js with the steps and code.

P
Pranisha Raifull stack development
How to Create a Full-Stack Application with Next.js?

Introduction

Next.js project at first, might seem intimidating with many new concepts to grasp. But fear not! You will be completely blown away by its tons of benefits. These added benefits will accelerate your development process, and provide a better user experience. Eventually, working with Next.js will be a cakewalk. If you’re still overwhelmed in using Next.js, this article will help to understand the concept of it with the steps and code. Let’s dive right into its steps! 

Install Next.js and Getting Started with It

  • First, you need to install the Next.js framework by simply writing the command “npm install next react react-dom” in the terminal. This will install dependencies such as React and React DOM into your system. 
  • Next, you need to set up your project in the Next.js app by running this command “npx create-next-app my-app”  
  • Once done, it will create a new app in a directory called “my-app”. You can also keep any name at your convenience instead of using “my-app”. 
  • Now, open the “my-app” directory and modify the default app that was created using the “create-next-app” command.  
  • You can make changes from your code editor, modify the content of the home page from the “page/index.js”, and add additional pages by creating new files in the “page” directory. 
  • You can use the command “npm run dev” to run the app, this will begin server development and then open your apps in the browser. 
  • So this is the step to get started with your Next.js app the next section walks you through the steps to build a homepage. 

Steps to Create a Navigation Bar and Shared Layout in Next.js

Unlike the other applications, Next.js comes with a shared layout concept that can be used in the entire application. One of these is a “Root Layout” that provides consistent structure in the application. Moreover, it includes all the necessary HTML tags.

Similarly, each route segment comes with its own layout that is shared across all the pages. This in return, maintains consistency and allows specific layouts for different sections in your app.

  • Open your code editor from there open the app layout file (app/layout.js) and then add the following code.
const inter = Inter({ subsets: ['latin'] })

export const metadata = {

  title: 'XYZ,

  description: 'Come here and learn more about Family Guy!',

}

export default function RootLayout({ children }) {

  return (

    <html lang="en">

      <body className={inter.className}>

        <Navigation />

        {children}

      </body>

    </html>

  )

}

So, you might wonder what the above code is doing exactly. Here’s the breakdown:

First, we define the “metadata” object in the component that contains all the default metadata tags in your application. These meta tags play a key role in helping your site rank better on search engines.

The “title property” specifies the title in your application.

The “description property” on the other hand, provides a brief description about that page.

If there is a requirement to change and modify this default metadata, you can easily adjust it according to your needs.

And we have structured the HTML tags inside the “RootLayout” function.

To set the language in English we have set the lang=”en” attribute.

The body tag includes “navigation component” and “children prop”, where the navigation component represents the shared across in the application and the children prop represents the content rendered in the “RootLayout component”.

  • Now open your navigation file and add the following code:
export const Navigation = () => {
return (
<div className="sticky top-0 backdrop-blur-xl bg-[rgba(0,0,0,0.8)] border-b border-slate-800 z-50">
<Container className="flex justify-between py-5">
<Link href="/">
<Image src="/logo.png" alt="Family Guy" width={70} height={50} />
</Link>
<Link
href="/quiz"
className="flex items-center justify-center gap-1 px-5 font-semibold text-black transition-colors bg-green-500 rounded-md duration-600 hover:bg-green-600"> 
<TbArrowBigRightFilled className="text-lg" />
XYZ
</Link>
</Container>
</div>
)
}

The above code will create and share the navigation layout across your application successfully, try and check on your local server. This will streamline the process of managing the elements in your Next.js app.

This code fetches data from the API endpoint for UI character data and then uses it to dynamically render the grid layout of the avatars with clickable links with individual character pages. But we haven’t used the “useEffect” hook in this code to fetch data from the API, still, this code will function undoubtedly.

Let’s break down its structure:
getAllCharacters”: This makes the asynchronous function HTTP request to the API endpoint and stores its response in the data variable. Next, it checks for the error whenever the HTTP response returns status code 200 then it throws an error.
Page Component”: It waits for the result from the calling function and stores data variables.
Main tag”: It holds a grid layout with multiple columns.“Containers”: It maps the character’s array in the data object and then generates the list of items. The “Link component” is created for each character that serves as a clickable link to a specific character page.
Slug property”: This will generate the URL links based on the character and within that, we have an image component to display the character’s avatar image.By now you will have an amazing-looking homepage. The next steps walk you through the steps to avoid code repetition to improve code reusability.

  • Now, go to the Page.jsx file and find the “getAllCharacters” function and then delete it.
  • After that, open the character.js file and export the “getAllCharacters” from there. This will import function into different parts of the codebase.
  • Now add the following code:
    Library.js fileimport { endpoint } from '@/utils/endpoint' 

    export async function getAllCharacters() { 

    const data = await fetch(`${endpoint}/characters`)  

    if (!data.ok) {   

    throw new Error('Failed to fetch data') 

    }  

    return data.json()

    }

    Page.jsx file
    import { getAllCharacters } from ‘@/lib/characters’
    export default async function Page() {  

    const data = await getAllCharacters()

    return (   
    <main>
     //content went here ...   
    </main> 
    )
    }

You have imported the “getAllCharacters” function from the library.js file to the index.jsx file. The next section walks you through the dynamic API route in Next.js to fetch character data based on the character slug.

Steps to Create Dynamic API Routes in Next.js

  • You need to use brackets in the folder name “[slug]/route.js” to indicate a dynamic route. This will allow retrieval and display of any character data.
  • Now open your API character [slug] route.js file and add the following code:
export async function GET(req, { params }) {  
try {   
const character = characters.data.find(item => item.slug === params.slug)

if (!character) { 
     return new NextResponse('not found', { status: 404 })   
}    
const character_qoutes = qoutes.data.filter(     
item => item.character_id === character.id,   
)    

return NextResponse.json({     
character,     
character_qoutes: character_qoutes.length > 0 ? character_qoutes : null,   
}) 
} catch (error) {   

return new NextResponse('Internal Server Error', { status: 500 }) 
  }
}

So what we did do? The code extracts dynamic parameters from the URL automatically and makes them available in the object “params”. It also uses the “params.slug” to access slug parameter and retrieves the specific character’s slug from the URL. Let’s break it down and understand.

  • The asynchronous function GET is responsible for managing GET requests.
  • We have used “character” and “quotes” from the JSON files using (@/data/characters.json and @/data/quotes.json , which is the Next.js file system.
  • req” and “params” contain the dynamic parameters extracted from the URL.
  • Try and catch” block compares the slug parameter from params within the slug property and try to find out each character object. If it does not find the character, it returns “not found 404” from the next/server package. And if it finds the character, code will filter the data array matching the “character_id” property.
  • And then the filter character quotes are assigned to the “character_quotes” variable.
  • At last the code uses “NextResponse.json()” “character” object and “character_quotes”to return JSON response.

Now you need to showcase this dynamic UI page by using the page.jsx file.Open character [slug] page.js file and add the following code:

import { getAllCharacters } from '@/lib/characters' 
export const dynamicParams = false

export async function generateStaticParams() { 
const { characters } = await getAllCharacters()
return characters.map(character => ({ slug: character.slug }))
}
export async function getCharacterBySlug(slug) { 
const data = await fetch(`${endpoint}/characters/${slug}`)

if (!data.ok) {    throw new Error('Failed to fetch data') 
}  
return data.json()
}

export default async function Page({ params }) {  const { character, character_qoutes } = await getCharacterBySlug(params.slug)

return (   
<Container className="flex flex-col gap-5 py-5" as="main">
<div className="flex flex-col gap-2">
<h1 className="text-2xl font-semibold capitalize">{character.name}</h1>
<ul className="flex gap-1 text-sm">
{character.occupations.map(item => {           
return (
<li               
key={item}               
className="p-2 text-gray-300 bg-gray-800 rounded-md">
{item}             
</li>
)         
})}       
</ul>     
</div>

<p className="text-sm leading-6">{character.description}</p>     
<ul className="grid gap-2 sm:grid-cols-2">       
{character.images.map(image => {          
return (           
<li             
key={image}             
className="relative flex overflow-hidden bg-gray-900 rounded-xl">
<Image               
className="transition-all duration-500 hover:scale-110 hover:rotate-2"               
src={image}               
alt=""               
width={760}               
height={435}             
/>           
</li>         
)       
})}
</ul>
{character.skills && (       
<>
<h2 className="text-xl font-bold">Power and Skills</h2>         
<ul className="flex flex-wrap gap-1">           
{character.skills.map(item => {             
return (               
 <li                 
className="flex justify-center flex-grow px-2 py-1 text-orange-400 rounded-full bg-orange-950"                 
key={item}               
>                 
{item}               
</li>
              )           
})}         
</ul>       
</>     
)}
{character_qoutes && (       
<>         
<h2 className="text-xl font-bold">Famous Qoutes</h2>         
<ul className="grid gap-5">           
{character_qoutes.map((item, idx) => {             
return (
                <li                  
className="p-2 italic text-gray-400 border-l-4 border-green-400 rounded-md"                 
key={item.idx}               
>                 
{item.qoute}               
</li>
)
})}         
</ul>       
</>     
)}   
</Container> 
)
}

Now let’s understand what we did in this code, first, we used “generateStaticParams” to to get the dynamic path of objects that you want to pre-render during build time. This “getAllCharacters()” function maps over the character and returns each containing slug property with slug value. The “dynamicParamas” on the other hand, control the behavior of dynamic segments that were not generated using “generateStaticPramas”. When it’s set to “true”, Next.js will try to fetch the corresponding page. On the flip side, if its set to “false”, Next.js will return 404 pages.

The asynchronous function “getCharacterBySlug” uses the slug parameter and fetches the data from the specified API endpoint. If it returns data in JSON format successfully but if it does not, then it throws errors. The page component receives dynamic parameter values from the “prop” object. And calls for the “getCharacterBySlug” function to pass the character slug from “params”. It returns the name of the character, description, skills, power, occupation, and images.

By now, you have created dynamic API routes, layout, navigation, and the homepage in Next.js. Only the only thing is left to add interactivity to your Next.js application. This next section walks you through how to add interactivity to your app.

Steps to Create API Route to Retrieve Random Question

First, open the random route.js file and add the following code:
export async function GET() { 
try {   
const random = Math.floor(Math.random() * questions.data.length)   
return NextResponse.json({     
randomQuestion: questions.data[random].id,   
})
} catch (error){   
return new NextResponse('Internal Server Error', { status: 500 }) 
}
}

This code implements the logic to fetch random questions stored in the JSON file. The “GET” function generates the data using two functions i.e., “Math.random()” and “Math.floor()” . Finally, the “id property” randomly selects the question.

Now, you will create the user interface of the quiz introduction section.

Open your quizpage. Jsx file and add the following:
export async function getRandomQuizQuestion() { 
const data = await fetch(`${endpoint}/quiz/random`, { cache: 'no-store' })
if (!data.ok) {   
throw new Error('Failed to fetch data') 
}
  return data.json()
}
export default async function Page() { 
const data = await getRandomQuizQuestion()
return (   
<Container     
as="main"
className="flex flex-col gap-5 py-5 md:flex-row-reverse md:justify-between">
<div className="relative overflow-hidden rounded-2xl">       
<div className="md:w-[24rem]">         
<Image src="/wallpaper.jpg" alt="" width={700} height={700} />       
</div>
<div className="absolute top-0 bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent md:bg-gradient-to-r"></div>     
</div>

<div className="md:w-[50%] flex flex-col gap-5">       
<h1 className="text-2xl font-semibold">Family Guy Quiz</h1>        
<p className="text-sm leading-6 text-gray-300">

Take this quiz to find out how much you know about the hit animated      sitcom Family Guy. Test your knowledge of the characters, the episodes, and the show&apos;s many pop culture references.
</p>
<Link         
href={`/quiz/${data.randomQuestion}`}
className="flex items-center justify-center gap-1 px-5 py-4 font-semibold text-orange-500 transition-colors rounded-md outline duration-600 hover:bg-orange-950">
<TbArrowBigRightFilled className="text-lg" />         
Take a Quiz Now!       
</Link>     
</div>   
</Container> 
)
}

The code above sets up the dynamic and interactive user interface for the quiz and fetches random questions from the API. Here, we have used the fetch method: { cache: ‘no-store’ }. which means it won’t use the static site generation method but instead uses the API request to fetch new data each time users visit the page. The use of “{ cache: ‘no-store‘ }” disables the cache and fetches a new question every time.

Dynamic API Routes Code for Quiz Answer using Next.js

export async function GET(req, { params }){  
try {   
const question = questions.data.find(item => item.id === params.id)
if (!question) {     
return new NextResponse('not found', { status: 404 })   
}
const { correct_answer, ...rest } = question
return NextResponse.json({     
question: rest,   
})
} catch (error) {   
return new NextResponse('Internal Server Error', { status: 500 }) 
}
}
P
§ The author

Pranisha Rai

Can Next.js be used for full stack development? This article will help to understand the concept of next.js with the steps and code.

Reading time12 min · 2,299 words

PublishedOctober 20, 2023

Categoryfull stack development
Enjoyed this piece?Share it with someone who would find it useful.
§ Stay in the loop

Don’t miss the next one.

We publish essays on engineering, hiring, and building teams. Subscribe and we’ll send them when they land.

Unsubscribe anytime · one letter, never more