Skip to content

Instantly share code, notes, and snippets.

@globulon
Created December 3, 2018 09:40
Show Gist options
  • Select an option

  • Save globulon/7dd64443e5edbce44d20e634afd223bd to your computer and use it in GitHub Desktop.

Select an option

Save globulon/7dd64443e5edbce44d20e634afd223bd to your computer and use it in GitHub Desktop.
import akka.http.scaladsl.model.HttpMethod
final case class Cors(domain: String, methods: List[HttpMethod])
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.model.headers.{HttpOrigin, HttpOriginRange}
import akka.http.scaladsl.server.Directive
import akka.http.scaladsl.server.Directives.{complete, options, respondWithHeaders, _}
trait CorsRouting {
protected[cors] def buildCors(domain: String, preFlight: Headers, flight: Headers): Directive[Unit] = Directive {
makeRoute ⇒
checkSameOrigin(HttpOriginRange(HttpOrigin(domain))) {
options(complete(HttpResponse(OK).withHeaders(preFlight))) ~
respondWithHeaders(flight) { makeRoute(()) }
}
}
}
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers._
import akka.http.scaladsl.server.{Directive, Directive0}
import scalaz.Scalaz._
import scalaz.{Kleisli, Reader, State}
trait CorsStaging {
private type StageHeader[A] = State[Headers, A]
private type StageHeaders = StageHeader[Headers]
private def stageHeader[A](f: Headers ⇒ (Headers, A)): StageHeader[A] = State(f)
private def setAllowOrigin: Kleisli[StageHeader, Cors, Unit] = Kleisli { c ⇒
stageHeader { hs ⇒ (`Access-Control-Allow-Origin`(HttpOrigin(c.domain)) :: hs, ()) }
}
private def setAllowMethods: Kleisli[StageHeader, Cors, Unit] = Kleisli { c ⇒
stageHeader { hs ⇒ (`Access-Control-Allow-Methods`(c.methods) :: hs, ()) }
}
private def setAllowCreds: Kleisli[StageHeader, Cors, Unit] = Kleisli { _ ⇒
stageHeader(hs ⇒ (`Access-Control-Allow-Credentials`(true) :: hs, ()))
}
private def getHeaders: Kleisli[StageHeader, Cors, Headers] = Kleisli(_ ⇒ get[Headers])
private def stagePreFlight: Kleisli[StageHeader, Cors, Headers] = for {
_ ← setAllowOrigin
_ ← setAllowMethods
s ← getHeaders
} yield s
private def stageFlight: Kleisli[StageHeader, Cors, Headers] = for {
_ ← setAllowOrigin
_ ← setAllowCreds
s ← getHeaders
} yield s
private def withCors[A](domain: String, ms: List[HttpMethod])(f: Cors ⇒ A): A =
f(Cors(domain, ms))
private def eval(k: Kleisli[StageHeader, Cors, Headers]): Reader[Cors, Headers] =
k.mapK[Id, StageHeaders](identity).map(_.eval(List.empty))
private def stageCors(domain: String): Reader[Cors, Directive0] =
(eval(stagePreFlight) ⊛ eval(stageFlight)) { buildCors(domain, _, _) }
final def cors(origin: String, m: HttpMethod, ms: HttpMethod*): Directive[Unit] =
withCors(origin, m :: ms.toList) { stageCors(origin)(_) }
}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.server.Directives.{complete, get, path, _}
import akka.http.scaladsl.server.Route
import com.graboid.alpha.service.cors._
import com.graboids.alpha.service.dto.{Info, Message, ValueObjects}
import com.graboids.alpha.service.users.app._
import com.graboids.alpha.service.users.dtos.{Entities, User}
import spray.json.DefaultJsonProtocol
trait Routes extends Entities with ValueObjects with DefaultJsonProtocol {
final protected def routes: ReadApp[Route] =
corsOrigin map { origin ⇒ index ~ users(origin) ~ user(origin) }
private def users(origin: String): Route = cors(origin, GET, OPTIONS) {
path("users") {
get {
complete(List.empty[User])
}
}
}
private def user(origin: String): Route = cors(origin, GET, OPTIONS) {
pathPrefix("user" / LongNumber) { id ⇒
get {
complete(User(id, s"user-$id"))
}
}
}
private def index: Route = get {
path("index") {
complete(Message(Info, "Welcome on Akka HTTP !"))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment