GuidesAPI Call

Any file named route.ts in the /app/api folder is an API endpoint. Use the helper /libs/api.ts (axios instance with interceptors) to simplify API calls:

  • Automatically display error messages
  • Redirect to login page upon error 401
  • Add /api as a base URL: /api/user/posts → /user/posts

Protected API Calls

NextAuth & Mongo

NextAuth automatically handles the authentication with cookies. Just make a normal API call on the front-end like this:

/components/UserProfile.tsx

1"use client";
2
3import { useState } from "react";
4import apiClient from "@/libs/api";
5
6const UserProfile = () => {
7  const [isLoading, setIsLoading] = useState(false);
8
9  const saveUser = async () => {
10    setIsLoading(true);
11
12    try {
13      const { data } = await apiClient.post("/user", {
14        email: "new@gmail.com",
15      });
16
17      console.log(data);
18    } catch (e) {
19      console.error(e?.message);
20    } finally {
21      setIsLoading(false);
22    }
23  };
24
25  return (
26    <button className="btn btn-primary" onClick={() => saveUser()}>
27      {isLoading && (
28        <span className="loading loading-spinner loading-sm"></span>
29      )}
30      Save
31    </button>
32  );
33};
34
35export default UserProfile;

In the backend, we get the session and we can use it to retrieve the user from the database. You have to configure the database first.

The API file should look like this:

/app/api/user/route.ts

1import { NextResponse, NextRequest } from "next/server";
2import { getServerSession } from "next-auth/next";
3import { authOptions } from "@/libs/next-auth";
4import connectMongo from "@/libs/mongoose";
5import User from "@/models/User";
6
7export async function POST(req: NextRequest) {
8  const session = await getServerSession(authOptions);
9
10  if (session) {
11    await connectMongo();
12
13    const { id } = session.user;
14
15    const body = await req.json();
16
17    if (!body.email) {
18      return NextResponse.json({ error: "Email is required" }, { status: 400 });
19    }
20
21    try {
22      const user = await User.findById(id);
23
24      if (!user) {
25        return NextResponse.json({ error: "User not found" }, { status: 404 });
26      }
27
28      user.email = body.email;
29      await user.save();
30
31      return NextResponse.json({ data: user }, { status: 200 });
32    } catch (e) {
33      console.error(e);
34      return NextResponse.json(
35        { error: "Something went wrong" },
36        { status: 500 }
37      );
38    }
39  } else {
40    // Not Signed in
41    NextResponse.json({ error: "Not signed in" }, { status: 401 });
42  }
43}

Supabase

Supabase automatically handles the authentication with cookies. Just make a normal API call on the front-end like this:

/components/UserProfile.tsx

1"use client";
2
3import { useState } from "react";
4import apiClient from "@/libs/api";
5
6const UserProfile = () => {
7  const [isLoading, setIsLoading] = useState(false);
8
9  const saveUser = async () => {
10    setIsLoading(true);
11
12    try {
13      const { data } = await apiClient.post("/user", {
14        email: "new@gmail.com",
15      });
16
17      console.log(data);
18    } catch (e) {
19      console.error(e?.message);
20    } finally {
21      setIsLoading(false);
22    }
23  };
24
25  return (
26    <button className="btn btn-primary" onClick={() => saveUser()}>
27      {isLoading && (
28        <span className="loading loading-spinner loading-sm"></span>
29      )}
30      Save
31    </button>
32  );
33};
34
35export default UserProfile;

In the backend, we get the session and we can use it to retrieve the user from the database. You have to configure the database first.

The API file should look like this:

/app/api/user/route.ts

1import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
2import { NextResponse, NextRequest } from "next/server";
3import { cookies } from "next/headers";
4
5export const dynamic = "force-dynamic";
6
7export async function POST(req: NextRequest) {
8  const supabase = createRouteHandlerClient({ cookies });
9  const { data } = await supabase.auth.getSession();
10  const { session } = data;
11
12  if (session) {
13    const body = await req.json();
14
15    if (!body.email) {
16      return NextResponse.json({ error: "Email is required" }, { status: 400 });
17    }
18
19    try {
20      // This call will fail if you haven't created a table named "users" in your database
21      const { data } = await supabase
22        .from("users")
23        .insert({ email: body.email })
24        .select();
25
26      return NextResponse.json({ data }, { status: 200 });
27    } catch (e) {
28      console.error(e);
29      return NextResponse.json(
30        { error: "Something went wrong" },
31        { status: 500 }
32      );
33    }
34  } else {
35    // Not Signed in
36    NextResponse.json({ error: "Not signed in" }, { status: 401 });
37  }
38}