Backend-разработка

Присоединяйтесь к нашей программе обучения

Задание 4: веб-сервер

Нужно создать новостной веб-сервер с REST API, который принимает HTTP-запросы и отдает ответы в формате JSON. Можно представить, что это сервер для мобильного приложения.

Функциональные требования

Сущности

  • Пользователи

    • Имя

    • Логин

    • Пароль

    • Дата создания

    • Админ (булевая переменная)

    • Может ли создавать новости (булева переменная)

  • Категории (могут быть вложенными, то есть одна категория является подкатегорией для другой). Допустим, есть категория "Языки программирования", и у нее может быть подкатегория "Динамически Типизированные ЯП", и далее, соответственно, подкатегория подкатегории "Python" — и таких уровней вложенности может быть произвольное количество.

  • Новости

    • Краткое название

    • Дата создания

    • Один пользователь (создатель)

    • Одна категория

    • Текстовый контент

    • Любое количество фотографий, от нуля

    • Опубликована ли новость (булева переменная)

API

  • Когда по API запрашиваем новости, в каждой новости должны быть вложены все сущности (автор, категория (рекурсивно) и т.д.), за исключением картинок: в ответе нужно вернуть их URI.

  • API новостей должно поддерживать фильтрацию. Фильтрация определяется параметрами в URI query (см. примеры ниже). Клиент может использовать сразу несколько фильтров по разным полям, и тогда они объединяются при помощи логического "И". Например, фильтр /news?created_at=2011-01-01&author=Ivan выдает новости, созданные 1 января 2011 г. пользователем по имени Ivan. Поддерживаются фильтры для полей:

    • День создания (созданные до даты, созданные с даты, созданные в указанный день)

    • Примеры (можно выбрать другие названия):

      • /news?created_at=2018-05-21

      • /news?created_until=2018-05-21

      • /news?created_since=2018-05-21

    • Имя пользователя-автора

    • Категория по айди

    • Название (вхождение подстроки)

    • Контент (вхождение подстроки)

  • API новостей должно поддерживать поиск по строке, которая может быть найдена либо в текстовом контенте, либо в имени автора, либо в названии категории.

  • API новостей должно поддерживать сортировку отдельным параметром URI query. Клиент может использовать сортировку вместе с любым набором фильтров.(Пример: /news?sort_by=category.) Критерии сортировки:

    • Дата

    • Автор (имя по алфавиту)

    • Категория (название по алфавиту)

    • Количество фотографий

  • Должны быть отдельные эндпойнты для сущностей:

    • Категории:

      • Создание только для админов

      • Получение списка для всех

      • Редактирование только для админов (редактирование названия и смена родительской категории)

    • Новости:

      • Создание для юзеров, имеющих право создания новостей

      • Получение списка всем. Опубликованные новости видят все, а неопубликованные - только их автор

      • Редактирование только автору новости. Редактироваться могут и опубликованные, и неопубликованные новости

    • Пользователи:

      • создание только для админов

      • получение списка всем

    • Картинки:

      • получение одной картинки.

  • Запросы на редактирование должны поддерживать редактирование любого количества полей сущности, вплоть до сразу всех.

  • Доступно только админам. При запросе не-админам возвращать 404, а не 403.

  • Запросы по всем остальным URL должны возвращать 404.

  • Для аутентификации рекомендуем использовать basic auth как самый простой вариант. Аутентификацию не надо проверять в эндпойнтах, которые доступны всем.

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

    • сервер никогда не выдает в ответе больше N элементов (т.е. новостей в запросе новостей, юзеров в запросе юзеров и т.п.). Значение N должно быть задано в одном месте (в коде или в конфиге), а не скопировано в разные места кода, чтобы ее можно было изменить правкой единственной строчки.

    • клиент может указать, сколько элементов он хочет получить и начиная с какого по счету элемента. Пример для новостей: /news?offset=15&limit=20 - вернуть 20 новостей, пропустив 15 штук от начала списка (названия параметров даны только для примера). Клиент может не указывать любой параметр или даже оба:

      • если limit опущен, подразумевается N

      • а если offset опущен, подразумевается 0.

    • если клиент запросил значение limit большее, чем N, он все равно получает не более N элементов.

    • пагинацию реализуйте ключевыми словами LIMIT и OFFSET в соответствующих SQL-запросах.

  • Сервер никогда не возвращает пароль пользователя.

  • В БД нужно хранить хеши паролей, а не сами пароли. Можно (но совсем необязательно) сделать сложнее и правильнее: использовать хеширование c солью, например, при помощи случайно сгенерированной соли и PBKDF2 (см. модуль Crypto.KDF.PBKDF2 в библиотеке cryptonite).

  • В ответе на запрос картинки должен быть правильный заголовок Content-Type, например, Content-Type: image/png. Как его узнать? Можно его передавать в запросе, который создает картинку.

  • Для создания картинки достаточно передать ее содержимое, закодированное в base64, в запросе на создание или редактирование новости. Но при желании вы можете передать картинку в запросе типа multipart/form-data.

Технические требования

  • В качестве веб-сервера под капотом использовать Warp Обязательно прочесть описание, как он работает:http://www.aosabook.org/en/posa/warp.html. В целом эту книгу (AOSA Book) очень рекомендуем, там огромное количество инсайтов по многим крутым опенсорсным проектам. Чтобы использовать Warp, необходимо понимать WAI, так что еще по нему прочитать — https://www.yesodweb.com/book/web-application-interface.

  • В качестве базы использовать PostgreSQL

  • Рекомендуемые библиотеки:

    • cryptonite для хеширования паролей

    • warp, wai и servant как основа для веб-сервера

    • библиотека для работы с PostgreSQL, любая, на выбор:

      • попроще: postgresql-simple, hasql

      • дольше изучать, но более безопасные в плане типов и чаще применяемые на практике: beam, pesistent + esqueleto

    • библиотека для чтения конфига: любая, например, aeson, yaml, configurator, dhall

    • вероятно, вам понадобится text, bytestring, http-types, network-uri, containers, unordeded-containers, base64, base64-bytestring, vector, array и другие библиотеки из Haskell Platform. В целом можно использовать почти все подобные простые библиотеки. Библиотека должна решать одну задачу, а не вести себя как фреймворк, т.е. не работать одновременно с базой и вебом. Если у вас есть сомнения, можно ли использовать библиотеку, спросите в чате.

  • Для работы с базой можно использовать любые библиотеки, главное — самим создавать и поддерживать миграции. В идеале, в готовом проекте по миграциям должна прослеживаться история изменения таблиц в процессе разработки - то есть дожна быть не только инициализирующая миграция (разве что вы сразу всё красиво спроектировали:)), но и миграции для добавления новых таблиц, изменения названий и типов полей и т.д. Миграции — код, который задает структуру базе (то есть создание таблиц, изменение, переименование, удаление полей и тд). Обязательно держите в голове, что после того, как проект выпускается в продакшен, база на проде заполняется данными, которые ни в коем случае нельзя потерять. Но требование менять структуру базы регулярно появляется за время развития проекта, и надо уметь развивать базу без потери данных. Для этого нужно как можно тщательней формализовать все изменения, которые вы проводите над базой от версии к версии.

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

  • В отдельной папке проекта сделать sh-скрипты со всеми возможными CURL-запросами, чтобы мы могли быстро склонировать проект и потестить его. Сделать по sh-файлу на каждый CURL-запрос.

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

Источники

Lessons learned while writing a Haskell application — не всем рекомендациям отсюда мы бы советовали следовать, но почитать про релевантный опыт автора статьи будет однозначно полезно.

Список библиотек Haskell Platform

Haskell Platform считается устаревшей и ее больше нельзя скачать, поэтому здесь мы приводим список ее пакетов. Все они достаточно важные и часто используемые, их можно использовать в тестовых проектах, если в задании не сказано обратное.

менеджер программы обучения

По любым вопросам по программе обучения пишите Светлане в Telegram