[Разработка веб-сайтов, Scala, API, ООП, Функциональное программирование] Изучаю Scala: Часть 5 — Http Requests
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет хабр! Продолжаю изучать Scala. Большинство бекендов так или иначе интегрированы с другими и делают HTTP запросы. Так как я на стек Cats и http4s ориентирован то буду рассматривать и изучать именно его. Сделаю запросы с куками, телом в json и в form, c файлом, с хедерами. Тут Hirrolot мне скорее всего минус поставит. Хочу сказать что может быть кому-то кто тоже изучает Scala будет полезна эта статья. Да и меня написание таких статей мотивирует изучать дальше. Люблю тебя малой. Расти большой не будь лапшой. Я уверен из тебя получится просто отличный инженер или даже может быть ученый в области IT. Давненько меня тут не было. В общем штормило у меня на личном фронте. С начала мы встречались обнимались и целовались с Марго. Потом мы расстались. Потом я переживал из-за этого. Потом работы навалилось. Вот так примерно у меня последние месяцы прошли. Взгрустнул, выпил и решил я написать сюда. И так, начнем.
Содержание
- Изучаю Scala: Часть 1 — Игра змейка
- Изучаю Scala: Часть 2 — Todo лист с возможностью загрузки картинок
- Изучаю Scala: Часть 3 — Юнит Тесты
- Изучаю Scala: Часть 4 — WebSocket
- Изучаю Scala: Часть 5 — Http Requests
Ссылки
Тестовый контроллер который будет отвечать на наши запросы:
import cats.effect.{ContextShift, IO}
import domain.todos.entities.Todo
import io.circe.generic.auto._
import sttp.model.CookieWithMeta
import sttp.tapir.json.circe.jsonBody
import sttp.tapir.{header, _}
class TestController(implicit contextShift: ContextShift[IO]) extends ControllerBase {
private val baseTestEndpoint = baseEndpoint
.in("test")
.tag("Test")
//Сюда мы будем делать наш запрос
private val postTest = baseTestEndpoint
.summary("Тестовый эндпойнт для запроска к самому себе")
.description("Возвращает тестовые данные")
.post
.in(header[String]("test_header"))
.in(jsonBody[List[Todo]])
.in(cookies)
.out(header[String]("test_header_out"))
.out(jsonBody[List[Todo]])
.out(setCookies)
.serverLogic(x => withStatus(IO {
(x._1 + x._3.map(c => c.name + "" + c.value).fold("")((a, b) => a + " " + b), x._2, List(CookieWithMeta(name = "test", value = "test_value")))
}))
//Этот метод будет запускать наш запрос
private val runHttpRequestTes = baseTestEndpoint
.summary("Запускает тестовый запрос к самому себе")
.description("Запускает тестовый запрос к самому себе")
.get
.out(stringBody)
.serverLogic(_ => withStatus(runHttp()))
def runHttp(): IO[String] = {
ClientExamples.execute().as("Ok")
}
val endpoints = List(
postTest,
runHttpRequestTes
)
}
Собственно сам запрос:
import cats.effect.{ContextShift, IO}
import com.typesafe.scalalogging.StrictLogging
import domain.todos.entities.Todo
import io.circe.generic.auto._
import org.http4s.circe.CirceEntityCodec.circeEntityEncoder
import org.http4s.client.blaze._
import org.http4s.client.middleware.Logger
import org.http4s.headers._
import org.http4s.{MediaType, Uri, _}
import org.log4s._
import java.time.Instant
import scala.concurrent.ExecutionContext.global
object ClientExamples extends StrictLogging {
private[this] val logger = getLogger
def execute()(implicit contextShift: ContextShift[IO]) = {
//Создаем клиент
BlazeClientBuilder[IO](global).resource.use { client =>
logger.warn("Start Request")
//Оборачиваем его в мидлвар который будет логгировать запросы и ответы.
//Указываем логгировать и боди и хедеры
val loggedClient = Logger[IO](true, true)(client)
//Парсим адресс и небезопасным методом достаем результат
val uri = Uri.fromString("http://localhost:8080/api/v1/test").toOption.get
//Создаем запрос. Указываем что это будет POST запрос по адресу что мы сформировали ранее
val request: Request[IO] = Request[IO](method = Method.POST, uri = uri)
//Указываем что в json теле запроса передавать массив todo
.withEntity(List(Todo(1, "Test", 2, Instant.now())))
//Указываем заголовки которые будут у запроса. Тут один наш кастомный.
.withHeaders(Accept(MediaType.application.json), Header(name = "test_header", value = "test_header_value"))
//Указываем что с запросом будут оправляться куки с таким значением
.addCookie("test_cookie", "test_cookie_value")
//Выполняем запрос
loggedClient.run(request).use(r => {
logger.warn("End Request")
//Логгируем статус (200, 404, 500 и т.д)
logger.warn(r.status.toString())
//Логгируем ответ
logger.warn(r.toString())
//Пишем в логи хедеры ответа. Там в том числе есть Set-Cookie
logger.warn(r.headers.toString())
//bodyText возвращает Stream[IO,String] и мы логгируем данные в нем
//Можно десериализовать из этого json ответ сервера.
r.bodyText.map(t => logger.warn(t)).compile.drain
})
}
}
}
В результате в логах увидим такой текст:
//Наш запрос
02:54:44.634 [ioapp-compute-7] INFO org.http4s.client.middleware.RequestLogger - HTTP/1.1 POST http://localhost:8080/api/v1/test Headers(Accept: application/json, test_header: test_header_value, Cookie: <REDACTED>) body="[{"id":1,"name":"Test","imageId":2,"created":"2020-12-08T23:54:44.627434500Z"}]"
//Наш статус
02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - 200 OK
//Наш ответ
02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - Response(status=200, headers=Headers(test_header_out: test_header_value test_cookietest_cookie_value, Set-Cookie: <REDACTED>, Content-Type: application/json, Date: Tue, 08 Dec 2020 23:54:44 GMT, Content-Length: 79))
//Хедеры нашего ответа
02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - Headers(test_header_out: test_header_value test_cookietest_cookie_value, Set-Cookie: test=test_value, Content-Type: application/json, Date: Tue, 08 Dec 2020 23:54:44 GMT, Content-Length: 79)
//Тело (json) нашего ответа сервера
02:54:44.643 [ioapp-compute-6] WARN appServices.ClientExamples - [{"id":1,"name":"Test","imageId":2,"created":"2020-12-08T23:54:44.627434500Z"}]
Тут был специально показан запрос в максимально общем виде. Показано как установить куки, хедеры, тело запроса. Если нужно данные формы отправить или там файл то есть для этого пару способов. Сами данные методом .withEntity выставляются а вот объект формируется по другому
//Тут можно файл отправить через Part.fileData
val data = Multipart(parts = Vector(Part.formData("age","18"):Part[IO]))
//Или
val data= UrlForm(("age","18"))
//И создаем запрос
val request: Request[IO] = Request[IO](method = Method.POST, uri = uri)
.withEntity(data)
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Сетевые технологии, DNS] Cloudflare, Apple и Fastly объявили о создании нового протокола DNS
- [PostgreSQL, .NET, API, C#] Development of “YaRyadom” (“I’mNear”) application under the control of Vk Mini Apps. Part 1 .Net Core (перевод)
- [Программирование] kotlinx.coroutines 1.4.0: представляем StateFlow и SharedFlow (перевод)
- [Информационная безопасность, Криптография, Законодательство в IT] Власти Казахстана снова принуждают пользователей устанавливать сертификат, чтобы читать зашифрованную переписку
- [Проектирование и рефакторинг, API, Профессиональная литература] Книга: проектирование API
- Казахстан возобновил попытки перехвата HTTPS-трафика
- [Информационная безопасность, Администрирование доменных имен] Сайты региональных органов власти: все еще печальнее, чем у федералов
- [Разработка веб-сайтов, PHP, Laravel] Laravel–Дайджест (23 ноября – 6 декабря 2020)
- [Серверная оптимизация, API, DevOps] Haproxy — программирование и конфигурирование средствами Lua
- [Информационная безопасность, Разработка веб-сайтов] Концепт — как усилить защиту паролей «12345» от bruteforce атаки (попытка вторая)
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_scala, #_api, #_oop (ООП), #_funktsionalnoe_programmirovanie (Функциональное программирование), #_scala, #_functional_programming, #_funktsionalnoe_programmirovanie (функциональное программирование), #_oop (ооп), #_http, #_http4s, #_api, #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_scala, #_api, #_oop (
ООП
), #_funktsionalnoe_programmirovanie (
Функциональное программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 06:34
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет хабр! Продолжаю изучать Scala. Большинство бекендов так или иначе интегрированы с другими и делают HTTP запросы. Так как я на стек Cats и http4s ориентирован то буду рассматривать и изучать именно его. Сделаю запросы с куками, телом в json и в form, c файлом, с хедерами. Тут Hirrolot мне скорее всего минус поставит. Хочу сказать что может быть кому-то кто тоже изучает Scala будет полезна эта статья. Да и меня написание таких статей мотивирует изучать дальше. Люблю тебя малой. Расти большой не будь лапшой. Я уверен из тебя получится просто отличный инженер или даже может быть ученый в области IT. Давненько меня тут не было. В общем штормило у меня на личном фронте. С начала мы встречались обнимались и целовались с Марго. Потом мы расстались. Потом я переживал из-за этого. Потом работы навалилось. Вот так примерно у меня последние месяцы прошли. Взгрустнул, выпил и решил я написать сюда. И так, начнем. Содержание
Ссылки Тестовый контроллер который будет отвечать на наши запросы: import cats.effect.{ContextShift, IO}
import domain.todos.entities.Todo import io.circe.generic.auto._ import sttp.model.CookieWithMeta import sttp.tapir.json.circe.jsonBody import sttp.tapir.{header, _} class TestController(implicit contextShift: ContextShift[IO]) extends ControllerBase { private val baseTestEndpoint = baseEndpoint .in("test") .tag("Test") //Сюда мы будем делать наш запрос private val postTest = baseTestEndpoint .summary("Тестовый эндпойнт для запроска к самому себе") .description("Возвращает тестовые данные") .post .in(header[String]("test_header")) .in(jsonBody[List[Todo]]) .in(cookies) .out(header[String]("test_header_out")) .out(jsonBody[List[Todo]]) .out(setCookies) .serverLogic(x => withStatus(IO { (x._1 + x._3.map(c => c.name + "" + c.value).fold("")((a, b) => a + " " + b), x._2, List(CookieWithMeta(name = "test", value = "test_value"))) })) //Этот метод будет запускать наш запрос private val runHttpRequestTes = baseTestEndpoint .summary("Запускает тестовый запрос к самому себе") .description("Запускает тестовый запрос к самому себе") .get .out(stringBody) .serverLogic(_ => withStatus(runHttp())) def runHttp(): IO[String] = { ClientExamples.execute().as("Ok") } val endpoints = List( postTest, runHttpRequestTes ) } Собственно сам запрос: import cats.effect.{ContextShift, IO}
import com.typesafe.scalalogging.StrictLogging import domain.todos.entities.Todo import io.circe.generic.auto._ import org.http4s.circe.CirceEntityCodec.circeEntityEncoder import org.http4s.client.blaze._ import org.http4s.client.middleware.Logger import org.http4s.headers._ import org.http4s.{MediaType, Uri, _} import org.log4s._ import java.time.Instant import scala.concurrent.ExecutionContext.global object ClientExamples extends StrictLogging { private[this] val logger = getLogger def execute()(implicit contextShift: ContextShift[IO]) = { //Создаем клиент BlazeClientBuilder[IO](global).resource.use { client => logger.warn("Start Request") //Оборачиваем его в мидлвар который будет логгировать запросы и ответы. //Указываем логгировать и боди и хедеры val loggedClient = Logger[IO](true, true)(client) //Парсим адресс и небезопасным методом достаем результат val uri = Uri.fromString("http://localhost:8080/api/v1/test").toOption.get //Создаем запрос. Указываем что это будет POST запрос по адресу что мы сформировали ранее val request: Request[IO] = Request[IO](method = Method.POST, uri = uri) //Указываем что в json теле запроса передавать массив todo .withEntity(List(Todo(1, "Test", 2, Instant.now()))) //Указываем заголовки которые будут у запроса. Тут один наш кастомный. .withHeaders(Accept(MediaType.application.json), Header(name = "test_header", value = "test_header_value")) //Указываем что с запросом будут оправляться куки с таким значением .addCookie("test_cookie", "test_cookie_value") //Выполняем запрос loggedClient.run(request).use(r => { logger.warn("End Request") //Логгируем статус (200, 404, 500 и т.д) logger.warn(r.status.toString()) //Логгируем ответ logger.warn(r.toString()) //Пишем в логи хедеры ответа. Там в том числе есть Set-Cookie logger.warn(r.headers.toString()) //bodyText возвращает Stream[IO,String] и мы логгируем данные в нем //Можно десериализовать из этого json ответ сервера. r.bodyText.map(t => logger.warn(t)).compile.drain }) } } } В результате в логах увидим такой текст: //Наш запрос
02:54:44.634 [ioapp-compute-7] INFO org.http4s.client.middleware.RequestLogger - HTTP/1.1 POST http://localhost:8080/api/v1/test Headers(Accept: application/json, test_header: test_header_value, Cookie: <REDACTED>) body="[{"id":1,"name":"Test","imageId":2,"created":"2020-12-08T23:54:44.627434500Z"}]" //Наш статус 02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - 200 OK //Наш ответ 02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - Response(status=200, headers=Headers(test_header_out: test_header_value test_cookietest_cookie_value, Set-Cookie: <REDACTED>, Content-Type: application/json, Date: Tue, 08 Dec 2020 23:54:44 GMT, Content-Length: 79)) //Хедеры нашего ответа 02:54:44.641 [scala-execution-context-global-62] WARN appServices.ClientExamples - Headers(test_header_out: test_header_value test_cookietest_cookie_value, Set-Cookie: test=test_value, Content-Type: application/json, Date: Tue, 08 Dec 2020 23:54:44 GMT, Content-Length: 79) //Тело (json) нашего ответа сервера 02:54:44.643 [ioapp-compute-6] WARN appServices.ClientExamples - [{"id":1,"name":"Test","imageId":2,"created":"2020-12-08T23:54:44.627434500Z"}] Тут был специально показан запрос в максимально общем виде. Показано как установить куки, хедеры, тело запроса. Если нужно данные формы отправить или там файл то есть для этого пару способов. Сами данные методом .withEntity выставляются а вот объект формируется по другому //Тут можно файл отправить через Part.fileData
val data = Multipart(parts = Vector(Part.formData("age","18"):Part[IO])) //Или val data= UrlForm(("age","18")) //И создаем запрос val request: Request[IO] = Request[IO](method = Method.POST, uri = uri) .withEntity(data) =========== Источник: habr.com =========== Похожие новости:
Разработка веб-сайтов ), #_scala, #_api, #_oop ( ООП ), #_funktsionalnoe_programmirovanie ( Функциональное программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 06:34
Часовой пояс: UTC + 5