0% found this document useful (0 votes)
93 views

Week-14.2 Backend in Nextjs Part-1

Uploaded by

Harsh Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
93 views

Week-14.2 Backend in Nextjs Part-1

Uploaded by

Harsh Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 16

8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

Week 14.2
In this lecture, Harkirat introduces the backend capabilities of Next.js, showcasing how it can be used
as a full-stack framework. We cover data fetching techniques, loaders, API routes, and implementing
sign-in and sign-up functionality with both frontend and backend components.

Backends in Next.js

1] Single Codebase for Frontend and Backend

2] No CORS Issues, Single Domain Name

3] Ease of Deployment

Recap of Data Fetching in React

Data Fetching In NextJS

Loaders In NextJS

Introducing API Routes In NextJS

Let’s move the backend into our own app

Frontend for Signing up

Create the Sign Up Page

Create the Sign Up Component

Create the Backend Route

Backend for signing up

Backends in Next.js
https://app.100xdevs.com/pdf/253 1/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

Next.js is often referred to as a full-stack framework, meaning it can handle both frontend and
backend code within the same codebase. This is a powerful feature that sets Next.js apart from
traditional frontend frameworks like React.

1] Single Codebase for Frontend and Backend


One of the key advantages of using Next.js for backend development is the ability to have a single
codebase for both your frontend and backend code. This approach simplifies the development
process and reduces the overhead of managing separate codebases for the frontend and backend.
By having a unified codebase, developers can easily share code, utilities, and logic between the
frontend and backend components of their application. This promotes code reusability and
consistency, making it easier to maintain and scale the codebase over time.

2] No CORS Issues, Single Domain Name


In traditional web development setups, where the frontend and backend are separate entities,
developers often encounter Cross-Origin Resource Sharing (CORS) issues. CORS is a security
mechanism that restricts cross-origin requests from one domain to another, which can cause
problems when the frontend and backend are hosted on different domains.
With Next.js, since both the frontend and backend are part of the same codebase and deployed
together, there is no need to worry about CORS issues. All requests from the frontend to the backend
are treated as same-origin requests, eliminating the need for complex CORS configurations.

https://app.100xdevs.com/pdf/253 2/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

Additionally, having a single codebase means that your frontend and backend can share the same
domain name, further simplifying the deployment and hosting process.

3] Ease of Deployment
Another significant advantage of using Next.js as a full-stack framework is the ease of deployment.
Since the frontend and backend code are part of the same codebase, you can deploy the entire
application as a single unit.
Next.js provides built-in support for various deployment platforms, such as Vercel (the company
behind Next.js), Netlify, and AWS Amplify, among others. These platforms offer seamless deployment
workflows, making it easy to deploy your Next.js application with minimal configuration.

Furthermore, Next.js supports serverless deployment, which means you can deploy your backend
code as serverless functions, taking advantage of the scalability and cost-effectiveness of serverless
architectures.

Recap of Data Fetching in React


In traditional React applications, data fetching typically happens on the client-side using hooks like
useEffect or libraries like Axios or Fetch API. Here's a common approach to fetch data from an API
endpoint:

1. Create a React component:

import React, { useState, useEffect } from 'react';

const UserCard = () => {


const [user, setUser] = useState(null);

useEffect(() => {
const fetchUserData = async () => {
try {
const response = await fetch('<https://week-13-offline.kirattechnologies.workers.dev/ap
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Error fetching user data:', error);
}
};

fetchUserData();
}, []);

if (!user) {
return <div>Loading...</div>;
}
https://app.100xdevs.com/pdf/253 3/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

return (
<div>
<h2>User Details</h2>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
};

export default UserCard;

1. Use the useEffect hook to fetch data:

The useEffect hook is used to perform side effects in React components, such as fetching
data from an API.

In the example above, the useEffect hook is called when the component mounts, and it
fetches user data from the provided API endpoint using the fetch function.

2. Handle the response and update state:

Once the API response is received, the json() method is used to parse the response data.

The parsed data is then stored in the component's state using the setUser function
provided by the useState hook.

3. Render the user data:

The component renders a loading message if the user state is null (i.e., data is still
being fetched).

Once the user state is updated with the fetched data, the component renders the user's
name and email.

By following this approach, you can fetch data from an API endpoint and display it in your React
component. However, it's important to note that this method of data fetching happens on the
client-side , which means the initial page load may not have the user data available, potentially
affecting the user experience and search engine optimization (SEO).

Data Fetching In NextJS


Next.js provides alternative approaches for data fetching, such as Server-Side Rendering (SSR) and
Static Site Generation (SSG), which can improve the initial page load performance and SEO. We'll
explore these approaches in the upcoming sections.

https://app.100xdevs.com/pdf/253 4/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

1. Initialize an Empty Next.js Project

First, we need to create a new Next.js project using the create-next-app command:

npx create-next-app@latest my-next-app

1. Install Axios

Next, we'll install the Axios library, which we'll use to make HTTP requests:

cd my-next-app
npm install axios

1. Clean Up the Initial Files

Let's clean up the initial files by removing everything from pages/index.js and styles/globals.css .

1. Fetch User Details

In the pages/index.js file, we'll create an async function to fetch the user details from the provided
API endpoint:

import axios from 'axios';

async function getUserDetails() {


const response = await axios.get('<https://week-13-offline.kirattechnologies.workers.dev/api/
return response.data;
}

1. Create an Async Component

Next.js supports async components, which means we can directly export an async function as the
default component:

import axios from 'axios';

async function getUserDetails() {


const response = await axios.get('<https://week-13-offline.kirattechnologies.workers.dev/api/
return response.data;
}

export default async function Home() {


const userData = await getUserDetails();

https://app.100xdevs.com/pdf/253 5/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

return (
<div>
{userData.email}
{userData.name}
</div>
);
}

In this example, the getUserDetails function fetches the user details from the API, and the Home
component renders the user's email and name.

1. Check the Network Tab

If you start the development server ( npm run dev ) and visit http://localhost:3000 , you should see
the user's email and name rendered on the page. Additionally, if you open the browser's network tab,
you should not see any waterfalling effect, as the data is fetched and rendered on the server-side.

1. Prettify the UI

To improve the visual appearance of the page, we can add some styling using Tailwind CSS:

import axios from 'axios';

async function getUserDetails() {


const response = await axios.get('<https://week-13-offline.kirattechnologies.workers.dev/api/
return response.data;
}

export default async function Home() {


const userData = await getUserDetails();

return (
<div className="flex flex-col justify-center h-screen">
<div className="flex justify-center">
<div className="border p-8 rounded">
<div>
Name: {userData?.name}
</div>
{userData?.email}
</div>
</div>
</div>
);
}

https://app.100xdevs.com/pdf/253 6/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

This code centers the user details vertically and horizontally on the page, adds a border and padding
to the container, and displays the user's name and email.

1. Loader

In this example, we don't need a separate loader component because the page is rendered on the
server-side, and the user will only see the content once it's fully rendered. However, if you need to
show a loading state for more complex scenarios, you can use React's Suspense and fallback
components.

By following this approach, you can fetch data on the server-side in Next.js, pre-
render the page with the fetched data, and provide a better user experience
with improved performance and SEO optimization.

Loaders In NextJS
In Next.js, you can define a loading.tsx file (or loading.js for JavaScript) in the same directory as
your page component. This file will be used to render a loading state while the page's async
operations, such as data fetching, are in progress.

Here's how you can implement a custom loader in Next.js:

1. Create a loading.tsx file

In the root directory of your Next.js project, create a new file called loading.tsx and add a custom
loader component:

// loading.tsx
export default function Loading() {
return (
<div className="flex flex-col justify-center h-screen">
<div className="flex justify-center">
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-9
</div>
</div>
);
}

In this example, we're rendering a spinning loader using Tailwind CSS utility classes. You can
customize the loader component according to your design requirements.

https://app.100xdevs.com/pdf/253 7/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

1. Update the Home component

Next, update the Home component in pages/index.tsx to use the Loading component while
fetching data:

import axios from 'axios';

async function getUserDetails() {


// Simulate a slow API call
await new Promise(resolve => setTimeout(resolve, 5000));
const response = await axios.get('<https://week-13-offline.kirattechnologies.workers.dev/api/
return response.data;
}

export default async function Home() {


const userData = await getUserDetails();

return (
<div className="flex flex-col justify-center h-screen">
<div className="flex justify-center">
<div className="border p-8 rounded">
<div>
Name: {userData?.name}
</div>
{userData?.email}
</div>
</div>
</div>
);
}

In this example, we've added a simulated delay of 5 seconds to the getUserDetails function to
mimic a slow API call.

1. Start the development server

Run the development server with the following command:

npm run dev

When you visit http://localhost:3000 , you should see the custom loader component rendered
while the data is being fetched. After 5 seconds, the user details will be displayed.

By defining a loading.tsx file, Next.js automatically renders the Loading


component while the page's async operations are in progress. This provides a

https://app.100xdevs.com/pdf/253 8/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

better user experience by showing a loading state instead of a blank page while
data is being fetched.

Introducing API Routes In NextJS


Next.js provides a powerful feature called API Routes, which allows you to create server-side APIs
directly within your Next.js application. This feature makes Next.js a full-stack framework, enabling
you to build both the frontend and backend components of your application in a single codebase.

Benefits of Using Next.js for Backend

1. Single Repository: By having both the frontend and backend code in the same repository, you can
streamline your development workflow and simplify collaboration between frontend and backend
developers.

2. Standard Backend Features: Next.js API Routes provide similar functionality to popular backend
frameworks like Express.js, allowing you to handle HTTP requests, define routes, and perform
server-side operations.

3. Direct Communication with Server Components: Server components in Next.js can directly
communicate with the backend API routes, eliminating the need for cross-origin requests (CORS)
and simplifying the development process.

Creating an API Route

To create an API route in Next.js, you need to create a file inside the pages/api directory. The file
name will determine the route path. For example, if you create a file named pages/api/hello.js , the
corresponding route will be /api/hello .

Here's an example of a simple API route in Next.js:

// pages/api/hello.js

export default function handler(req, res) {


if (req.method === 'GET') {
res.status(200).json({ message: 'Hello, world!' });
} else {
res.status(405).json({ message: 'Method not allowed' });
}
}

In this example, the handler function receives the req (request) and res (response) objects,
similar to Express.js. You can handle different HTTP methods (GET, POST, PUT, DELETE, etc.) and
perform server-side operations accordingly.

https://app.100xdevs.com/pdf/253 9/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

To access this API route, you can send a GET request to http://localhost:3000/api/hello (during
development) or https://your-domain.com/api/hello (in production).

Accessing API Routes from Server Components

One of the benefits of using Next.js API routes is the ability to directly access them from server
components. This eliminates the need for cross-origin requests (CORS) and simplifies the
development process.

Here's an example of how you can fetch data from an API route in a server component:

// pages/index.js

export default async function Home() {


const res = await fetch('/api/hello');
const data = await res.json();

return (
<div>
<h1>{data.message}</h1>
</div>
);
}

In this example, the Home component fetches data from the /api/hello route using the fetch
function. Since the API route is part of the same Next.js application, there's no need to worry about
CORS or cross-origin requests.

Let’s move the backend into our own app


1. Create the API folder

First, create a new folder called api inside the pages directory. This is where we'll define our API
routes.

app/
├── api/
└── index.tsx

1. Create the user folder and route file

Inside the api folder, create a new folder called user . This folder will contain routes related to user
data. Then, create a new file called route.ts inside the user folder.

https://app.100xdevs.com/pdf/253 10/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

app/
├── api/
│ └── user/
│ └── route.ts
└── index.tsx

1. Define the GET route

Open the route.ts file and define a GET route that returns hardcoded user details:

// app/api/user/route.ts

import { NextResponse } from 'next/server';

export async function GET() {


return NextResponse.json({
username: 'harkirat',
email: '[email protected]',
});
}

In this example, we're using the NextResponse utility from Next.js to send a JSON response with
hardcoded user details.

1. Update the getUserDetails function

Now, update the getUserDetails function in pages/index.tsx to fetch data from the new API route:

// pages/index.tsx
import axios from 'axios';

async function getUserDetails() {


try {
const response = await axios.get('<http://localhost:3000/api/user>');
return response.data;
} catch (e) {
console.log(e);
}
}

export default async function Home() {


const userData = await getUserDetails();

return (
<div className="flex flex-col justify-center h-screen">
<div className="flex justify-center">
<div className="border p-8 rounded">
<div>
Name: {userData?.username}
</div>
https://app.100xdevs.com/pdf/253 11/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

{userData?.email}
</div>
</div>
</div>
);
}

In this updated code, we're using Axios to fetch data from the http://localhost:3000/api/user
route, which corresponds to the API route we defined earlier.

1. Start the development server

Run the development server with the following command:

npm run dev

When you visit http://localhost:3000 , you should see the hardcoded user details rendered on the
page.

By creating an API route within our Next.js app, we've moved the backend logic
into our application. This approach allows us to have a unified codebase for
both the frontend and backend components, simplifying development and
deployment.

Frontend for Signing up


Create the Sign Up Page
First, create a new file called page.tsx inside the app/signup directory. This file will render the Sign
Up component.

// app/signup/page.tsx
import { Signup } from "@/components/Signup";

export default function SignUpPage() {


return <Signup />;
}

Create the Sign Up Component


Next, create a new file called Signup.tsx inside the components directory. This file will contain
the Sign Up component.
https://app.100xdevs.com/pdf/253 12/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

// components/Signup.tsx
"use client"; // Mark this component as a client component
import axios from "axios";
import { useRouter } from "next/router";
import { ChangeEventHandler, useState } from "react";

export function Signup() {


const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const router = useRouter();

return (
<div className="h-screen flex justify-center flex-col">
<div className="flex justify-center">
<div className="block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow
<div>
<div className="px-10">
<div className="text-3xl font-extrabold">Sign up</div>
</div>
<div className="pt-2">
<LabelledInput
onChange={(e) => {
setUsername(e.target.value);
}}
label="Username"
placeholder="[email protected]"
/>
<LabelledInput
onChange={(e) => {
setPassword(e.target.value);
}}
label="Password"
type={"password"}
placeholder="123456"
/>
<button
onClick={async () => {
const response = await axios.post("<http://localhost:3000/api/user>", {
username,
password,
});
router.push("/");
}}
type="button"
className="mt-8 w-full text-white bg-gray-800 focus:ring-4 focus:ring-gray-3
>
Sign up
</button>
</div>
</div>

https://app.100xdevs.com/pdf/253 13/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

</div>
</div>
</div>
);
}

function LabelledInput({ label, placeholder, type, onChange }: LabelledInputType) {


return (
<div>
<label className="block mb-2 text-sm text-black font-semibold pt-4">{label}</label>
<input
onChange={onChange}
type={type || "text"}
id="first_name"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:
placeholder={placeholder}
required
/>
</div>
);
}

interface LabelledInputType {
label: string;
placeholder: string;
type?: string;
onChange: ChangeEventHandler<HTMLInputElement>;
}

In this component, we're using the useState hook to manage the state of the username and
password fields. We're also using the useRouter hook from Next.js to navigate to the landing page
( / ) after a successful sign-up.
The Signup component renders a form with two input fields (username and password) and a "Sign
up" button. When the user clicks the "Sign up" button, an onClick handler is triggered, which sends
a POST request to the /api/user route with the username and password data.
If the sign-up is successful, the user is redirected to the landing page ( / ) using the router.push
method.

Create the Backend Route


Now, let's create the backend route to handle the sign-up request. Inside the app/api/user
directory, create a new file called route.ts (or route.js for JavaScript).

// ap/api/user/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {

https://app.100xdevs.com/pdf/253 14/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

const { username, password } = await request.json();

// Here, you would typically perform validation and store the user data in a database
// For simplicity, we'll just log the username and password to the console
console.log('Username:', username);
console.log('Password:', password);

return NextResponse.json({ message: 'Sign up successful' });


}

In this example, we're defining a POST route that accepts the username and password data from the
client. In a real-world scenario, you would typically perform validation and store the user data in a
database. For simplicity, we're just logging the username and password to the console.

After implementing the backend route, you should be able to sign up by


entering a username and password on the Sign Up page. When you click the
"Sign up" button, you should see the username and password logged in the
console, and you should be redirected to the landing page ( / ).

Backend for signing up


1. Navigate to the API Route File

First, navigate to the app/api/user/route.ts file. This is where we'll define our API routes related to
user authentication.

1. Import Required Dependencies

At the top of the file, import the necessary dependencies from Next.js:

import { NextRequest, NextResponse } from 'next/server';

1. Define the POST Route

Next, define the POST route by exporting an async function named POST . This function will handle
the incoming POST requests to the /api/user route.

export async function POST(req: NextRequest) {


const body = await req.json();

return NextResponse.json({ username: body.username, password: body.password });


}

https://app.100xdevs.com/pdf/253 15/16
8/18/24, 12:08 AM Take your development skills from 0 to 100 and join the 100xdevs community

In this code:

The POST function receives a NextRequest object ( req ) as a parameter, which represents the
incoming HTTP request.

We use the req.json() method to parse the request body as JSON data and store it in the body
variable.

Finally, we return a NextResponse object with the username and password properties from the
request body as JSON data.

Here's the complete app/api/user/route.ts file:

import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {


const body = await req.json();

return NextResponse.json({ username: body.username, password: body.password });


}

With this implementation, when a POST request is sent to the /api/user route with a JSON payload
containing username and password properties, the server will respond with a JSON object
containing the same username and password values.

For example, if you send a POST request with the following JSON payload:

{
"username": "[email protected]",
"password": "mypassword"
}

The server will respond with:

{
"username": "[email protected]",
"password": "mypassword"
}

To conclude, in the next lecture, we will dive deeper into building full-stack applications with Next.js.
We will explore integrating databases, implementing better fetching techniques, using the Prisma
ORM, and leveraging server-side capabilities. This will equip us with the knowledge and skills
necessary to build robust, scalable, and secure full-stack applications using Next.js.

https://app.100xdevs.com/pdf/253 16/16

You might also like