Can I create a default OPTIONS directive for all entry points on my route?

I do not want to explicitly write:

options { ... } 

for every entry / path point in my route spray. I would like to write some generic code that will add OPTIONS support for all paths. He should look at the routes and extract the supported methods from them.

I can’t insert any code since I don’t know how to approach it in Spray.

The reason I do this is to provide an API for self-discovery that adheres to the principles of HATEOAS.

+5
source share
3 answers

The directive below will be able to catch the rejected request, check if it is an option request, and return:

  • CORS headers for CORS support ( this directive removes ALL cors protection, beware !!!!! )
  • Allow headers to provide peers with a list of available methods

Try to understand the following snippet and adjust if necessary. You should prefer to provide as much information as possible, but if you want to return only the allowed methods, I suggest you cut the rest :).

 import spray.http.{AllOrigins, HttpMethods, HttpMethod, HttpResponse} import spray.http.HttpHeaders._ import spray.http.HttpMethods._ import spray.routing._ /** * A mixin to provide support for providing CORS headers as appropriate */ trait CorsSupport { this: HttpService => private val allowOriginHeader = `Access-Control-Allow-Origin`(AllOrigins) private val optionsCorsHeaders = List( `Access-Control-Allow-Headers`( "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, " + "Referer, User-Agent" ), `Access-Control-Max-Age`(60 * 60 * 24 * 20) // cache pre-flight response for 20 days ) def cors[T]: Directive0 = mapRequestContext { context => context.withRouteResponseHandling { // If an OPTIONS request was rejected as 405, complete the request by responding with the // defined CORS details and the allowed options grabbed from the rejection case Rejected(reasons) if ( context.request.method == HttpMethods.OPTIONS && reasons.exists(_.isInstanceOf[MethodRejection]) ) => { val allowedMethods = reasons.collect { case r: MethodRejection => r.supported } context.complete(HttpResponse().withHeaders( `Access-Control-Allow-Methods`(OPTIONS, allowedMethods :_*) :: allowOriginHeader :: optionsCorsHeaders )) } } withHttpResponseHeadersMapped { headers => allowOriginHeader :: headers } } } 

Use it as follows:

 val routes: Route = cors { path("hello") { get { complete { "GET" } } ~ put { complete { "PUT" } } } } 

Resource: https://github.com/giftig/mediaman/blob/22b95a807f6e7bb64d695583f4b856588c223fc1/src/main/scala/com/programmingcentre/utils/utils/CorsSupport.scala

+2
source

Methinks options pretty general, you can use it like:

 path("foo") { options { ... } } ~ path("bar") { options { ... } } 

or like this:

 options { path("foo") { ... } ~ path("bar") { ... } } 
-2
source

I did it like this:

 private val CORSHeaders = List( `Access-Control-Allow-Methods`(GET, POST, PUT, DELETE, OPTIONS), `Access-Control-Allow-Headers`("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent"), `Access-Control-Allow-Credentials`(true) ) def respondWithCORS(origin: String)(routes: => Route) = { val originHeader = `Access-Control-Allow-Origin`(SomeOrigins(Seq(HttpOrigin(origin)))) respondWithHeaders(originHeader :: CORSHeaders) { routes ~ options { complete(StatusCodes.OK) } } } val routes = respondWithCORS(config.getString("origin.domain")) { pathPrefix("api") { // ... your routes here } } 

Thus, each OPTION request to any URL with the / api prefix returns 200 codes.

Update : Added Access * headers.

-2
source

Source: https://habr.com/ru/post/1200809/


All Articles