Выполните форк этого репозитория для выполнения домашних заданий (2-6) Форк создаст репозиторий на вашем http://github.com
Добавьте ментора в коллаборацию
Для каждой домашней работы создавайте свою ветку.
- hw02
- hw03
- hw04
- hw05
- hw06
Каждая новая ветка для дз должна делаться с master
После того как вы закончили выполнять домашнее задание в своей ветке, необходимо сделать пулл-реквест (PR). Потом добавить ментора для ревью кода. Только после того как ментор заапрувит PR, вы можете выполнить мердж ветки с домашним заданием в мастер.
Внимательно читайте комментарии ментора. Исправьте замечания и сделайте коммит в ветке с домашним заданием. Изменения подтянуться в PR автоматически после того как вы отправите коммит с исправлениями на github После исправления снова добавьте ментора на ревью кода.
- При сдаче домашней работы есть ссылка на PR
- JS-код чистый и понятный, для форматирования используется Prettier
npm start
— старт сервера в режиме productionnpm run start:dev
— старт сервера в режиме разработки (development)npm run lint
— запустить выполнение проверки кода с eslint, необходимо выполнять перед каждым PR и исправлять все ошибки линтераnpm lint:fix
— та же проверка линтера, но с автоматическими исправлениями простых ошибок
Создай форк репозитория в свой github аккаунт.
Посмотри поясняющее видео как это сделать и сдавать ДЗ правильно.
Написать REST API для работы с коллекцией контактов. Для работы с REST API используй Postman.
Прочитай внимательно readme в клонированном бойлерплейте, там описан механизм сдачи домашних заданий. Приступай к выполнению ДЗ
Создай ветку hw02-express
из ветки master.
Установи модули командой:
npm i
Следующие модули уже есть в проекте:
В app.js – веб сервер на express, добавлены прослойки morgan
и cors
. Начни настраивать раутинг для работы с коллекцией контактов.
REST API должен поддерживать следующие рауты.
- ничего не получает
- вызывает функцию
listContacts
для работы с json-файломcontacts.json
- возвращает массив всех контактов в json-формате со статусом
200
- Не получает
body
- Получает параметр
id
- вызывает функцию getById для работы с json-файлом contacts.json
- если такой id есть, возвращает объект контакта в json-формате со статусом
200
- если такого id нет, возвращает json с ключом
"message": "Not found"
и статусом404
- Получает
body
в формате{name, email, phone}
(все поля обязательны) - Если в body нет каких-то обязательных полей, возвращает json с ключом
{"message": "missing required name field"}
и статусом400
- Если с
body
все хорошо, добавляет уникальный идентификатор в объект контакта - Вызывает функцию
addContact(body)
для сохранения контакта в файлеcontacts.json
- По результату работы функции возвращает объект с добавленным
id
{id, name, email, phone}
и статусом201
- Не получает
body
- Получает параметр
id
- вызывает функцию
removeContact
для работы с json-файломcontacts.json
- если такой
id
есть, возвращает json формата{"message": "contact deleted"}
и статусом200
- если такого
id
нет, возвращает json с ключом"message": "Not found"
и статусом404
- Получает параметр
id
- Получает
body
в json-формате c обновлением любых полейname, email и phone
- Если
body
нет, возвращает json с ключом{"message": "missing fields"}
и статусом400
- Если с
body
все хорошо, вызывает функциюupdateContact(contactId, body)
(напиши ее) для обновления контакта в файлеcontacts.json
- По результату работы функции возвращает обновленный объект контакта и статусом
200
. В противном случае, возвращает json с ключом"message": "Not found"
и статусом404
Для маршрутов, что принимают данные (POST
, PUT
, PATCH
), продумайте проверку (валидацию) принимаемых данных. Для валидации принимаемых данных используйте пакет joi
- Создан репозиторий с домашним заданием — REST API приложение
- При создании репозитория использован бойлерплейт
- Пулл-реквест (PR) с соответствующим дз отправлен ментору в schoology на проверку (ссылка на PR)
- Код соответствует техническому заданию проекта
- При выполнении кода не возникает необработанных ошибок
- Название переменных, свойств и методов начинается со строчной буквы и записываются в нотации CamelCase. Используются английские существительные
- Название функции или метода содержит глагол
- В коде нет закомментированных участков кода
- Проект корректно работает в актуальной LTS-версии Node
Создай ветку hw03-mongodb
из ветки master
.
Продолжи создание REST API для работы с коллекцией контактов.
Создай аккаунт на MongoDB Atlas. После чего в аккаунте создай новый проект и настрой бесплатный кластер. Во время настройки кластера выбери провайдера и регион как на скриншоте ниже. Если выбрать слишком удаленный регион, скорость ответа сервера будет дольше.
Установи графический редактор MongoDB Compass для удобной работы с базой данных для MongoDB. Настрой подключение своей облачной базы данных к Compass. В MongoDB Atlas не забудь создать пользователя с правами администратора.
Через Compass создай базу данных db-contacts
и в ней коллекцию contacts
. Возьми ссылка на json и при помощи Compass наполни коллекцию contacts
(сделай импорт) его содержимым.
Если вы все сделали правильно, данные должны появиться в вашей базе в коллекции contacts
Используйте исходный код домашней работы #2 и замените хранение контактов из json-файла на созданную вами базу данных.
- Напишите код для создания подключения к MongoDB при помощи Mongoose.
- При успешном подключении выведите в консоль сообщение
"Database connection successful"
. - Обязательно обработайте ошибку подключения. Выведите в консоль сообщение ошибки и завершите процесс используя
process.exit(1)
. - В функциях обработки запросов замените код CRUD-операций над контактами из файла, на Mongoose-методы для работы с коллекцией контактов в базе данных.
Схема модели для коллекции contacts
:
{
name: {
type: String,
required: [true, 'Set name for contact'],
},
email: {
type: String,
},
phone: {
type: String,
},
favorite: {
type: Boolean,
default: false,
},
}
У нас появилось в контактах дополнительное поле статуса favorite
, которое принимает логическое значение true
или false
. Оно отвечает за то, что в избранном или нет находится указанный контакт. Реализуй для обновления статуса контакта новый маршрут
- Получает параметр
contactId
- Получает
body
в json-формате c обновлением поляfavorite
- Если
body
нет, возвращает json с ключом{"message": "missing field favorite"}
и статусом400
- Если с
body
все хорошо, вызывает функциюupdateStatusContact(contactId, body)
(напиши ее) для обновления контакта в базе - По результату работы функции возвращает обновленный объект контакта и статусом
200
. В противном случае, возвращает json с ключом"message": "Not found"
и статусом404
Для роута POST /api/contacts
внесите изменения: если поле favorite
не указали в body
, то при сохранении в базу нового контакта, сделайте поле favorite
равным по умолчанию false
. Не забываем про валидацию данных!
Создайте ветку hw04-auth
из ветки master
.
Продолжите создание REST API для работы с коллекцией контактов. Добавьте логику аутентификации/авторизации пользователя с помощью JWT.
В коде создайте схему и модель пользователя для коллекции users
.
{
password: {
type: String,
required: [true, 'Password is required'],
},
email: {
type: String,
required: [true, 'Email is required'],
unique: true,
},
subscription: {
type: String,
enum: ["starter", "pro", "business"],
default: "starter"
},
token: {
type: String,
default: null,
},
}
Чтобы каждый пользователь работал и видел только свои контакты в схеме контактов добавьте свойство owner
owner: {
type: SchemaTypes.ObjectId,
ref: 'user',
}
Примечание: 'user'
- название коллекции (в единственном числе), в которой хранятся пользователи.
Создайте эндпоинт /users/signup
Сделать валидацию всех обязательных полей (email
и password
). При ошибке валидации вернуть
Ошибку валидации.
В случае успешной валидации в модели User
создать пользователя по данным которые прошли валидацию. Для засолки паролей используй bcrypt или bcryptjs
- Если почта уже используется кем-то другим, вернуть Ошибку Conflict.
- В противном случае вернуть Успешный ответ.
POST /users/signup
Content-Type: application/json
RequestBody: {
"email": "example@example.com",
"password": "examplepassword"
}
Status: 400 Bad Request
Content-Type: application/json
ResponseBody: <Ошибка от Joi или другой библиотеки валидации>
Status: 409 Conflict
Content-Type: application/json
ResponseBody: {
"message": "Email in use"
}
Status: 201 Created
Content-Type: application/json
ResponseBody: {
"user": {
"email": "example@example.com",
"subscription": "starter"
}
}
Создайте эндпоинт /users/login
В модели User
найти пользователя по email
.
Сделать валидацию всех обязательных полей (email
и password
). При ошибке валидации вернуть Ошибку валидации.
- В противном случае, сравнить пароль для найденного юзера, если пароли совпадают создать токен, сохранить в текущем юзере и вернуть Успешный ответ.
- Если пароль или email неверный, вернуть Ошибку Unauthorized.
POST /users/login
Content-Type: application/json
RequestBody: {
"email": "example@example.com",
"password": "examplepassword"
}
Status: 400 Bad Request
Content-Type: application/json
ResponseBody: <Ошибка от Joi или другой библиотеки валидации>
Status: 200 OK
Content-Type: application/json
ResponseBody: {
"token": "exampletoken",
"user": {
"email": "example@example.com",
"subscription": "starter"
}
}
Status: 401 Unauthorized
ResponseBody: {
"message": "Email or password is wrong"
}
Создайте мидлвар для проверки токена и добавь его ко всем маршрутам, которые должны быть защищены.
- Мидлвар берет токен из заголовков
Authorization
, проверяет токен на валидность. - В случае ошибки вернуть Ошибку Unauthorized.
- Если валидация прошла успешно, получить из токена
id
пользователя. Найти пользователя в базе данных по этому id. - Если пользователь существует и токен совпадает с тем, что находится в базе, записать его данные в
req.user
и вызвать методnext()
. - Если пользователя с таким
id
не существует или токены не совпадают, вернуть Ошибку Unauthorized
Status: 401 Unauthorized
Content-Type: application/json
ResponseBody: {
"message": "Not authorized"
}
Создайте ендпоинт /users/logout
Добавьте в маршрут мидлвар проверки токена.
- В модели
User
найти пользователя по_id
. - Если пользователя не существует вернуть Ошибку Unauthorized.
- В противном случае, удалить токен в текущем юзере и вернуть Успешный ответ.
GET /users/logout
Authorization: "Bearer {{token}}"
Status: 401 Unauthorized
Content-Type: application/json
ResponseBody: {
"message": "Not authorized"
}
Status: 204 No Content
Создайте эндпоинт /users/current
Добавьте в маршрут мидлвар проверки токена.
- Если пользователя не существует вернуть Ошибку Unauthorized
- В противном случае вернуть Успешный ответ
GET /users/current
Authorization: "Bearer {{token}}"
Status: 401 Unauthorized
Content-Type: application/json
ResponseBody: {
"message": "Not authorized"
}
Status: 200 OK
Content-Type: application/json
ResponseBody: {
"email": "example@example.com",
"subscription": "starter"
}
- Сделать пагинацию для коллекции контактов (GET /contacts?page=1&limit=20).
- Сделать фильтрацию контактов по полю избранного (GET /contacts?favorite=true)
- Обновление подписки (
subscription
) пользователя через эндпоинтPATCH
/users
. Подписка должна иметь одно из следующих значений['starter', 'pro', 'business']
Создай ветку hw05-avatars
из ветки master
.
Продолжи создание REST API для работы с коллекцией контактов. Добавь возможность загрузки аватарки пользователя через Multer.
Создай папку public
для раздачи статики. В этой папке сделай папку avatars
. Настрой Express на раздачу статических файлов из папки public
.
Положи любое изображение в папку public/avatars
и проверь что раздача статики работает. При переходе по такому URL браузер отобразит изображение.
http://localhost:<порт>/avatars/<имя файла с расширением>
В схему пользователя добавь новое свойство avatarURL
для хранения изображения.
{
...
avatarURL: String,
...
}
- Используй пакет gravatar для того чтобы при регистрации нового пользователя сразу сгенерить ему аватар по его
email
.
При регистрации пользователя:
- Создавай ссылку на аватарку пользователя с помощью gravatar
- Полученный URL сохрани в поле
avatarURL
во время создания пользователя
Добавь возможность обновления аватарки, создав эндпоинт /users/avatars
и используя метод PATCH
.
# Запрос
PATCH /users/avatars
Content-Type: multipart/form-data
Authorization: "Bearer {{token}}"
RequestBody: загруженный файл
# Успешный ответ
Status: 200 OK
Content-Type: application/json
ResponseBody: {
"avatarURL": "тут будет ссылка на изображение"
}
# Неуспешный ответ
Status: 401 Unauthorized
Content-Type: application/json
ResponseBody: {
"message": "Not authorized"
}
- Создай папку tmp в корне проекта и сохраняй в неё загруженную аватарку.
- Обработай аватарку пакетом jimp и задай для нее размеры 250 на 250
- Перенеси аватарку пользователя из папки tmp в папку
public/avatars
и дай ей уникальное имя для конкретного пользователя. - Полученный
URL
/avatars/<имя файла с расширением>
сохрани в полеavatarURL
пользователя
При помощи Jest
- ответ должен иметь статус-код 200
- в ответе должен возвращаться токен
- в ответе должен возвращаться объект
user
с 2 полямиemail
иsubscription
, имеющие тип данныхString
Создай ветку hw06-email
из ветки master
.
Продолжаем создание REST API для работы с коллекцией контактов. Добавьте верификацию email пользователя после регистрации при помощи сервиса SendGrid.
- После регистрации, пользователь должен получить письмо на указанную при регистрации почту с ссылкой для верификации своего email
- Пройдя ссылке в полученном письме, в первый раз, пользователь должен получить Ответ со статусом 200, что будет подразумевать успешную верификацию email
- Пройдя по ссылке повторно пользователь должен получить Ошибку со статусом 404
- Зарегистрируйся на SendGrid.
- Создай email-отправителя. Для это в административной панели SendGrid зайдите в меню Marketing в подменю senders и в правом верхнем углу нажмите кнопку "Create New Sender". Заполните необходимые поля в предложенной форме. Сохраните. Должен получится следующий как на картинке результат, только с вашим email:
На указанный email должно прийти письмо верификации (проверьте спам если не видите письма). Кликните на ссылку в нем и завершите процесс. Результат должен изменится на:
- Теперь необходимо создать API токен доступа. Выбираем меню "Email API", и подменю "Integration Guide". Здесь выбираем "Web API"
Дальше необходимо выбрать технологию Node.js
На третьем шаге даем имя нашему токену. Например systemcats, нажимаем кнопку сгенерировать и получаем результат как на скриншоте ниже. Необходимо скопировать этот токен (это важно, так как больше вы не сможете его посмотреть). После завершить процесс создания токена
- Полученный API-токен надо добавить в
.env
файл в нашем проекте
- добавить в модель
User
два поляverificationToken
иverify
. Значение поляverify
равноеfalse
будет означать, что его email еще не прошел верификацию
{
verify: {
type: Boolean,
default: false,
},
verificationToken: {
type: String,
required: [true, 'Verify token is required'],
},
}
- создать эндпоинт GET
/users/verify/:verificationToken
, где по параметруverificationToken
мы будем искать пользователя в моделиUser
- если пользователь с таким токеном не найден, необходимо вернуть Ошибку 'Not Found'
- если пользователь найден - устанавливаем
verificationToken
вnull
, а полеverify
ставим равнымtrue
в документе пользователя и возвращаем Успешный ответ
GET /auth/verify/:verificationToken
Status: 404 Not Found
ResponseBody: {
message: 'User not found'
}
Status: 200 OK
ResponseBody: {
message: 'Verification successful',
}
При создания пользователя при регистрации:
- создать
verificationToken
для пользователя и записать его в БД (для генерации токена используйте пакет uuid или nanoid) - отправить email на почту пользователя и указать ссылку для верификации email'а (
/users/verify/:verificationToken
) в сообщении - Так же необходимо учитывать, что теперь логин пользователя не разрешен при не верифицированном email
Необходимо предусмотреть, вариант, что пользователь может случайно удалить письмо. Оно может не дойти по какой-то причине к адресату. Наш сервис отправки писем во время регистрации выдал ошибку и т.д.
- Получает
body
в формате{ email }
- Если в
body
нет обязательного поляemail
, возвращает json с ключом{"message": "missing required field email"}
и статусом400
- Если с
body
все хорошо, выполняем повторную отправку письма сverificationToken
на указанный email, но только если пользователь не верифицирован - Если пользователь уже прошел верификацию отправить json с ключом
{ message: "Verification has already been passed"}
со статусом400 Bad Request
POST /users/verify
Content-Type: application/json
RequestBody: {
"email": "example@example.com"
}
Status: 400 Bad Request
Content-Type: application/json
ResponseBody: <Ошибка от Joi или другой библиотеки валидации>
Status: 200 Ok
Content-Type: application/json
ResponseBody: {
"message": "Verification email sent"
}
Status: 400 Bad Request
Content-Type: application/json
ResponseBody: {
message: "Verification has already been passed"
}
Примечание: Как альтернативу SendGrid можно использовать пакет nodemailer