[ANN] encors: CORS middleware for Ring apps

217 views
Skip to first unread message

ro...@unbounce.com

unread,
Nov 25, 2014, 6:40:17 PM11/25/14
to clo...@googlegroups.com
It is our pleasure to announce a new ring middleware for CORS support.


Features include:

* Add multiple CORS Policy to an app (can classify them via ring request info)

* Preflight CORS requests are supported

* Thoroughly tested (around 276 different assertions in both unit and integration tests)

* Validated API options via Prismatic's schema

* Full documentation on README

Any feedback is welcome.

James Reeves

unread,
Nov 25, 2014, 8:27:12 PM11/25/14
to clo...@googlegroups.com
I mentioned this on r/clojure, but don't understand why you have a map->CorsPolicy function, as it doesn't appear to serve any purpose. You seem to be using it as a map, but in Clojure it's more idiomatic to use maps as maps.

- James

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

ro...@unbounce.com

unread,
Nov 26, 2014, 6:08:48 PM11/26/14
to clo...@googlegroups.com, ja...@booleanknot.com
map->CorsPolicy enforces correctness of input, this way the wrap-cors functions doesn't need to validate data. Probably we can add a call to map->CorsPolicy as the first thing of wrap-cors function and keep this function private.

Thanks for the suggestion.

Román González

unread,
Nov 26, 2014, 6:34:17 PM11/26/14
to clo...@googlegroups.com, ja...@booleanknot.com
James, I have second thoughts on including map->CorsPolicy to the internal API...

Given that we are returning a Policy per request call, calling a map->CorsPolicy every time we call warp-cors sounds a bit overkill performance wise... Instead of validating development settings once when the namespaces is loaded, it is being validated every time a request comes in. 

I understand using map->CorsPolicy is not as Clojuresque, but I think we would prefer to enforce validity on development settings once than validate it each time just for the sake of keeping Clojure Map semantics.

Does this make sense? Let me know your thoughts.

Roman.-

You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/GLFldAIjq7M/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

James Reeves

unread,
Nov 26, 2014, 6:43:33 PM11/26/14
to ro...@unbounce.com, clo...@googlegroups.com
On 26 November 2014 at 23:08, <ro...@unbounce.com> wrote:
map->CorsPolicy enforces correctness of input, this way the wrap-cors functions doesn't need to validate data. Probably we can add a call to map->CorsPolicy as the first thing of wrap-cors function and keep this function private.

In Clojure, types and validation are orthogonal concepts. You don't need to use deftype in order to validate a map.

For instance, you could write your middleware function instead as:

    (defn wrap-cors [handler options]
      (s/validate cors-schema options)
      (fn [request]
        ...))

Or better yet, perhaps just use s/defn instead.

Given that we are returning a Policy per request call, calling a map->CorsPolicy every time we call warp-cors sounds a bit overkill performance wise... Instead of validating development settings once when the namespaces is loaded, it is being validated every time a request comes in. 

Even though the function wrap-cors returns will be evaluated many times, the wrap-cors function itself will likely only be evaluated once when your handler is created. For instance:

    (def handler
      (wrap-cors my-routes cors-options))

This means that there's no performance benefit to creating a type to just contain the option map, particularly since you're not using type hints, so you're accessing the type via reflection.

By convention, Ring middleware also takes the handler as the first argument, allowing it to be more easily threaded.

- James

Román González

unread,
Nov 26, 2014, 7:31:37 PM11/26/14
to James Reeves, clo...@googlegroups.com
Good points...

So possible changes:

* Replace the get-policy-for-req argument with a just policy-options map

This makes it easier to validate options just once. I guess all the validations done on a simple
Request -> CorsPolicy function can be done by composing middleware together (e.g. Middleware that check certain header or route + cors middleware). I like this.

* Remove the CorsPolicy type and just do the schema validation at the beginning of the middleware.

I believe this actionables are feasible. I discuss this internally and develop of all this make sense.

Thanks for your feedback James, highly appreciated.

Roman.- 

David Dossot

unread,
Dec 3, 2014, 7:20:02 PM12/3/14
to clo...@googlegroups.com, ja...@booleanknot.com

Just to let everyone know that we've just released version 2.0 of encors, with these suggested changes in place.

The middleware should now feel more Clojure-ish and Ring-ish :)

Thanks James for the great feedback.
Reply all
Reply to author
Forward
0 new messages