Русский
Русский
English
Статистика
Реклама

Изучаю Scala Часть 2 Todo лист с возможностью загрузки картинок


Привет Хабр! Следующих этап изучения нового языка это старый добрый todo list только не простой а с загрузкой и скачиванием картинок чтобы научится работе с базой данных и файловой системой. За подробностями добро пожаловать под кат.

Содержание




Ссылки


Исходники
Образы docker image

API


Описание апи в swagger и эндпойнты я сделал с помощью Tapir. Он позволяет своим DSL описать API которое мы хотим реализовать.
  def withStatus[A](f: IO[A]): IO[Either[(StatusCode, String), A]] =    f.attempt.map(x => x match {      case Right(value) => Right(value)      case Left(value) => Left(StatusCode.InternalServerError, value.getMessage)    })val baseEndpoint = endpoint    .in("api" / "v1")    .errorOut(statusCode.and(stringBody))private val baseImageEndpoint = baseEndpoint    .in("images")    .tag("Images")  private val download = baseImageEndpoint    .summary("Скачать картинку")    .description("Скачивает картику по ее идентификатору")    .get    .in(path[Long]("id"))    .out(header[Long](HeaderNames.ContentLength))    .out(streamBody[Stream[IO, Byte]](schemaFor[File], CodecFormat.OctetStream()))    .serverLogic(x => withStatus(imagesService.download(x)))


на основе коллекции таких эндпойнтов создаются роуты, а на основе них документация Swagger
    endpoints = todosController.endpoints ::: imagesController.endpoints    routes = endpoints.toRoutes;    docs = endpoints.toOpenAPI("The Scala Todo List", "0.0.1")    yml: String = docs.toYaml    appRoutes = routes <+> new SwaggerHttp4s(yml, "swagger").routes[IO]


Server


В качестве сервера Tapir поддерживает несколько бекендов. Я использовал http4s
    httpApp = Router(      "/" -> appRoutes    ).orNotFound    blazeServer <- BlazeServerBuilder[IO](serverEc)      .bindHttp(settings.host.port, settings.host.host)      .withHttpApp(httpApp)      .resource


Работа с файлами и стримы


Для работы с файлами я использовал стримы из fs2
import fs2.{Stream, io}  def get(path: Path): Stream[IO, Byte] =    io.file.readAll[IO](path, blocker, 4096)


Работа с базой данных


Для работы с БД я использовал doobie и он мне чертовски понравился потому что напомнил старый добрый Dapper ORM. Позволяет маппить DTO и выполнять SQL запросы.
  def add(image: Image): IO[Long] = sql"""         INSERT INTO images (hash, file_path)         VALUES (${image.hash}, ${image.filePath})""".update    .withUniqueGeneratedKeys[Long]("id")    .transact(xa)


Сборка и упаковка в образ Docker


Я захотел собрать все в один единственный файл как например делает это Go или .NET Core с нужными настройками поэтому использовал sbt-native-packager и плагин к нему sbt-assembly. Собранный файл можно запустить с помощью команды
java -jar <имя файла>

Потом сделал DockerFile для запуска этого образа в контейнере
FROM hseeberger/scala-sbt:11.0.2-oraclelinux7_1.3.12_2.13.3 AS baseCOPY . /rootWORKDIR /rootRUN sbt universal:packageZipTarballRUN sbt testFROM openjdk:15-alpine as finalCOPY --from=base /root/target/scala-2.13/scala-todo-api.jar /rootWORKDIR /rootEXPOSE 8080ENTRYPOINT ["java","-jar","scala-todo-api.jar"]

Собранный образ автоматом отправляется в Registry гитлаба через его встроенный CI/CD

Настройки


Настройки сервера загружаю с помощью библиотеки PureConfig и потом так как я использую Docker дополняю их из переменных окружения. Файл application.conf:
db {  url = "jdbc:postgresql://localhost:5432/todos_db"  url = ${?TODO_API_DB_URL}  user = "postgres"  user = ${?TODO_API_DB_USER}  password = "postgres"  password = ${?TODO_API_DB_PASSWORD}}host {  port = 8080  port = ${?TODO_API_HOSTING_PORT}  host = "0.0.0.0"  host = ${?TODO_API_HOSTING_HOST}}


val config = ConfigSource.default.load[AppSettings]
Источник: habr.com
К списку статей
Опубликовано: 28.06.2020 22:13:05
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Scala

Разработка веб-сайтов

Функциональное программирование

Functional programming

Категории

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

© 2006-2020, personeltest.ru