jester icon indicating copy to clipboard operation
jester copied to clipboard

middleware support

Open niv opened this issue 8 years ago • 10 comments

Request for feature: middlewares, much like other frameworks do them. The basic principle is:

You have a chain of handler instances, each responding to a method that takes, at the very least, the request, a way to respond to the request, and the next handler as parameters.

They are called in sequence; each handler is responsible for calling into the next one. This results in a nested call chain, and allows each registered handler to:

  • stop propagating the request and return data to the client - for example, to keep auth&auth in one place, or to add api/request throttling
  • modify the request or environment (for example, handle content-type and transform the body data from/to json, and handle errors pertaining to that transparent to the framework user)

And many more usecases. A good search term for more information and examples would be "rack middleware".

niv avatar Apr 05 '16 18:04 niv

Superset of #51? Most of the required functionality should be there if #51 was fixed, then it's just a matter of piecing it together as you want to.

PMunch avatar Oct 27 '17 06:10 PMunch

After some discussion with @dom96 about the best methods of achieving packageable middleware, we are both at a loss for how it can be done currently and may need to consider adding additional functionality.

As can be seen in https://github.com/dom96/jester/blob/master/tests/alltest.nim#L165 there is the before feature to get roughly the functionality we're looking for, however, it's not very extensible and wouldn't work well as far as packaging is concerned.

Per @dom96 https://github.com/dom96/jester/blob/master/jester.nim#L48 may be hookable to allow middleware to add it's own match procs, alongside register to append (will need changes to prepend). How this could be optionally applied to only desired routes is yet to be seen.

ImVexed avatar Nov 15 '18 21:11 ImVexed

Best thing to do in these kinds of situations is to see how other frameworks do it :)

dom96 avatar Nov 17 '18 21:11 dom96

I think you should stop thinking about how to mangle individual routes/matches. The middleware I thought would be useful would simply wrap the request at a lower level, like other implementations (cough rack cough) do it. Route matching is a different layer. IMHO, mingling the two adds confusion and needless complexity.

Apologies for pseudocode. You get the idea I hope.

proc myMiddleWare(r: Req, o: Resp, m: Next): .. =
  if r.origin.wellLiked():
    let before = time()
    o.setCookie("hi", "there")
    m.call(r, o)
    let after = time()
    o.setHeader("x-benchmark", after - before)
  else:
    info "Dropping ", r

jester.middlewareStack.insert myMiddleWare, 0

That said, I gave up on this for my previous use case so don't rush on my account.

niv avatar Nov 17 '18 22:11 niv

I feel route matching/selective application of the middleware to desired routes is arguably the second most important feature of middleware short of its primary purpose of executing logic before the actual route's main logic.

What is the use of a login session manager/jwt middleware if even the login/register routes are protected?

I may be misunderstanding your previous comment, however, I think one potential solution would be to do it similarly to how Go's iris framework handles applying middleware to individual groups of api endpoints. Where in this example v1 has no middleware, but v2 has a jwt middleware:

func main() {
	app := iris.Default()

	// Simple group: v1.
	v1 := app.Party("/v1")
	{
		v1.Post("/login", loginEndpoint)
		v1.Post("/submit", submitEndpoint)
		v1.Post("/read", readEndpoint)
	}

	// Simple group: v2.
	v2 := app.Party("/v2", jwtHandler.Serve)
	{
		v2.Post("/login", loginEndpoint)
		v2.Post("/submit", submitEndpoint)
		v2.Post("/read", readEndpoint)
	}

	app.Run(iris.Addr(":8080"))
} 

I'm not sure how we'd do it syntactically in jester but maybe something to the tune of this:

import jester
import authmiddleware

router api:
  uses: authmiddleware.authenticate
  get "/test":
    resp "I'm authenticated!"

routes:
  extend api, "/api"

ImVexed avatar Nov 17 '18 23:11 ImVexed

Lack of middleware is a serious bane to the development experience when utilizing Jester.

If you look at other web micro-frameworks, you'll notice a great deal of them end up having packages developed that integrate at the middleware level. This helps promote the growth of tooling around those libraries.

shawnd avatar Jan 23 '20 23:01 shawnd

I'm wondering how to add JWT into Jester, I can imagine the best way is through middleware layer, or does anybody know any of nim web app server supports the feature out of box?

geohuz avatar Jul 24 '20 06:07 geohuz

You can already make use of libraries like nim-jwt fairly easily from Jester (there is at least one other library for this too). If you want middleware then you can check out @JohnAD's efforts: https://github.com/dom96/jester/pull/227

dom96 avatar Jul 24 '20 09:07 dom96

Thanks @dom96 !

@geohuz,

JWT is a fairly generic tool. Is there a general purpose for JWT you would like to see supported in a middleware package? Such as user authentication? (Such as seen for Python Django with https://jpadilla.github.io/django-rest-framework-jwt/ ?) Or for access to external service by your web site (such as Zapier?)

JohnAD avatar Jul 25 '20 18:07 JohnAD

@JohnAD , If you look at python sanic framework, they have jwt as middleware supported very well.

geohuz avatar Aug 07 '20 02:08 geohuz