Создание сайтов в Алмазной, ЛНР. Создайте веб-приложение фрагмента кода с помощью Next.js и FaunaDB

 
 

При программировании разработчики сталкиваются с проблемами, требующими повторного использования кода, что приводит к повторяющемуся программированию, которое может отнимать время и снижает производительность. Это приводит к необходимости многократного использования исходного кода, называемого «фрагментами кода». Эти фрагменты предотвращают повторение кода во время программирования, могут быть сохранены для использования в будущем и доступны для совместного использования.

В этом руководстве мы создадим веб-сайт, чтобы помочь пользователям сохранять ежедневные фрагменты кода, используя среду веб-разработки Next.js и используя базу данных Fauna для управления хранением, обработкой и отображением фрагментов кода. Работая над этим забавным проектом, мы также узнаем, как создать базовое CRUD-приложение с помощью Next.js и FaunaDB, которое также можно использовать для создания других подобных проектов.

Рабочую версию этого проекта можно найти на GitHub. Чтобы продолжить, вам потребуется установленный на вашем компьютере Node, а также учетная запись FaunaDB и учетная запись Google (для аутентификации).

Установка зависимостей

В этом разделе мы рассмотрим, как установить Next.js с помощью npx create-next-appкоманды. Это инициализирует Next CLI и создаст новое приложение Next.js.

Мы также установим зависимости, которые будем использовать для серверной части — FaunaDB и SWR — через командную строку. SWR (state-while-revalidate) — это хук Next.js для получения данных. Мы подробно рассмотрим это позже в этом уроке.

Установка Next.js

Чтобы установить Next.js, введите в CLI следующую команду:

npx create-next-app snippetapp

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

cd snippetapp

Установка FaunaDB и SWR

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

npm install —save faunadb

Затем для установки SWR:

npm install swr@0.3.8

Таким образом, мы установили все зависимости, которые будем использовать для создания нашего приложения, и теперь можем приступить к настройке нашей базы данных в Fauna.

Настройка базы данных фауны

FaunaDB — это бессерверная база данных, работающая в режиме реального времени. Он превращает традиционную базу данных в гибкий API данных, который по-прежнему сохраняет возможности базы данных и ее производительность, обеспечивая при этом безопасный и масштабируемый доступ к данным приложения.

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

Создание учетной записи пользователя

Чтобы создать учетную запись пользователя, перейдите на страницу регистрации Fauna и создайте учетную запись.

Создание учетной записи FaunaDB

После создания учетной записи пользователя вы будете перенаправлены на панель инструментов.

Панель инструментов FaunaDB

Создайте базу данных фрагментов и коллекцию

Здесь мы создадим базу данных с коллекциями, необходимыми для управления фрагментами кода нашего приложения. Нажмите СОЗДАТЬ БАЗУ ДАННЫХ. Мы создадим базу данных с именем snippets.

Создание базы данных фрагментов FaunaDB

На открывшейся новой странице нажмите НОВАЯ КОЛЛЕКЦИЯ и создайте коллекцию под названием codesnippet.

страница коллекции

После создания коллекции мы получаем страницу, на которой можем создать документ.

Создать документ

Здесь вы нажмете НОВЫЙ ДОКУМЕНТ. Откроется документ JSON, где вы можете ввести данные, как показано на рисунке ниже.

Создание документа

{

name: «Prompt User»,

description: «prompts the user»,

language: «javascript»,

code: «prompt ('would you like to continue’)»

}

Здесь мы определяем фрагмент с атрибутами: name, descriptionи language. codeНажмите СОХРАНИТЬ, чтобы сохранить новую коллекцию. Мы успешно добавили фрагмент в нашу базу данных. Теперь мы можем перейти к получению наших учетных данных для использования в нашем приложении.

Создание секретного ключа

На панели инструментов нажмите «Безопасность «. Откроется новая страница для создания нашего ключа безопасности.

Создание ключа безопасности FaunaDB

Здесь мы установим роль «сервер» вместо «администратор», и вы можете дать ключу имя. Нажмите кнопку СОХРАНИТЬ, чтобы сгенерировать ключ.

Создание.envфайла

Теперь мы создадим.envфайл в каталоге нашего проекта. В этом файле будет храниться наш сгенерированный секретный ключ. В.envфайле имеем вот это:

FAUNA_SECRET = paste your key here

Создание страницы фрагмента кода

В этом разделе мы создадим страницу отображения и загрузки для сниппетов, а также добавим в нее функциональность.

Откройте каталог проекта в редакторе кода и перейдите к index.jsфайлу в папке ваших страниц. Здесь мы очистим код и начнем создавать наше приложение:

import Head from «next/head»

import Image from «next/image»

import styles from «.../styles/Home.module.css»

export default function Home () {

return (

Re-usuable Code Snippets

Add your code snippets here...

)

}

Создание наших компонентов

Теперь мы создадим файл компонента, который будет отображать наши фрагменты. Создайте папку с именем componentв вашем рабочем каталоге и создайте в ней файл с именем Snippets.jsсо следующим кодом:

import React from «react»

import styles from «.../styles/Home.module.css»

function Snippets () {

return (

language

name of snippet

description of snippet

{/* Code will be displayed here*/}

)

}

export default Snippets

Импорт наших компонентов в приложение

Теперь мы добавим импорт для этого файла в наш index.js:

import Snippets from «.../components/Snippets»

И использовать его в нашем приложении:

Стилизация нашего приложения

Теперь мы можем стилизовать нашу страницу. Перейдите к Home.module.cssфайлу в stylesпапке и замените там стили следующими:

.container{

display: flex;

height: 100%;

min-height: 100vh;

background: rgb (48, 48, 255) ;

flex-direction: column;

align-items: center;

color: #fff;

font-family: Montserrat;

}

.cont{

color: #333;

margin-top: 5px;

background: rgb (214, 214, 214) ;

border-radius: 15px;

padding: 10px 15px;

}

.main button{

width: fit-content;

flex-grow: unset;

display: inline-block;

padding: 5px 10px;

outline: none;

border: none;

border-radius: 5%;

font-weight: bold;

color: rgb (48, 48, 255) ;

}

.main button: hover{

cursor: pointer;

}

.links{

margin-top: 10px;

}

.links a{

margin-left: 5px;

}

.links a: hover{

cursor: pointer;

}

Просмотр нашего приложения

На этом этапе вы сможете запустить сервер разработки с помощью npm run dev, посетить http: //localhost:3000 и увидеть скелет нашего приложения.

Настройка области отображения сниппета

Далее мы создадим раздел отображения для кода фрагмента. Создайте новый файл с именем Code.jsв папке компонентов и импортируйте его в Snippets.js:

import React from 'react’

import styles from '.../styles/Home.module.css’

import Code from «. /Code»;

function Snippets () {

return (

language

name of snippet

description of snippet

{/* Code will be displayed here*/}

)

}

export default Snippets

Для подсветки синтаксиса кода мы будем использовать два пакета, а именно react-syntax-highlighter и react-copy-to-clipboard. Мы можем загрузить это через CLI:

npm install react-syntax-highlighterreact-copy-to-clipboard —save

Затем в Code.js:

import React from «react»

import { PrismLight as SyntaxHighlighter } from «react-syntax-highlighter»

import {atomDark} from «react-syntax-highlighter/dist/cjs/styles/prism»

import { CopyToClipboard } from «react-copy-to-clipboard»

import styles from «.../styles/Home.module.css»

function Code () {

const codeString = «npm install import react from 'react’»

const [show, setshow] = React.useState (false)

return (

{show? (

 

 

 

{codeString}

): null}

)

}

export default Code

Здесь мы создали компонент для отображения кода с подсветкой синтаксиса. Мы также добавили функции копирования и переключения. Теперь в stylesфайле:

.btn{

left: 80%;

position: relative;

}

Тестирование блоков кода

Чтобы просмотреть это изменение, вы можете запустить npm run devего в командной строке и просмотреть в своем браузере. У нас есть строка «npm install import react from 'react’», отображаемая с подсветкой синтаксиса в виде блока кода. Также есть кнопка для скрытия и отображения фрагмента кода и кнопка, позволяющая скопировать код из блока кода.

Инициализация базы данных фауны

В этом разделе мы будем получать данные из нашей базы данных FaunaDB в наше приложение. Создайте файл с именем Fauna.jsв каталоге вашего проекта:

const faunadb = require («faunadb»)

const faunaClient = new faunadb.Client ({

secret: process.env.FAUNA_SECRET

})

const q = faunadb.query

const getResponse = async () => {

const { data } = await faunaClient.query (

q.Map (

q.Paginate (q.Documents (q.Collection («codesnippet»))),

q.Lambda («doc», q.Get (q.Var («doc»)))

)

)

const snippets = data.map ((snippet) => {

snippet.id = snippet.ref.id

delete snippet.ref

return snippet

})

return snippets

}

module.exports = {

getResponse,

}

Здесь мы инициализировали FaunaDB с помощью нашего секретного ключа. Мы также создали asyncзапрос для запроса нашей коллекции и возврата данных. Мы сохранили возвращенные данные в переменной с именем snippetsи удалили ссылку, чтобы лучше структурировать данные. Другие функции для создания, обновления и удаления фрагментов будут добавлены позже в этом руководстве.

Обратите внимание, что если вы получаете несанкционированную ошибку в консоли, вам может потребоваться указать доменное имя целевой конечной точки. По умолчанию используется db.fauna.com, но с момента введения региональных групп доступны три облачных домена. Используйте правильный домен для группы регионов вашей базы данных:

Классический (США и ЕС): db.fauna.com

США (США): db.us.fauna.com

Европа (ЕС): db.eu.fauna.com

Пример кода:

const faunaClient = new faunadb.Client ({

secret: process.env.FAUNA_SECRET,

domain: «db.eu.fauna.com»

})

Обработка наших запросов API

Мы также создадим файл для обработки нашего запроса API для нашей базы данных. В apiпапке в pages, создайте файл с именем snippets.jsсо следующим кодом:

import { getResponse } from «.../... /Fauna.js»

export default async function handler (req, res) {

console.log (req)

if (req.method≠= «GET») {

return res.status (405)

}

try {

const snippets = await getResponse ()

return res.status (200).json (snippets)

} catch (err) {

console.log (err)

res.status (500).json ({ msg: «Something went wrong.» })

}

}

Выше мы просто настроили функцию для обработки запросов из нашей базы данных. Фрагменты возвращаются как Jsonи регистрируют ошибки, если таковые возникают. В Next.js любой файл, хранящийся в apiпапке, рассматривается как конечная точка API, а не как страница, и обрабатывается на стороне сервера.

Что такое КСВ?

Как было сказано ранее, SWR (state-while-revalidate) — это хук Next.js для получения данных. Это идеальное решение для получения часто обновляемых данных, и оно хорошо подходит для нашего приложения.

Настройка КСВ

Мы будем использовать это для получения данных из FaunaDB. Чтобы использовать это, нам нужно импортировать его в index.js:

import useSWR from «swr»

export default function Home () {

const { data: snippets, mutate }=useSWR («api/snippets»)

...

})

Здесь мы импортировали SWR и использовали его для получения данных в соответствии с настройками в формате snippets.js. Затем мы сохранили эти фрагменты в snippetsпеременной и будем выводить их оттуда. Теперь мы передадим snippetsнашему Snippetsкомпоненту для отображения:

+ {snippets &&

+ snippets.map ((snippet) => (

+ <Snippets

+ key={snippet.id}

+ snippet={snippet}

+ snippetDeleted={mutate}

+ />

+))

+ }

Выше мы передали ключ и фрагмент в Snippets. Мы также настроили mutateсвойство для обновления (повторного извлечения) фрагментов при удалении фрагмента. Чтобы использовать переданные данные, мы модифицируем Snippetsкомпонент следующим образом:

function Snippets ({snippet}) {

return (

{snippet.data.language}

{snippet.data.name}

{snippet.data.description}

)

}

Выше мы вставили в наш код язык фрагмента, имя и описание, полученные от FaunaDB. Чтобы получить код от Fauna в нашем приложении, нам также пришлось передать Codeкомпоненту сниппет.

Затем в Codeкомпоненте:

function Code ({snippet}) {

...

{snippet.data.code}

...

}

Мы закончили с GetSnippetфункциональностью. Если мы вернемся в FaunaDB и создадим новый фрагмент, мы увидим то, что изображено ниже.

добавил еще один документ в FaunaDB

{

«name»: «console.log ()»,

«language»: «javascript»,

«description»: «logs out data»,

«code»: «console.log ('Hello, world!')»'

}

Запуск кода

Для запуска в CLI:

npm run dev

Если вы откроете страницу в своем браузере, вы получите результат, подобный изображенному ниже.

Страница отображения фрагмента

Мы успешно создали страницу отображения фрагмента кода с функциями отображения и скрытия кода и копирования фрагмента кода.

Страница загрузки фрагмента

Нам нужно создать ссылку на страницу загрузки из нашего домашнего компонента. В Next.js есть положения, которые упрощают маршрутизацию без необходимости установки react-routerи других зависимостей, как если бы вы использовали собственный код React.

В index.js, мы будем импортировать Linkмодуль из next:

import Link from «next/link»

Затем добавьте его к нашей кнопке «Создать новый фрагмент «:

+

+

+

Мы создадим новую страницу в нашей pagesпапке и назовем ее upload.js.

Вернувшись в наш Fauna.jsфайл, мы создадим, а также экспортируем функцию для создания фрагментов в нашем приложении:

const createSnippet = async (code, language, description, name) => {

return await faunaClient.query (q.Create (q.Collection («codesnippet»), {

data: {code, language, description, name}

}))

}

module.exports = {

getResponse,

createSnippet,

}

Здесь мы создали функцию createSnippet, которая будет принимать некоторые параметры и передавать их как данные в новый документ, который будет создан в базе данных.

Добавление функции для создания сниппетов

Мы также настроим нашу конечную точку для создания фрагментов. Создайте новый файл с именем createSnippet.jsв apiпапке и заполните его следующим кодом:

import { createSnippet } from «.../... /Fauna»

export default async function handler (req, res) {

const { code, language, description, name } = req.body

if (req.method≠= «POST») {

return res.status (405).json ({msg:"unauthorized"})

}

try {

const createdSnippet = await createSnippet (code, language, description, name)

return res.status (200).json (createdSnippet)

} catch (error) {

console.log (error)

res.status (500).json ({msg:"unauthorized"})

}

}

Создание нашей страницы загрузки

Теперь мы создадим страницу загрузки в нашем upload.jsфайле. Чтобы наша форма создавала сниппеты, мы будем использовать форму react-hook. Мы установим это через CLI:

npm install react-hook-form

Затем в нашем upload.jsфайле:

import React from «react»

import { useForm } from «react-hook-form»

import { useRouter } from «next/router»

import style from «.../styles/form.module.css»

import { Link } from «next/link»

function upload ({ snippet }) {

const { register, handleSubmit, errors, reset } = useForm ()

const router = useRouter ()

const createSnippet = async (data) => {

const { code, language, description, name } = data

console.log (data)

try {

// code here to push to Fauna

} catch (error) {

console.log (error)

}

}

return (

 

 

<form

className={style.form}

onSubmit={handleSubmit (snippet? updateSnippet: createSnippet) }

>

 

 

<input

className={style.input}

type="text"

id="name"

{...register («name», { required: true }) }

/>

 

 

 

 

 

language

 

<select

className={style.select}

type="text"

id="language"

{...register («language», { required: true }) }

>

 

 

 

 

 

 

 

 

 

description

 

<textarea

className={style.input}

rows={7}

type="text"

id="description"

placeholder="snippet description"

{...register («description», { required: true }) }

/>

 

 

 

 

 

Code

 

<textarea

className={style.input}

rows={8}

columns={8}

type="text"

id="code"

{...register («code», { required: true }) }

placeholder="background: none;"

/>

 

 

 

 

 

 

 

 

 

)

}

export default upload

Стилизация нашей формы

Выше мы создали нашу форму, используя react-hook-formфайл package. Мы использовали handleSubmitфункцию useForm () в тернарном операторе. После отправки формы он определяет, предназначена ли отправка для создания или обновления существующего фрагмента. С помощью registerмы добавили необходимое свойство к каждому полю в нашей форме. Мы также добавили импорт для таблицы стилей с именем form.module.css, где у нас есть следующие стили для нашей формы:

.form {

max-width: 800px;

display: flex;

justify-content: center;

flex-direction: column;

align-items: center;

}

.cont{

background: rgb (48, 48, 255) ;

height: 100%;

min-height: 100vh;

padding: 10px 0 0 0;

display: flex;

justify-content: center;

align-items: center;

}

.select,

.input {

display: block;

box-sizing: border-box;

width: 100%;

border-radius: 4px;

border: 1px solid black;

padding: 10px 15px;

margin-bottom: 15px;

font-size: 14px;

}

.label{

line-height: 2;

text-align: left;

display: block;

margin: 5px;

color: white;

font-size: 14px;

font-weight: 200;

}

.button {

background: #fff;

color: #444;

border: none;

border-radius: 5%;

margin-right: 8px;

}

Создание конечной точки API для создания фрагментов

Чтобы отправить данные из нашей формы в базу данных FaunaDB, добавьте следующий код в try...catchблок в createSnippetфункции в upload.js:

try {

await fetch («/api/createSnippet», {

method: «POST»,

body: JSON.stringify ({ code, language, description, name }),

headers: {

«Content-type»: «application/json»

},

})

router.push («/»)

} catch (error) {

console.log (error)

}

Тестирование нашей формы

Запустите код и перейдите на страницу загрузки. Теперь, если мы добавим в форму новый фрагмент и нажмем «Отправить «, мы увидим то, что изображено ниже.

Страница загрузки фрагмента

Когда мы переходим к нашему домашнему компоненту, мы видим созданный фрагмент.

Создан новый фрагмент

Создание функции для редактирования сниппетов

Чтобы создать нашу функцию редактирования фрагмента, в Fauna.jsфайле мы создадим и экспортируем функцию для выполнения этой задачи:

const updateSnippet = async (id, code, language, description, name) => {

return await faunaClient.query (q.Update (q.Ref (q.Collection («codesnippet»), id), {

data: {code, language, name, description},

}))

}

module.exports = {

...

updateSnippet,

}

Создание конечной точки API для редактирования фрагментов

Эта функция аналогична createSnippetфункции, но также принимает параметр id. Он использует этот идентификатор, чтобы определить, какие фрагменты следует редактировать. Если idсоответствует, мы обновляем данные с другими параметрами. Мы также создадим файл конечной точки в apiкаталоге с именем updateSnippet.jsдля обработки обновлений:

import { updateSnippet } from «.../... /Fauna»

export default async function handler (req, res) {

const { id, code, language, description, name } = req.body

if (req.method≠= «PUT») {

return res.status (405).json ({ msg: «unauthorized» })

}

try {

const updated = await updateSnippet (

id,

code,

language,

description,

name

)

return res.status (200).json (updated)

}

catch (error) {

console.log (error)

res.status (500).json ({ msg: «unauthorized» })

}

}

Связывание нашей кнопки редактирования

Теперь перейдите к Snippetsкомпоненту и измените этот компонент, чтобы использовать эту функцию. Сначала мы импортируем Linkмодуль:

...

import Link from «next/link»

Мы также модифицируем нашу editкнопку:

Edit

+ <Link href={`/edit/${snippet.id}`}>

+ Edit

+

Обработка фрагмента редактирования

При клике отправляет запрос на страницу editс idвыбранным сниппетом. В pagesпапке создайте папку editс именем файла [id].jsвнутри нее:

import { getSnippetById } from «.../... /Fauna»

import Upload from «.../upload»

export default function Home ({ snippet }) {

const email = «»

const user = «»

return (

 

 

Update a snippet

 

 

)

}

export async function getServerSideProps (context) {

try {

//get and update record

const id = context.params.id

}

catch (error) {

console.log (error)

context.res.statusCode = 302

context.res.setHeader («Location», «/»)

return {props: {}}

}

}

В [id].js, мы передаем фрагмент кода propsна страницу загрузки фрагмента. Однако на этот раз страница загрузки будет содержать данные, хранящиеся во фрагменте кода, на который ссылается файл id. Чтобы получить сниппет по ID, нам нужно создать в файле getSnippetByIdфункцию: Fauna.js

const getSnippetById = async (id) => {

const snippet = await faunaClient.query (q.Get (q.Ref (q.Collection («codesnippet»), id)))

snippet.id = snippet.ref.id

delete snippet.ref

return snippet

}

module.exports = {

getResponse,

createSnippet,

updateSnippet,

getSnippetById,

}

Когда мы экспортируем функцию обратно в [id].jsфайл, мы можем использовать ее для получения определенного фрагмента с его идентификатором:

try {

const id = context.params.id;

const snippet = await getSnippetById (id) ;

return {

props: { snippet },

};

} catch (error) {

// as before

}

Изменение сохраненных фрагментов

Теперь в upload.jsфайле мы изменим его, чтобы иметь доступ к сохраненным данным, если фрагмент нужно отредактировать:

— const { register, handleSubmit, errors, reset } = useForm ()

+ const { register, handleSubmit, errors, reset } = useForm ({

+ defaultValues: {

+ code: snippet? snippet.data.code: «»,

+ language: snippet? snippet.data.language: «»,

+ description: snippet? snippet.data.description: «»,

+ name: snippet? snippet.data.name: «»,

+ }

+ })

Приведенный выше код проверяет, хранит ли сниппет данные. Если он возвращает true, он возвращает данные в параметры: code, language, descriptionи code. Если он возвращает false, он возвращает пустую строку.

Далее мы создадим функцию для обновления фрагмента кода:

const createSnippet = async (data) => {... }

const updateSnippet = async (data) => {

const { code, language, description, name } = data

const id = snippet.id

try {

await fetch («/api/updateSnippet», {

method: «PUT»,

body: JSON.stringify ({ code, language, description, name, id }),

headers: {

«Content-Type»: «application/json»,

},

})

router.push («/»)

}

catch (error) {

console.log (error)

}

}

return (,)

Тестирование функциональности фрагмента редактирования

Если мы запустим наш код, мы сможем отредактировать ранее созданные фрагменты кода, нажав кнопку «Редактировать «, внеся изменения в данные в форме и нажав «Отправить «.

Добавление функции удаления фрагмента

Теперь, если мы вернемся к Homeкомпоненту в нашем браузере, мы сможем редактировать и обновлять фрагменты кода. Наконец-то мы можем добавить финальную функциональность для удаления нашего фрагмента кода. Создайте и экспортируйте новую функцию — deleteSnippet— в Fauna.jsфайл:

const deleteSnippet = async (id) => {

return await faunaClient.query (q.Delete (q.Ref (q.Collection («codesnippet»), id)))

}

module.exports = {

...

deleteSnippet,

}

Создание конечной точки API для функции удаления

Мы создадим еще одну конечную точку для этой функции в нашей apiпапке с именем deleteSnippet.jsи заполним ее следующим кодом:

import { deleteSnippet } from «.../... /Fauna»

export default async function handler (req, res) {

if (req.method≠= «DELETE») {

return res.status (405).json ({ msg: «unauthorized» })

}

const { id } = req.body

try {

const deleted = await deleteSnippet (id)

return res.status (200).json (deleted)

}

catch (error) {

console.log (error)

res.status (500).join ({ msg: «error occured» })

}

}

Затем мы модифицируем Snippets.jsфайл, чтобы добавить новую функциональность:

function Snippets ({ snippet, snippetDeleted }) {

...

}

Затем создайте deleteSnippetфункцию для извлечения конечной точки из apiи удаления фрагмента, на который ссылается идентификатор:

function Snippets ({snippet, snippetDeleted}) {

const deleteSnippet = async () => {

try {

await fetch («/api/deleteSnippet», {

method: «DELETE»,

body: JSON.stringify ({ id: snippet.id }),

headers: {

«Content-Type»: «application/json»,

},

}) ;

snippetDeleted () ;

} catch (e) {

console.log (e) ;

}

};

return (

 

 

 

{snippet.data.language}

{snippet.data.name}

 

{snippet.data.description}

 

 

 

<Link href={`/edit/${snippet.id}`}>

Edit

 

Delete

 

 

 

 

)

}

Мы также обновили элемент привязки, чтобы он вызывал deleteSnippetфункцию при нажатии.

Тестирование функции удаления

Мы добавили функцию удаления фрагментов кода. Теперь мы можем удалить фрагменты, нажав кнопку «Удалить «в нашем приложении.

На этом функции приложения фрагмента заканчиваются. Теперь мы приступим к добавлению мер аутентификации в наше приложение, чтобы только авторизованные пользователи могли создавать или изменять фрагменты в нашем приложении.

Аутентификация пользователя

Зачем нам нужна аутентификация? В настоящее время пользователи могут создавать фрагменты, но они также могут удалять и изменять фрагменты, которые они не создавали. Нам нужно будет предоставить средства для авторизации пользователей для доступа к нашему сайту — и, следовательно, потребность в аутентификации пользователей.

Мы установим next-auth для аутентификации через наш CLI:

npm i next-auth

Мы будем использовать токен JWT для аутентификации. JWT — это стандарт, используемый для создания токенов доступа для приложения.

Создайте папку с именем authв вашей apiпапке и внутри нее создайте файл [...nextauth].jsсо следующим кодом:

import NextAuth from «next-auth»

import GoogleProvider from «next-auth/providers/google»

export default NextAuth ({

providers: [

GoogleProvider ({

clientId: process.env.GOOGLE_CLIENT_ID,

clientSecret: process.env.GOOGLE_CLIENT_SECRET,

authorizationUrl: «https: //accounts.google.com/o/oauth2/v2/auth? prompt=consent&access_type=offline&response_type=code»,

})

],

jwt: {

encryption: true

},

secret: process.env.secret,

callbacks: {

async jwt (token, account) {

if (account?.accessToken) {

token.accessToken = account.accessToken

}

return token

},

redirect: async (url, _baseUrl)=>{

if (url === «/profile») {

return Promise.resolve («/»)

}

return Promise.resolve («/»)

}

}

})

После этого мы завернем наши компоненты в _app.jsфайл:

import '.../styles/globals.css’

import {Provider} from «next-auth/client»

function MyApp ({ Component, pageProps }) {

return (

 

)

}

export default MyApp

Обработка аутентификации

Мы изменим наш Homeкомпонент index.js, чтобы вернуться к нашему компоненту, если пользователь аутентифицирован, в противном случае он возвращает кнопку, ведущую на страницу аутентификации:

import {signIn, signOut, useSession} from «next-auth/client»

...

Затем внутри Home:

export default function Home () {

const { data: snippets, mutate }=useSWR («api/snippets»)

const [session, loadingSession] = useSession ()

if (loadingSession) {

<>

...authenticating

</>

}

...

}

Приведенный выше код проверяет, является ли приложение loadingSession. Если это правда, он возвращает pблок тегов, иначе он возвращает остальную часть нашего приложения, если есть session. Далее мы отобразим «вход», если сеанса нет:

return (

 

 

 

...

{! session && (

<>

Sign in to access snippet app

</>

) }

{session && (

<>

 

 

welcome {session.user.email}

...

 

 

</>

) }

 

 

)

Чтобы использовать «службу входа в Google», нам нужны учетные данные для доступа из облачной консоли Google. Для этого войдите в свою учетную запись Google и перейдите в консоль Google Cloud. Нажмите «СОЗДАТЬ ПРОЕКТ «на странице, введите название своего проекта и нажмите «Создать «.

На открывшейся новой странице нажмите + CREATE CREDENTIALS в верхней строке меню и, наконец, выберите идентификатор клиента OAuth в раскрывающемся меню.

Облачная консоль Google

На открывшейся странице вы получите уведомление с кнопкой «Настроить экран согласия». Нажмите на эту кнопку.

На следующей странице выберите «Внешний «под типом пользователя и нажмите «Создать «. Введите необходимые поля для «Имя приложения» и «Электронная почта» и нажмите «Сохранить и продолжить «.

В разделах Scopes и Test users прокрутите вниз и нажмите Save and Continue.

Наконец, нажмите «Вернуться к панели инструментов «и нажмите кнопку «Опубликовать «.

Теперь мы можем создать наш ключ, нажав «Учетные данные «в боковом меню, а затем «Создать учетные данные «в верхней строке меню. Выберите идентификатор клиента Oauth в раскрывающемся списке, и вы получите страницу с запросом типа приложения.

Выберите «Веб-приложение «, затем в разделе «Авторизованные источники JavaScript» нажмите «Добавить URI «и введите http: //localhost. Наконец, в разделе «Авторизованные URI перенаправления» нажмите «Добавить URI «и введите http: //localhost/api/auth/callback/googleв поле, прежде чем нажать «Создать «.

Создание ключа Oauth

Скопируйте идентификатор клиента и секрет клиента из открывшегося всплывающего окна и добавьте их в.envфайл:

GOOGLE_CLIENT_ID=id

GOOGLE_CLIENT_SECRET=secret

Теперь мы можем войти в наше приложение, используя аутентификацию Google. Кроме того, мы настроим наш upload.jsфайл как защищенный маршрут, чтобы неавторизованные пользователи не могли создавать новые фрагменты:

import { getSession } from «next-auth/client»

function Upload ({ snippet, user }) {... }

export async function getServerSideProps (context) {

const session = await getSession (context)

if (! session) {

context.res.writeHead (302, { Location: «/» })

context.res.end ()

return {}

}

return {

props: {

user: session.user,

}

}

}

export default Upload;

Тестирование аутентификации пользователя

Если мы запустим наше приложение с помощью npm run devкоманды, сначала мы получим страницу с просьбой «войти в систему». Мы не можем перейти на страницу загрузки по /uploadпути в нашем URL. Мы можем получить доступ к нашему приложению только тогда, когда мы используем функцию входа в Google для входа в наше приложение.

Авторизация пользователей для создания фрагмента

Наконец, мы изменим createSnippetфункциональность, чтобы добавить адрес электронной почты пользователя в базу данных, а затем мы покажем кнопки «Изменить «и «Удалить «, только если адрес электронной почты соответствует.

В Fauna.jsизмените createSnippetфункцию следующим образом:

const createSnippet = async (code, language, description, name, mail) => {

return await faunaClient.query (q.Create (q.Collection («codesnippet»), {

data: {code, language, description, name, mail}

}))

}

В createSnippet.jsфайле внесите следующие изменения:

— const { code, language, description, name } = req.body;

+ const { code, language, description, name, mail } = req.body;

— const createdSnippet = await createSnippet (code, language, description, name) ;

+ const createdSnippet = await createSnippet (code, language, description, name, mail) ;

В upload.js:

function upload ({ snippet, user }) {

+ const email = user.email;

...

}

И измените createSnippetфункцию и updateSnippetфункцию следующим образом:

const createSnippet = async (data) => {

const { code, language, description, name, mail } = data;

console.log (data)

try {

await fetch («/api/createSnippet», {

method: «POST»,

body: JSON.stringify ({ code, language, description, name, mail: email }),

headers: {

«Content-type»: «application/json»

},

})

router.push («/»)

} catch (error) {

console.log (error)

}

}

const updateSnippet = async (data) => {

const { code, language, description, name } = data

const id = snippet.id

try {

await fetch («/api/updateSnippet», {

method: «PUT»,

body: JSON.stringify ({ code, language, description, name, mail: email }),

headers: {

«Content-Type»: «application/json»,

},

})

router.push («/»)

}

catch (error) {

console.log (error)

}

}

Теперь мы можем приступить к отображению кнопок «Изменить «и «Удалить «, только если адрес электронной почты соответствует.

Во-первых, мы передаем user.mailas props Snippetкомпоненту в index.js:

<Snippets

key={snippet.id}

snippet={snippet}

snippetDeleted={mutate}

+ email={session.user.email}

/>

Затем в Snippet.js:

function Snippets ({ snippet, snippetDeleted, email }) {

...

{email == snippet.data.mail && (

<>

 

 

<Link href={`/edit/${snippet.id}`}>

Edit

 

Delete

 

 

</>

) }

...

}

Тестирование нашего приложения

Запустите npm run devв CLI и откройте приложение в браузере. Теперь, если вы создадите новый фрагмент, адрес электронной почты пользователя будет добавлен в базу данных. Если адрес электронной почты не соответствует, кнопки «Изменить «и «Удалить «не отображаются на странице отображения фрагмента. Вы можете проверить это, войдя в систему с адресом электронной почты, отличным от того, который использовался для создания фрагментов кода.

Заключение

Наконец-то мы подошли к концу этого урока. Мы узнали, как создать приложение CRUD с помощью Next.js и FaunaDB и как выполнять операции CRUD на основе аутентификации пользователя.

Чтобы ознакомиться с полным кодом, посетите репозиторий GitHub.

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая