ivpusic / neo

Go Web Framework
http://ivpusic.github.io/neo/
MIT License
420 stars 43 forks source link

CORS support (or lack thereof) #12

Closed Netherdrake closed 9 years ago

Netherdrake commented 9 years ago

I feel like neo has a potential of being a really nice Go library for building API's, but while trying to do so, I ran into another issue. CORS.

Currently, neo can only properly handle GET and simple POST requests from same origin. Handling cors requires a bit of middleware code

    // CORS Middleware
    app.Use(func(ctx *neo.Ctx, next neo.Next) {
        if origin := ctx.Req.Header.Get("Origin"); origin != "" {
            ctx.Res.Header.Set("Access-Control-Allow-Origin", origin)
            ctx.Res.Header.Set("Access-Control-Allow-Credentials", "true")
            ctx.Res.Header.Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
            ctx.Res.Header.Set("Access-Control-Allow-Headers",
                "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
        }

        // back to neo
        next()
    })

, but the real pain is enabling POST, PUT, PATCH, DELETE... requests, since Neo doesn't expose router internals, one has to manually define OPTIONS region for every single endpoint.

    app.Options("/channels/:name", func(ctx *neo.Ctx) {
        ctx.Res.Raw([]byte(""), http.StatusOK)
    })
    app.Options("/channels", func(ctx *neo.Ctx) {
        ctx.Res.Raw([]byte(""), http.StatusOK)
    })

This is a lot of repetitive boilerplate, and is something the framework should be able to take care of in a more succint manner.

Note: My cors setup here isn't 100% correct and shound't be used as a reference.

Netherdrake commented 9 years ago

I found a way how to avoid having to set options:

    // CORS Middleware
    app.Use(func(ctx *neo.Ctx, next neo.Next) {
        if origin := ctx.Req.Header.Get("Origin"); origin != "" {
            ctx.Res.Header.Set("Access-Control-Allow-Origin", origin)
            ctx.Res.Header.Set("Access-Control-Allow-Credentials", "true")
            ctx.Res.Header.Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
            ctx.Res.Header.Set("Access-Control-Allow-Headers",
                "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
        }
        // Stop here if its Preflighted OPTIONS request
        if ctx.Req.Method == "OPTIONS" {
            ctx.Res.Raw([]byte(""), http.StatusOK)
            return
        }
        // back to neo
        next()
    })

Still, some built in support would be nice.

ivpusic commented 9 years ago

You are totally right. Thank you for pointing out.

I just added support for wildcards, you can check docs here (Wildcards section) http://ivpusic.github.io/neo/tutorials/2015/01/22/routing.html

I hope so this will help you.

ivpusic commented 9 years ago

I also created neo-cors package. https://github.com/ivpusic/neo-cors

Netherdrake commented 9 years ago

Wow, you are awesome!