Http4s Client Encode Entity как x-www-form-urlencoded Рекурсивно
У меня есть такая просьба
val request =
Request[IO](
method = POST,
uri = Uri.uri("..."),
headers = Headers(
Authorization(BasicCredentials("...", "..."))
)
)
.withEntity(PaymentIntentRequest2(2000, "usd"))
Я смотрю исходный код, и похоже, что
withEntity
наследует заголовки от вложенных
EntityDecoder
поэтому код выше по умолчанию
Content-Type: application/json
. Где, как если бы я явно перешел
UrlForm
Все отлично.
К сожалению, API, на который я обращаюсь, ожидал данных как
x-www-form-urlencoded
и учитывая сложность целевого API со всеми различными конечными точками / запросами, я хотел бы найти способ кодировать данный класс case как форму. Как лучше всего это сделать?
Я пытался:
Явное указание
Content-Type
но это не работает, потому что унаследованный тип имеет приоритетСоздание неявного универсального преобразования из
Product
кUrlForm
(метод расширения на данный момент)
implicit class UrlFormEncode[+B <: Product](val u: B) {
def asUrlForm: UrlForm =
u.productElementNames
.zip(u.productIterator)
.foldLeft(UrlForm()) { (a, b) =>
a.combine(UrlForm(b._1 -> b._2.toString))
}
}
Проблема здесь в
UrlForm
ожидает строку в обеих сторонах отображения. И если я просто конвертирую вещи с
.toString
это не работает из-за вложенного типа, например:
ChargeRequest(Amount(refInt), EUR, source = Some(SourceId("...."))
Результаты в следующих
json
что не верно
{
"currency": "EUR",
"amount": "2000",
"source": "Some(SourceId(....))",
"customer": "None"
}
Я старался
asJson
вместо
toString
но Цирцея не может определиться с правильным
KeyEncoder
Как правильно подойти к этому, чтобы данный
Product
закодировано по потоку?
1 ответ
I just faced the same issue and this is the way it worked for me.
From https://http4s.org/v0.20/client/
// This import will add the right `apply` to the POST.
import org.http4s.client.dsl.io._
val form = UrlForm(
OAuthAttribute.Code -> code,
OAuthAttribute.RedirectUri -> callbackUri,
OAuthAttribute.GrantType -> "authorization_code"
)
private def buildRequest(tokenUri: Uri, form: UrlForm, header: String): Request[IO] =
POST(
form,
tokenUri,
Header.Raw(CIString("Authorization"), header),
Header.Raw(CIString("Content-Type"), "application/x-www-form-urlencoded"),
Header.Raw(CIString("Accept"), "application/json")
)
And that's it. For some strange reason using
.withHeaders
didn't work for me, seems like they are overridden or so.