Реализуйте Google OAuth в своем приложении Next.js с помощью NextAuth.js

В этой статье мы узнаем следующее:

  • Использование NextAuth.js с Next.js.
  • Сторонняя аутентификация Google с помощью NextAuth.js.
  • Поддержание связи между пользователями и таблицами Notes.
  • Выполнение операций CRUD с нашей базой данных для чтения и записи заметок.

Вступление

Итак, вы создали потрясающий блог с Next.js, который ежедневно привлекает миллионы пользователей. Чтобы получать доход от написания статей, вам пришла в голову идея заблокировать статьи за платный доступ. Так читатели смогут вас поддержать. Чтобы реализовать такую ​​идею, вам потребуется выполнить следующие шаги:

  • Создайте систему входа в систему.
  • Убедитесь, что зарегистрированный пользователь подписался на ваш сайт.
  • Если они являются платными участниками, позвольте им продолжить наслаждаться вашим контентом.
  • С другой стороны, если посетитель не вошел в систему, предложите ему создать учетную запись или войти в систему.

Однако давайте посмотрим правде в глаза: аутентификация - это боль. Для этого требуется тонна кода, а в некоторых случаях обслуживание затруднено.

Здесь на помощь приходит Next-Auth.js. Он не только упрощает процесс создания аутентификации пользователей, но также имеет следующие преимущества:

  • Файлы cookie: в паспорте, если вы перезапустите свой сервер, вы автоматически выйдете из системы. В Next-Auth.js это не проблема, поскольку он уже использует файлы cookie для хранения данных сеанса.
  • Чрезвычайно безопасный: Next-Auth.js активно продвигает варианты входа без пароля. Кроме того, он использует токены CSRF в своем коде, чтобы гарантировать, что ваш проект не будет содержать эксплойтов и других лазеек.

Пришло время писать код!

Настройка проекта

Инициализация репозитория

Этот шаг довольно прост. Чтобы создать экземпляр проекта Next.js, выполните следующую команду терминала:

Затем создайте файл .env.local в корне вашего проекта следующим образом:

Здесь мы будем хранить переменные среды.

Теперь приступим к установке наших зависимостей.

Установка модулей

В этом проекте мы будем использовать следующие модули:

  • next-auth: Суть нашего проекта. Эта библиотека будет обрабатывать все наши процессы, основанные на аутентификации.
  • mongodb: Поскольку мы будем использовать сервер MongoDB, Next-Auth.js будет использовать пакет mongodb как одну из своих зависимостей.
  • mongoose: Для взаимодействия с нашей базой данных и выполнения операций CRUD с нашими коллекциями.

Чтобы установить эти пакеты, выполните следующую команду терминала:

Давайте теперь инициализируем наш сервер MongoDB.

Настройка MongoDB Atlas

Рекомендую использовать MongoDB Atlas. Он настраивает для вас сервер базы данных в облаке без какой-либо дополнительной настройки.

Сначала войдите на страницу Атласа и выполните следующие действия, чтобы создать свой первый кластер. Когда это будет сделано, нажмите Подключиться:

Затем выберите «Разрешить доступ из любого места»:

Теперь создайте свое имя пользователя и пароль и нажмите «Создать пользователя базы данных», чтобы зарегистрироваться в качестве пользователя. Когда это будет сделано, нажмите «Подключить ваше приложение»:

Затем вы получите строку подключения. Скопируйте это и вставьте в свой .env.local файл:

Теперь займемся созданием учетных данных Google OAuth.

OAuth с Google

Перейдите в Консоль разработчика Google и нажмите Выбрать проект. Затем нажмите Новый проект:

Когда это будет сделано, перейдите на боковую панель и нажмите «API и службы». Затем нажмите «Панель управления»:

На верхней панели нажмите «Включить API и службы». Вы попадете на страницу библиотеки API. Найдите «Google+» и ​​включите его.

Теперь веб-сайт приведет вас на страницу «Включенные API». Сначала выберите «Учетные данные», а затем щелкните ссылку «Учетные данные в API и службах»:

Это перенаправит вас на домашнюю страницу. Нажмите «Создать учетные данные», а затем «Идентификатор клиента OAuth»:

Выберите «Веб-приложение»:

Теперь дайте вашему приложению имя. Когда это будет сделано, прокрутите вниз до «URI авторизованного перенаправления» и настройте его следующим образом:

Теперь нажмите «Создать», чтобы сообщить Google о создании нашего клиента OAuth. Вы получите свой идентификатор клиента и секрет:

Скопируйте их в свой .env.local файл следующим образом:

И мы, наконец, закончили! В следующем разделе мы обсудим нашу файловую структуру.

Файловая структура проекта

В корневом каталоге вашего проекта создайте следующие папки:

  • models: Будем хранить наши модели Mongoose.
  • helpers: будет содержать все наши функции промежуточного программного обеспечения.
  • components: хранит наши пользовательские компоненты, которые можно повторно использовать в других файлах.

Теперь войдите в свою папку pages и создайте эти папки:

  • notes в каталоге /api: будет обрабатывать /api/notes/ маршруты.
  • auth в каталоге /api: будет содержать логику аутентификации пользователя.
  • notes: будет обрабатывать маршрут /notes.

В итоге структура вашего проекта должна выглядеть так:

Готово! А теперь давайте попробуем построить внутреннюю часть нашей системы входа в систему.

Создание нашей системы входа в систему

Настройка бэкэнда

В своем проекте перейдите в каталог /pages/api/auth и создайте файл с именем [...nextauth.js]. Это означает, что все маршруты, начинающиеся с /api/auth, будут обрабатываться файлом [...nextauth].js.

В /pages/api/[...nextauth].js напишите следующий фрагмент кода:

import NextAuth from "next-auth";
import Providers from "next-auth/providers";
export default NextAuth({
// Configure one or more authentication providers
providers: [
Providers.Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
database: process.env.MONGODB_URI,
callbacks: {
session: async (session, user) => {
session.id = user.id;
return Promise.resolve(session);
},
},
});
  • Строки 1-2: Импортируйте модуль NextAuth для реализации аутентификации. Затем импортируйте пакет Providers, чтобы сообщить Next.js, что мы будем использовать стороннюю аутентификацию.
  • Строки 6-11: Сообщите Next.js, что мы будем использовать только Google OAuth для этого проекта. Мы также передаем наш идентификатор Google и секретный ключ через переменные среды.
  • Строка 13: используйте наш экземпляр базы данных MongoDB. Строка подключения передается через переменные среды.
  • Строка 14: Наш обратный вызов session будет запущен, когда пользовательский сеанс будет проверен.
  • Строка 16. Раскройте свойство сеанса id, чтобы мы могли получить к нему доступ. Это будет полезно при создании заметок, связанных с каждым пользователем.

Давайте теперь создадим наш интерфейс.

Создание нашего интерфейса

В /pages/index.js замените весь свой код следующим:

import { signIn, signOut, useSession } from "next-auth/client";
export default function Home() {
const [session, loading] = useSession();
return (
<div>
{loading && <p>Loading..</p>}
{!session && (
<>
Not signed in <br />
<button
onClick={() =>
signIn("google", { callbackUrl: "http://localhost:3000/" })
}
>
Sign in
</button>
</>
)}
{session && (
<>
Signed in as {session.user.name} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
)}
</div>
);
}
view raw next-index.js hosted with ❤ by GitHub
  • Строка 3. Используйте useSession Hook, чтобы получить данные вошедшего в систему пользователя.
  • Строка 7: проверьте, не вошел ли пользователь в систему (если session не имеет значения). Если да, предложите пользователю войти в систему. Метод signIn обрабатывает функции входа.
  • Строка 19: Если пользователь вошел в систему (если session имеет значение), то показать возможность выхода. Метод signOut сделает это за нас.
  • Строка 21: отображение имени пользователя на главной странице.

Последний шаг - изменить наш _app.js файл. В /pages/_app.js сначала импортируйте модуль Provider следующим образом:

Теперь найдите в /pages/_app.js следующий фрагмент кода:

Измените это так:

  • Строки 2–4: оберните наш Component тегами Provider. Это сделает наши данные сеанса постоянными на всех маршрутах.

Запустите код. Это будет результат:

Большой! Наш код работает как задумано. Теперь создадим наш Note компонент.

В итоге ваш /pages/_app.js файл должен выглядеть так:

import "../styles/globals.css";
import { Provider } from "next-auth/client";
function MyApp({ Component, pageProps }) {
return (
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
);
}
export default MyApp;

Компонент Note

В папке components создайте файл с именем Note.js. В этом файле напишите следующий фрагмент кода:

import Link from "next/link";
import { useRouter } from "next/router";
export default function Note({ id, title }) {
const router = useRouter();
const sendDelete = async () => {
const res = await fetch(`/api/notes/delete/${id}`, {
method: "DELETE",
});
router.push("/dashboard");
};
return (
<div>
<Link href={`/notes/${id}`}>
<a>
{" "}
<h1>{title}</h1>
</a>
</Link>
<button>
<Link href={`/notes/update/${id}`}>Update</Link>
</button>
<button onClick={() => sendDelete()}>Delete</button>
</div>
);
}
  • Строка 4: Наш Note компонент будет иметь два свойства: id и title.
  • Строка 5: этот useRouter экземпляр поможет нам выполнять перенаправление на стороне клиента.
  • Строка 7: Создайте функцию sendDelete.
  • Строки 8–10: выполнение запроса DELETE к маршруту api/notes/delete/{id}. Это скажет серверу идентифицировать нашу запись по id, а затем удалить ее.
  • Строка 11: После запроса DELETE перенаправьте пользователя на /dashboard.
  • Строки 16-21: отобразите опору title. Если щелкнуть, перенаправить пользователя на маршрут /notes/{id}. Это отобразит полную информацию о заметке.
  • Строки 22-24: перенаправляют пользователя на страницу /notes/update/${id}. Это позволит клиенту обновить указанный документ.
  • Строка 25: Если щелкнуть, вызвать функцию sendDelete.

В следующем разделе мы создадим нашу страницу панели инструментов.

Страница панели инструментов

В папке /pages создайте файл с именем dashboard.js. В этом файле будут показаны все сохраненные заметки пользователя.

В pages/dashboard.js напишите следующий код:

import { useSession } from "next-auth/client";
import Link from "next/link";
import Note from "../components/Note";
export default function Dashboard() {
const [session, loading] = useSession();
return (
<div>
{!session && <h1>You're not logged in yet</h1>}
{session && <h1>Hello, {session.user.name}!</h1>}
<button>
<Link href={`/notes/add`}>Add</Link>{" "}
</button>
<button onClick={() => signOut({ callbackUrl: "/" })}>Sign out</button>
</div>
);
}
  • Строка 6: useSession Hook сообщит нам, вошел ли пользователь в систему.
  • Строка 11: отображение приветственного сообщения, если пользователь вошел в систему.
  • Строки 13–14: при нажатии пользователь будет перенаправлен на маршрут notes/add.
  • Строка 15: Эта кнопка позволяет пользователю выйти из системы. В случае успеха наше приложение перенаправит их на страницу /.

Запустите код. Должен быть результат:

Однако заставлять пользователя вручную переходить на страницу /dashboard - не очень удобно. Нам нужно это исправить.

В pages/index.js найдите следующий фрагмент кода:

Измените это так:

  • Строка 3: Когда пользователь входит в систему, перенаправьте его на страницу dashboard.

Запустите код. Должен быть результат:

Готово! Пришло время создать на его основе наше приложение для создания заметок.

В итоге /pages/index.js должен выглядеть так:

import { signIn, signOut, useSession } from "next-auth/client";
export default function Home() {
const [session, loading] = useSession();
return (
<div>
{loading && <p>Loading..</p>}
{!session && (
<>
Not signed in <br />
<button
onClick={() =>
signIn("google", {
callbackUrl: "http://localhost:3000/dashboard",
})
}
>
Sign in
</button>
</>
)}
{session && (
<>
Signed in as {session.user.name} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
)}
</div>
);
}

Приложение "Заметки"

Модель Notes

В папке /models создайте файл с именем Note.js. В /models/Note.js напишите следующий код:

import mongoose, { Schema } from "mongoose";
const noteSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "user",
},
title: String,
body: String,
});
mongoose.models = {};
export default mongoose.models.Note || mongoose.model("Note", noteSchema);
view raw Note.js hosted with ❤ by GitHub
  • Строка 3: Определите наш noteSchema.
  • Строка 4: В нашей коллекции будет поле user, которое будет связано с вошедшим в систему пользователем. Это позволяет нам создать реляционную базу данных.
  • Строки 8–9: Наша модель будет иметь поля title и body, которые будут содержать строковые значения.
  • Строка 13: Экспортируйте нашу Note модель, которая будет производным от noteSchema.

Давайте теперь поработаем над связыванием нашей базы данных с этим проектом.

Подключение к базе данных

В папке helpers создайте файл с именем dbConnect.js. Как следует из названия, этот файл содержит конфигурацию нашей базы данных.

В helpers/dbConnect.js напишите следующий код:

import mongoose from "mongoose";
const MONGODB_URI = process.env.MONGODB_URI;
if (!MONGODB_URI) {
throw new Error(
"Please define the MONGODB_URI environment variable inside .env.local"
);
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
bufferCommands: false,
bufferMaxEntries: 0,
useFindAndModify: false,
useCreateIndex: true,
};
cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
view raw dbConnect.js hosted with ❤ by GitHub
  • Строки 3–9: Получите нашу строку подключения MongoDB от .env.local. Если его нет, то выдает ошибку.
  • Строка 16: Здесь мы используем Globals для поддержания кэшированного соединения. Это предотвратит рост количества подключений во время использования.
  • Строка 28-34: Укажите конфигурацию нашей базы данных.
  • Строка 37: подключение к базе данных.
  • Строка 45: Наконец, экспортируем нашу dbConnect функцию. Теперь мы можем использовать его в нашем проекте.

Мы сделали! Давайте теперь поработаем с CRUD-операциями с нашими заметками.

Добавление заметки

Перейдите в папку /pages/api/notes и создайте файл с именем add.js. Этот файл скажет нашей базе данных вставить запись.

В /pages/api/notes/add.js напишите следующий код:

import { getSession } from "next-auth/client";
import Note from "../../../models/Note";
import dbConnect from "../../../helpers/dbConnect";
export default async (req, res) => {
const user = await getSession({ req });
await dbConnect();
if (!user) {
return res.json({ error: "not logged in" });
}
if (req.method === "POST") {
const note = new Note({
user: user.id,
title: req.body.title,
body: req.body.body,
});
note.save(async function (err, doc) {
if (err) console.log(err);
console.log(doc);
});
}
res.end();
};
view raw add.js hosted with ❤ by GitHub
  • Строка 6: Метод getSession вернет данные пользователя.
  • Строка 8: Подключитесь к базе данных перед выполнением любых критически важных для базы данных функций.
  • Строка 10: Если клиент не вошел в систему, отправьте сообщение об ошибке.
  • Строка 14: Проверить, был ли выполнен запрос POST.
  • Строки 15–16. Если верно, то создайте Note документ с полем user, указывающим на id вошедшего в систему пользователя. Это позволяет нам строить отношения.
  • Строки 17-18: поля title и body будут содержать введенные пользователем данные.
  • Строки 21-24: Сохраните документ и выйдите из сохраненной записи.
  • Строка 26: Завершить ответ.

Давайте теперь закодируем наш интерфейс для этой функции. В /pages/notes создайте файл с именем add.js.

В pages/notes/add.js напишите следующий код:

import { useSession } from "next-auth/client";
import { useRouter } from "next/router";
export default function Add() {
const router = useRouter();
const [session, loading] = useSession();
const addNote = async (event) => {
event.preventDefault();
const res = await fetch("/api/notes/add", {
body: JSON.stringify({
title: event.target.title.value,
body: event.target.body.value,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
});
router.push("/dashboard");
};
return (
<div>
{loading && <p>Loading..</p>}
{session ? (
<form onSubmit={addNote}>
<label htmlFor="name">Name</label>
<input id="title" name="title" type="text" autoComplete="name" />
<input id="body" name="body" type="text" autoComplete="false" />
<button type="submit">Add</button>
</form>
) : (
<p>Not logged in to view this resource</p>
)}
</div>
);
}
view raw pages-add.js hosted with ❤ by GitHub
  • Строка 7: Создайте нашу функцию addNote.
  • Строки 10-19: отправьте POST запрос на /api/notes/add. Это скажет нашему серверу добавить данные в базу данных. Наши поля body и title будут иметь значения input.
  • Строка 20: Когда запрос завершен, перенаправьте пользователя на /dashboard.
  • Строка 26: Когда форма отправлена, вызовите функцию addNote.

Запустите код. Должен быть результат:

Посмотрите на консоль:

Это доказывает, что наш документ был сохранен в базе данных. Наш код работает так, как ожидалось.

Теперь мы будем работать над отображением всех наших заметок.

Отображение наших заметок

Давайте сначала разработаем внутренний код этого раздела. В папке /pages/api/notes создайте файл с именем list.js. В этом файле напишите следующий код:

import { getSession } from "next-auth/client";
import Note from "../../../models/Note";
import dbConnect from "../../../helpers/dbConnect";
export default async (req, res) => {
const user = await getSession({ req });
await dbConnect();
if (user) {
console.log("user id: " + user.id);
const notes = await Note.find({ user: user.id }).lean();
return res.json({ notes });
} else res.json({ error: "Not logged in" });
};
view raw list.js hosted with ❤ by GitHub
  • Строка 11: Найдите все заметки пользователя. Это делается путем фильтрации заметок, содержащих поле user поля id текущего пользователя. Наконец, используйте метод lean, чтобы вернуть документы в формате JSON.
  • Строка 12: отправьте результаты клиенту в формате JSON.
  • Строка 13: Если пользователь не вошел в систему, вернуть ошибку.

Теперь поработаем с нашим интерфейсом. В /pages/dashboard.js добавьте следующий фрагмент кода:

export async function getServerSideProps(context) {
const hostname = "http://localhost:3000";
const options = { headers: { cookie: context.req.headers.cookie } };
const res = await fetch(`${hostname}/api/notes/list`, options);
const json = await res.json();
if (json.error) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: {
data: json,
},
};
}
  • Строка 1: функция getServerSideProps получит данные с сервера.
  • Строка 3: Создайте наши заголовки, чтобы сообщить NextAuth.js, что мы уполномочены просматривать наши документы.
  • Строка 4: Выполните FETCH запрос к нашему серверу и отправьте эти заголовки.
  • Строка 6: Если возвращенные данные содержат ошибку, вместо этого перенаправьте пользователя на маршрут /.
  • Строка 14: отправьте возвращенные данные как реквизиты.

Затем в /pages/dashboard.js найдите следующий фрагмент кода:

Измените это так:

Теперь мы можем использовать данные, возвращаемые сервером, в нашем компоненте.

В этом же файле найдите свой return блок:

Замени его так:

  • Строка 2: Используйте функцию map для отображения наших данных.
  • Строка 4: Каждый объект будет отображаться с компонентом Note.

Запустите код. Должен быть результат:

Наш код работает! Давайте теперь поработаем над чтением конкретного документа.

В итоге /pages/dashboard.js должно выглядеть так:

import { signIn, signOut, useSession, getSession } from "next-auth/client";
import Link from "next/link";
import Note from "../components/Note";
export default function Dashboard({ data }) {
const [session, loading] = useSession();
return (
<div>
{data.notes.map((item) => (
<Note id={item._id} title={item.title} body={item.body} />
))}
<button>
<Link href="/notes/add">Add</Link>{" "}
</button>
<button onClick={() => signOut({ callbackUrl: "/" })}>Sign out</button>
</div>
);
}
export async function getServerSideProps(context) {
const hostname = "http://localhost:3000";
const options = { headers: { cookie: context.req.headers.cookie } };
const res = await fetch(`${hostname}/api/notes/list`, options);
const json = await res.json();
if (json.error) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: {
data: json,
},
};
}

Чтение заметки

В качестве первого шага нам нужно закодировать бэкэнд. В каталоге /pages/api/notes создайте файл с именем [id].js. Здесь напишите следующий код:

import { getSession } from "next-auth/client";
import Note from "../../../models/Note";
import dbConnect from "../../../helpers/dbConnect";
export default async (req, res) => {
const user = await getSession({ req });
await dbConnect();
if (!user) return res.json({ error: "Not logged in" });
const note = await Note.findOne({ _id: req.query.id, user: user.id });
return res.json({ note });
};
view raw [id].js hosted with ❤ by GitHub
  • Строка 10. Найдите заметку пользователя с конкретным id.
  • Строка 12: вернуть документ в формате JSON.

Теперь нам нужно создать наш интерфейс. В папке /pages/notes создайте файл с именем [id].js. Это означает, что этот файл будет обрабатывать маршрут /pages/notes/{id}. Здесь {id} - это id нашей заметки.

В /pages/notes/[id].js напишите следующий код:

export default function Specific({ data }) {
return (
<>
{data.note && (
<div>
<h1>{data.note.title}</h1>
<p>{data.note.body}</p>
</div>
)}
</>
);
}
export async function getServerSideProps(context) {
const hostname = "http://localhost:3000";
const options = { headers: { cookie: context.req.headers.cookie } };
const res = await fetch(
`${hostname}/api/notes/${context.params.id}`,
options
);
const json = await res.json();
if (json.error) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
return {
props: {
data: json,
},
};
}
view raw notes-[id].js hosted with ❤ by GitHub
  • Строка 1: свойство data содержит наши данные, которые мы хотим отобразить.
  • Строки 6-7: отображают поля title и body нашего объекта.
  • Строка 14: Создайте функцию getServerSideProps для получения данных с сервера.
  • Строки 18–22: выборка данных из базы данных и их возврат.
  • Строки 24-31: Если была ошибка, вместо этого перенаправьте пользователя на /.
  • Строка 33: вернуть данные в компонент Specific в качестве свойств.

Запустите код. Должен быть результат:

Большой! Наш код работает так, как ожидалось.

На следующем шаге мы узнаем, как обновлять наши записи.

Обновление заметки

В каталоге /pages/api/note создайте папку с именем update. В этой папке создайте файл с именем [id].js.

В /pages/api/note/update/[id].js напишите следующий код:

import { getSession } from "next-auth/client";
import Note from "../../../../models/Note";
import dbConnect from "../../../../helpers/dbConnect";
export default async (req, res) => {
const user = await getSession({ req });
if (!user) return res.json({ error: "user not logged in" });
await dbConnect();
if (req.method === "GET") {
let note = await Note.findOne({ user: user.id, _id: req.query.id }).lean();
return res.json({ note });
}
if (req.method === "PUT") {
let note = await Note.findOneAndUpdate(
{
user: user.id,
_id: req.query.id,
},
{ title: req.body.title, body: req.body.body },
(err, doc) => console.log(doc)
);
}
res.end();
};
view raw update.js hosted with ❤ by GitHub
  • Строка 11: Проверить, был ли выполнен запрос GET.
  • Строка 12: Если true, найдите примечание с совпадающим id, которое находится в параметре URL-адреса.
  • Строка 13: Наконец, верните данные в формате JSON.
  • Строка 16: Проверить, был ли выполнен запрос PUT.
  • Строка 17: Найдите документ с совпадающим id и затем обновите его.
  • Строка 22: Обновите поля title и body значениями, введенными пользователем.
  • Строка 26: Завершить ответ.

Теперь напишем наш интерфейс. В папке /pages/notes создайте еще один каталог с именем update. Здесь создайте файл с именем [id].js.

В /pages/notes/update/[id].js напишите следующий код:

import { useRouter } from "next/router";
export default function Update({ data }) {
const router = useRouter();
const { id } = router.query;
const updateNote = async (event) => {
event.preventDefault();
const res = await fetch(`/api/notes/update/${id}`, {
body: JSON.stringify({
title: event.target.title.value,
body: event.target.body.value,
}),
headers: {
"Content-Type": "application/json",
},
method: "PUT",
});
router.push("/dashboard");
};
}
view raw update-page.js hosted with ❤ by GitHub
  • Строка 3: Используйте опору data в нашем компоненте. Он будет содержать данные с сервера.
  • Строка 5: извлеките параметр id из URL-адреса.
  • Строка 7: Создайте функцию updateNote.
  • Строка 10: Выполните PUT запрос к api/notes/update маршруту и ​​отправьте наши входные поля title и body в качестве полезной нагрузки.
  • Строка 20: По завершении запроса перенаправьте пользователя на страницу /dashboard.

Когда это будет сделано, добавьте в тот же файл следующий код:

return (
<div>
{data.error ? (
<p>{data.error}</p>
) : (
<form onSubmit={updateNote}>
<label htmlFor="name">Name</label>
<input
id="title"
name="title"
type="text"
defaultValue={data.note.title}
autoComplete="name"
/>
<input
id="body"
name="body"
type="text"
defaultValue={data.note.body}
autoComplete="false"
/>
<button type="submit">Update</button>
</form>
)}
</div>
);
}
  • Строка 6: После отправки формы запустите функцию updateNote.
  • Строки 8-13: Создаем наш input элемент. Его начальным значением будет поле title нашей заметки.
  • Строки 15-20: создайте наш input элемент, который будет содержать поле body примечания в качестве значения по умолчанию.

В качестве последнего шага нам нужно указать Next.js получить данные. Добавьте в этот файл следующий код:

export async function getServerSideProps(context) {
const hostname = "http://localhost:3000";
const options = { headers: { cookie: context.req.headers.cookie } };
const res = await fetch(
`${hostname}/api/notes/update/${context.params.id}`,
options
);
const json = await res.json();
return {
props: {
data: json,
},
};
}

Этот код функции идентичен коду файла /pages/notes/[id].js.

Запустите код. Это будет результат:

Вуаля! Результат оказался ожидаемым. Давайте теперь поработаем над удалением нашей записи.

В итоге /pages/notes/update/[id].js должен выглядеть так:

import { useRouter } from "next/router";
export default function Update({ data }) {
const router = useRouter();
const { id } = router.query;
const updateNote = async (event) => {
event.preventDefault();
const res = await fetch(`/api/notes/update/${id}`, {
body: JSON.stringify({
title: event.target.title.value,
body: event.target.body.value,
}),
headers: {
"Content-Type": "application/json",
},
method: "PUT",
});
router.push("/dashboard");
};
return (
<div>
{data.error ? (
<p>{data.error}</p>
) : (
<form onSubmit={updateNote}>
<label htmlFor="name">Name</label>
<input
id="title"
name="title"
type="text"
defaultValue={data.note.title}
autoComplete="name"
/>
<input
id="body"
name="body"
type="text"
defaultValue={data.note.body}
autoComplete="false"
/>
<button type="submit">Update</button>
</form>
)}
</div>
);
}
export async function getServerSideProps(context) {
const hostname = "http://localhost:3000";
const options = { headers: { cookie: context.req.headers.cookie } };
const res = await fetch(
`${hostname}/api/notes/update/${context.params.id}`,
options
);
const json = await res.json();
return {
props: {
data: json,
},
};
}
view raw update-[id].js hosted with ❤ by GitHub

Удаление записи

В папке /pages/api/notes создайте каталог с именем delete. Здесь создайте файл с именем [id].js.

В /pages/api/notes/delete/[id].js напишите следующий код:

import { getSession } from "next-auth/client";
import Note from "../../../../models/Note";
import dbConnect from "../../../../helpers/dbConnect";
export default async (req, res) => {
await dbConnect();
const session = await getSession({ req });
if (!session) {
return res.json({ error: "not logged in" });
} else {
await Note.findOneAndDelete(
{
_id: req.query.id,
user: session.id,
},
function (err, docs) {
if (err) console.log(err);
}
);
res.end();
}
};
view raw delete-[id].js hosted with ❤ by GitHub
  • Строка 11: Найдите заметку с совпадающими полями id и user. Если нашел, то удалите.
  • Строка 20: Завершить ответ.

Запустите код. Должен быть результат:

Готово! Результат оказался ожидаемым.

Дополнительные ресурсы

Репозиторий GitHub

Другой учебный материал

Заключение

NextAuth.js упростил разработчикам создание функций аутентификации пользователей в своих приложениях. Как следствие, это улучшает опыт разработчика. Более того, нам не нужно было создавать внешний сервер Express для построения нашей системы входа в систему. Все было сделано в Next.js, что обещало более быстрое и производительное приложение.

Если вы столкнулись с какими-либо проблемами, советую разобрать программу и поиграться с кодом. Спасибо, что дожили до конца!