Skip to content

Instantly share code, notes, and snippets.

@jeroenr
Last active January 28, 2021 14:01
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jeroenr/5261fa041d592f37cd80 to your computer and use it in GitHub Desktop.
Save jeroenr/5261fa041d592f37cd80 to your computer and use it in GitHub Desktop.
Akka HTTP API with CORS headers and custom Media types
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.stream.ActorMaterializer
object Boot extends App with Service with CorsSupport {
override implicit val system = ActorSystem()
override implicit val executor = system.dispatcher
override implicit val materializer = ActorMaterializer()
Http().bindAndHandle(corsHandler(routes), "0.0.0.0", 1337)
}
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model.{StatusCodes, HttpResponse}
import akka.http.scaladsl.model.headers._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{Directive0, Route}
import com.typesafe.config.ConfigFactory
trait CorsSupport {
lazy val allowedOrigin = {
val config = ConfigFactory.load()
val sAllowedOrigin = config.getString("cors.allowed-origin")
HttpOrigin(sAllowedOrigin)
}
//this directive adds access control headers to normal responses
private def addAccessControlHeaders: Directive0 = {
respondWithHeaders(
`Access-Control-Allow-Origin`(allowedOrigin),
`Access-Control-Allow-Credentials`(true),
`Access-Control-Allow-Headers`("Authorization", "Content-Type", "X-Requested-With")
)
}
//this handles preflight OPTIONS requests.
private def preflightRequestHandler: Route = options {
complete(HttpResponse(StatusCodes.OK).withHeaders(`Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE)))
}
def corsHandler(r: Route) = addAccessControlHeaders {
preflightRequestHandler ~ r
}
}
libraryDependencies ++= {
val akkaV = "2.3.12"
val akkaStreamV = "1.0"
Seq(
"com.typesafe.akka" %% "akka-actor" % akkaV,
"com.typesafe.akka" %% "akka-stream-experimental" % akkaStreamV,
"com.typesafe.akka" %% "akka-http-core-experimental" % akkaStreamV,
"com.typesafe.akka" %% "akka-http-experimental" % akkaStreamV,
"com.typesafe.akka" %% "akka-http-spray-json-experimental" % akkaStreamV
)
}
import akka.actor.ActorSystem
import akka.event.LoggingAdapter
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.marshalling.{ToEntityMarshaller, Marshaller}
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.Materializer
import com.oxyme.monitoring.HealthChecker
import com.oxyme.monitoring.model.{Unhealthy, Healthy}
import com.typesafe.config.{ConfigFactory, Config}
import akka.http.scaladsl.model.StatusCodes._
import spray.json._
import spray.json.DefaultJsonProtocol
import scala.concurrent.ExecutionContextExecutor
case class Person(name: String, age: Int)
case class Persons(total: Int, data: Iterable[Person])
trait Protocols extends DefaultJsonProtocol {
implicit val personFormat = jsonFormat2(Person.apply)
implicit val personsFormat = jsonFormat2(Persons.apply)
val `application/vnd.persons.v1+json` =
MediaType.custom("application/vnd.persons.v1+json", MediaType.Encoding.Fixed(HttpCharsets.`UTF-8`))
implicit val personsMarshaller: ToEntityMarshaller[Persons] = Marshaller.opaque { persons =>
HttpEntity(ContentType(`application/vnd.persons.v1+json`, HttpCharsets.`UTF-8`), persons.toJson.compactPrint)
}
}
trait Service extends Protocols {
implicit val system: ActorSystem
implicit val materializer: Materializer
// declared here because it needs Materializer as opposed to Marshaller
implicit val personsUnmarshaller = sprayJsonUnmarshaller[Persons].forContentTypes(
`application/vnd.persons.v1+json`,
`application/json`
)
val routes = {
path("persons"){
get {
complete {
Persons(3, Seq(Person("jeroen", 28), Person("harry", 12), Person("john", 31)))
}
}
}
}
}
@jrudolph
Copy link

There's also the respondWithHeaders directive which is slightly more straight-forward than mapResponseHeaders.

@jeroenr
Copy link
Author

jeroenr commented Sep 25, 2015

@jrudolph good point, thnx 👍

@Joldnine
Copy link

Good demo! It works well for me.

@premeaswaran
Copy link

Perfect! Exactly what i was looking for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment