Skip to content

Instantly share code, notes, and snippets.

@lanceon
Forked from jeroenr/AkkaHttpMicroService.scala
Created August 25, 2017 09:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lanceon/9f58a3915c6d411d6d53555d1c699946 to your computer and use it in GitHub Desktop.
Save lanceon/9f58a3915c6d411d6d53555d1c699946 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)))
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment