akka/akka-http
Vedi su GitHubCustom headers should be parsed to the custom types instead of `RawHeader`
Open
#1196 aperta il 13 giu 2017
1 - triagedhelp wantedt:coret:model
Metriche repository
- Star
- (1311 star)
- Metriche merge PR
- (Merge medio 1h 17m) (1 PR mergiata in 30 g)
Descrizione
Akka HTTP should allow registering custom headers so that a custom header can be rendered to the custom type instead of RawHeader. Custom methods, mediatypes and status codes are allowed to be passed to ParserSettings.
It should be possible to read a custom header by request.header[ApiTokenHeader]. Please see below a reproducer.
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.headers.{ModeledCustomHeader, ModeledCustomHeaderCompanion, `User-Agent`}
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Flow
import akka.testkit.TestKit
import org.scalatest.{AsyncFlatSpecLike, Matchers}
import scala.concurrent.duration._
import scala.util.Try
class CustomHeaderSpec extends TestKit(ActorSystem("CustomHeaderSpec")) with AsyncFlatSpecLike with Matchers {
implicit val ac = ActorMaterializer()
val flow = Flow[HttpRequest].map { request =>
val userAgent = request.header[`User-Agent`].map(_.value).getOrElse("N/A")
val apiKey = request.header[ApiTokenHeader].map(_.value).getOrElse("N/A")
val apiKeyAsRaw =
request.headers
.collectFirst { case h if h.lowercaseName == ApiTokenHeader.lowercaseName => h.value }
.getOrElse("N/A")
HttpResponse(entity = s"User-Agent: $userAgent apiKey: $apiKey apiKeyAsRaw: $apiKeyAsRaw")
}
val binding = Http().bindAndHandle(flow, "localhost", port = 0)
it should "parse to custom header object" in {
binding flatMap { b =>
Http()
.singleRequest(HttpRequest(uri = s"http://localhost:${b.localAddress.getPort}/")
.withHeaders(`User-Agent`("abc"), ApiTokenHeader("myToken")))
} flatMap { response =>
response.entity.toStrict(30 seconds)
} flatMap { e =>
e.data.utf8String shouldBe "User-Agent: abc apiKey: myToken apiKeyAsRaw: myToken"
}
}
}
final class ApiTokenHeader(token: String) extends ModeledCustomHeader[ApiTokenHeader] {
override def renderInRequests = true
override def renderInResponses = false
override val companion = ApiTokenHeader
override def value: String = token
}
object ApiTokenHeader extends ModeledCustomHeaderCompanion[ApiTokenHeader] {
override val name = "apiKey"
override def parse(value: String) = Try(new ApiTokenHeader(value))
}