Обработка многокомпонентного контента в http4s

Я хотел бы знать, как я могу обрабатывать многокомпонентный контент, используя библиотеку http4s.

Представьте себе сервис со следующим фрагментом (полный смысл здесь):

  case GET -> Root / "form" =>
   Ok(
   """|<html>
      |<body>
      |<form method="post" action="/post" enctype="multipart/form-data">
      | <input type="date" name="birthDate" placeholder="birthDate">
      | <input type="file" name="dataFile">
      | <input type="submit">
      |</form></body></html>""".stripMargin).
      withContentType(Some(`Content-Type`(`text/html`)))

case req @ POST -> Root / "post" => {
 req.decode[Multipart[IO]] { m =>
  Ok(
    s"""Multipart Data\nParts:${m.parts.length}
       |${m.parts.map { case f: Part[IO] => { f.name + ", headers: " + f.headers.mkString(",")} }.mkString("\n")}""".stripMargin)
}
  }

Если я выполняю службу и заполняю соответствующие поля, я получаю вывод, подобный следующему:

Multipart Data
Parts:2
Some(birthDate), headers: Content-Disposition: form-data; name="birthDate"
Some(dataFile), headers: Content-Disposition: form-data; name="dataFile"; 
 filename="file.pdf",Content-Type: application/pdf

Так что я знаю, как получить информацию о деталях, которые являются элементами типа Part[IO] и содержать headers а также body,

Я хотел бы знать, как обрабатывать эти детали. В этом случае, например, я хотел бы открыть файл и сообщить о его длине. Какой идиоматический способ сделать это?

1 ответ

body из Part[IO] это Stream[F[_],Byte] которые могут быть обработаны с использованием методов из fs2 библиотека.

Существует несколько возможностей, одна из которых - записать содержимое потока в файл, используя io.file.writeAll а также io.file.writeAllASync методы.

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

Результат может быть:

  case req @ POST -> Root / "post" => {
    req.decode[Multipart[IO]] { m => {
      m.parts.find(_.name == Some("dataFile")) match {
        case None => BadRequest(s"Not file")
        case Some(part) => for {
          contents <- part.body.through(utf8Decode).runFoldMonoid
          response <- Ok(s"""Multipart Data\nParts:${m.parts.length}
                            |File contents: ${contents}""".stripMargin)
        } yield response
      }
    }
   }
  }
 }

Предыдущий фрагмент вернет содержимое файла.

Другие вопросы по тегам