Optimizing Web Performance by Reducing API Response Time with Next.js and Django REST Framework

Published on 2025-04-17

Blog Thumbnail
Boost your web app’s speed by minimizing API response times using Next.js and Django REST Framework. Learn performance optimization techniques like caching, lazy loading, and efficient data fetching. Deliver faster, smoother user experiences with a powerful Next.js + DRF stack.

 

Introduction:

In today's fast-paced digital world, website performance is crucial for delivering a seamless user experience. Slow API response times can significantly hinder user satisfaction and search engine rankings. This blog post will guide you through optimizing web performance by reducing API response time using Next.js and Django REST Framework. We'll also explore how to leverage WebOpt for SEO, UI, and responsive testing to ensure your web application is top-notch.

Understanding the Performance Challenge:

API response time plays a critical role in the overall performance of a web application. Whether you're fetching data for rendering a page or processing user inputs, slow APIs can create bottlenecks that affect both front-end and back-end performance.

The combination of Next.js and Django REST Framework is a powerful duo for building scalable and efficient applications. Next.js offers server-side rendering (SSR), static site generation (SSG), and dynamic routing, while Django REST Framework provides a robust backend for managing data and handling API requests.

Setting Up Next.js with Django REST Framework:

Backend: Django REST Framework:

First, you'll need to set up a Django project and install Django REST Framework.

# Install Django and Django REST Framework
pip install django djangorestframework

# Create a new Django project
django-admin startproject myproject
for example(django-admin startproject blog)

# Navigate into the project directory
cd myproject

# Create a new app
python manage.py startapp myapp
for example (python manage.py startapp optimize)

2. Defining Models:

Let’s define a simple model in optimize/models.py:

from django.db import models


class EmployeeInfo(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)
    age = models.IntegerField()
    email = models.EmailField(max_length=1000)
    country = models.CharField(max_length=1000)
    city = models.CharField(max_length=1000)
    gender = models.CharField(max_length=100)

    def __str__(self):
        return self.first_name


class EmployeeSalary(models.Model):
    employee_id = models.ForeignKey(EmployeeInfo, related_name="emp", on_delete=models.CASCADE)
    salary = models.IntegerField()
    skill = models.CharField(max_length=500)

3. Creating Serializers:

Next, create serializers for the models in optimize/serializers.py:

from rest_framework import serializers
from .models import EmployeeInfo, EmployeeSalary


class EmployeeInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = EmployeeInfo
        fields = "__all__"


class EmployeeSalarySerializer(serializers.ModelSerializer):
    employee_id = EmployeeInfoSerializer()

    class Meta:
        model = EmployeeSalary
        fields = "__all__"


class EmployeeDetailSerializer(serializers.ModelSerializer):
    info = serializers.SerializerMethodField()  

    class Meta:
        model = EmployeeInfo
        fields = ["id","first_name", "last_name", "age", "email", "country", "city", "gender", "info"]

    def get_info(self, obj):
        composer_credit = list(EmployeeSalary.objects.filter(id=obj.id).values())

        usercredential = {}
        if len(composer_credit):
            usercredential["salary"] = composer_credit[0]["salary"]
            usercredential["skill"] = composer_credit[0]["skill"]

        return usercredential

4. Writing Optimized Views:

In optimize/views.py, we’ll create API views that handle requests efficiently.

from rest_framework import generics
from .models import EmployeeInfo, EmployeeSalary
from .serializer import EmployeeInfoSerializer

class EmployeeListView(generics.RetrieveAPIView):

    queryset = EmployeeInfo.objects.prefetch_related('emp').all()
    serializer_class = EmployeeInfoSerializer
    lookup_field='employee_id'

class EmployeeFullInfoView(generics.RetrieveAPIView):
    queryset = EmployeeInfo.objects.prefetch_related('emp').all()
    serializer_class = EmployeeInfoSerializer

class EmployeeDetailsView(viewsets.ModelViewSet):
    queryset = EmployeeInfo.objects.all()
    serializer_class = EmployeeDetailSerializer

5. Setting Up URLs:

Now, map these views to URLs in myapp/urls.py:

from django import views
from django.urls import path
from .views import EmployeeFullInfoView,EmployeeDetailsView


employee = EmployeeDetailsView.as_view({'get':'list'})
urlpatterns = [
    path("employee/<int:pk>", EmployeeFullInfoView.as_view(), name="employee"),
    path("employee-details/", employee),
]

Include these URLs in your main urls.py file:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('optimize/', include('optimize.urls')),
]

6. Running Migrations and Starting the Server:

Finally, apply the migrations and start the server:

python manage.py makemigrations
python manage.py migrate
python manage.py runserver

 

Set Up a New Next.js Project:

1.Install Node.js and npm:

Ensure that you have Node.js and npm installed on your machine.

node -v
npm -v

2.Create a New Next.js Project:

Use the following command to create a new Next.js project.

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

3.Run the Development Server:

Start the development server to ensure everything is working.

npm run dev

Navigate to http://localhost:3000 in your browser to see your new Next.js application.

Create API Request Functions:

  1. Create a Utility Folder: Inside your src or lib directory, create a Compoenents folder to hold your API request functions.

  2. Create API Functions: Inside the Components folder, create a file named Fetch.js and define functions to fetch data from the Django REST API.

const API_BASE_URL = 'http://localhost:8000';

export async function EmployeeGetApi(event, method, api) {
  var response_data;

  await fetch(`${API_BASE_URL}` + api, {
    method: method,
    headers: {
      'Content-Type': 'application/json',
    },
  }).then((res) => {
    console.log(res);
    return res.json()
  }).then(data => {
    response_data = data
  })
  .catch(error => {
    response_data = error   
});
  return response_data
}

Create Pages to Display Data:

In pages/index.js, add the following code.

import Image from "next/image";
import { product_info } from "@/components/Api";
import { useState, useEffect } from "react";
import { EmployeeGetApi } from "@/components/fetch";
import { useRouter } from "next/router";


export default function Home() {

  const router  = useRouter()
  const [jsonData, setJsonData] = useState([])

  async function PmcGetFunction() {
    const response = await EmployeeGetApi('', "GET", "/optimize/employee-details/")
    setJsonData(response)
  }

  useEffect(() => { PmcGetFunction() }, [])

  return (

    <main
      className={`flex min-h-screen flex-col items-center justify-between p-24 bg-white `}
    >
      <div className="px-4 sm:px-6 lg:px-8">
        <div className="sm:flex sm:items-center">
          <div className="sm:flex-auto">
            <h1 className="text-base font-semibold leading-6 text-gray-900">Users</h1>
            <p className="mt-2 text-sm text-gray-700">
              A list of all the users in your account including their first_name, last_name, email, age, country, city and gender.
            </p>
          </div>
        </div>
        <div className="mt-8 flow-root">
          <div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
            <div className="inline-block w-[700px] py-2 align-middle sm:px-6 lg:px-8">
              <table className="min-w-full divide-y divide-gray-300">
                <thead>
                  <tr>
                    <th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0">
                      Id
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      First_name
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Last_name
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Age
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Email
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Country
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      City
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Gender
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Salary
                    </th>
                    <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
                      Skill
                    </th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-gray-200">
                  {jsonData.map((person, index) => (
                    <tr key={index} onClick={()=>{router.push('/person/?id='+person.id)}} className="cursor-pointer">
                      <td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-black sm:pl-0 ">
                        {person.id}
                      </td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.first_name}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.last_name}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.age}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.email}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.country}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.city}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.gender}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.info?.salary}</td>
                      <td className="whitespace-nowrap px-3 py-4 text-sm text-black">{person.info?.skill}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </main>
  );
}

In pages/person.js.js, add the following code.


import Image from "next/image";
import { user_info } from "@/components/Api";
import React, { useState, useEffect } from "react";
import { EmployeeGetApi } from "@/components/fetch";
import { useRouter } from "next/router";

export default function UserInfo() {

  const router = useRouter()
  const [userData, setUserInfoData] = useState([])

  useEffect(() => {
    if (router.query.id) {
      UserInfoApi()
    }
  }, [])
  async function UserInfoApi() {
    const response = await EmployeeGetApi('', "GET", user_info + router.query.id)
    setUserInfoData(response)
  }

  return (
    <>
      <div className="w-full min-h-screen  bg-white">
        <div className="w-[600px] min-h-[300px] pt-[80px]  mx-auto">
          <h1 className="text-2xl text-center font-bold">
            User Information
          </h1>
            <div className='space-y-6 my-6'>
              <div className='space-y-2 w-full'>
                <label for='id' className='text-[#121212]'>
                  Id
                </label>
                <div>
                  <input id='id' name='first_name' value={userData.id}
                    type='text' className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='first_name' className='text-[#121212]'>
                  First Name
                </label>
                <div>
                  <input id='first_name' name='first_name' type='text' value={userData.first_name}
                    className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='last_name' className='text-[#121212]'>
                  Last Name
                </label>
                <div>
                  <input id='last_name' name='last_name'
                    value={userData.last_name}
                    type='text' className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='Age' className='text-[#121212]'>
                  Age
                </label>
                <div>
                  <input id='age' name='age' type='text' value={userData.age}
                    className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='Email' className='text-[#121212]'>
                  Email
                </label>
                <div>
                  <input id='email' name='email'
                    value={userData.email}
                    type='text' className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='Gender' className='text-[#121212]'>
                  Gender
                </label>
                <div>
                  <input id='gender' name='gender' type='text' value={userData.gender}
                    className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='Country' className='text-[#121212]'>
                  Country
                </label>
                <div>
                  <input id='country' name='country' type='text' value={userData.country}
                    className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
              <div className='space-y-2 w-full'>
                <label for='City' className='text-[#121212]'>
                  City
                </label>
                <div>
                  <input id='city' name='city' type='text' value={userData.city}
                    className='w-full  px-6 py-2  text-black  border border-gray-500 focus:outline-0 focus:ring-0 ' />
                </div>
              </div>
            </div>
          <div>
          </div>
        </div>
      </div>
    </>
  )
}

Run Your Application:

npm run dev


Monitor and Test with WebOpt:

Integrate WebOpt: Utilize the WebOpt UI testing tool to continuously monitor your application. WebOpt offers powerful network analysis capabilities that allow you to capture and analyze network traffic during user interactions, such as mousedown events. This feature helps identify performance bottlenecks, monitor response times, and optimize resource loading.

Network Traffic Analysis: With WebOpt, you can capture and analyze network requests made by your application. This is especially useful for detecting slow API responses, large assets, or unoptimized third-party scripts.

Response Time Calculation: WebOpt provides detailed response time metrics, enabling you to identify and address performance issues that could affect your users' experience.

Cross-Browser Compatibility: Alongside network analysis, WebOpt also ensures your application performs consistently across different browsers and devices.

Optimize for Performance: Leverage the insights from WebOpt's network analysis to optimize your application's performance. By reducing unnecessary network requests and improving response times, you can enhance the overall user experience and ensure your application runs smoothly under various conditions.

Conclusion:

In conclusion, WebOpt serves as a robust tool for continuously monitoring and optimizing your application's performance. By integrating WebOpt, you gain access to advanced network traffic analysis and response time metrics, allowing you to identify and resolve performance bottlenecks effectively. Additionally, WebOpt's cross-browser compatibility testing ensures a consistent user experience across different platforms. Utilizing these insights, you can make data-driven optimizations, reduce unnecessary network requests, and improve resource loading, resulting in a faster, smoother application experience for your users.