discord-gophers / goapi-gen

This package contains a set of utilities for generating Go boilerplate code for services based on OpenAPI 3.0 API definitions
Apache License 2.0
132 stars 12 forks source link

Middleware Ordering #67

Closed tiehm closed 2 years ago

tiehm commented 2 years ago

We really need documentation on how middleware is processed, as I now found out. The last middleware is the one which is called first, so:

x-go-middlewares: [auth,something-that-needs-auth]

will run something-that-needs-auth first. Ordering is intact, however, you would really think it is the other way around.

hhhapz commented 2 years ago

I have a current service with the following middleware:

x-go-middlewares: ["foo", "bar"]

And the generated code is as such:

var handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.ModifyOtherUser(w, r, params)
})

// Operation specific middleware
handler = siw.Middlewares["foo"](handler).ServeHTTP
handler = siw.Middlewares["bar"](handler).ServeHTTP

handler(w, r.WithContext(ctx))

These are called in the order I expect, foo first, then bar. Can you please show us what you are using?

tiehm commented 2 years ago

The ordering within the generated code is "correct". However in the example you provided, bar is called before foo.

hhhapz commented 2 years ago
  /with-tagged-middleware:
    summary: GetWithTaggedMiddleware
    x-go-middlewares: [pathMiddleware]
    get:
      operationId: getWithTaggedMiddleware
      responses:
        '200':
          $ref: "#/components/responses/SimpleResponse"
    post:
      x-go-middlewares: [operationMiddleware, operationMiddleware2]
      operationId: postWithTaggedMiddleware
      responses:
        '200':
          $ref: "#/components/responses/SimpleResponse"
func TestMiddlewareCalledWithOrder(t *testing.T) {
    var order []string
    mw := map[string]func(http.Handler) http.Handler{
        "pathMiddleware": func(h http.Handler) http.Handler {
            t.Log("first")
            order = append(order, "first")
            return h
        },
        "operationMiddleware": func(h http.Handler) http.Handler {
            t.Log("second")
            order = append(order, "second")
            return h
        },
        "operationMiddleware2": func(h http.Handler) http.Handler {
            t.Log("third")
            order = append(order, "third")
            return h
        },
    }

    h := Handler(&m, WithMiddlewares(mw))

    s := httptest.NewServer(h)
    defer s.Close()

    _, err := http.DefaultClient.Post(s.URL+"/with-tagged-middleware", "", nil)
    assert.Nil(t, err)
    assert.Equal(t, []string{"first", "second", "third"}, order)
}
$ go test -v ./...
=== RUN   TestMiddlewareCalledWithOrder
    server_test.go:98: first
    server_test.go:103: second
    server_test.go:108: third
--- PASS: TestMiddlewareCalledWithOrder (0.00s)
hhhapz commented 2 years ago

These are all called exactly in the order I would expect them to be.

Karitham commented 2 years ago

Cleaning up issues to keep the actives one up top