spirit-js / spirit

Modern modular library for building web applications
http://spirit.function.run
ISC License
244 stars 18 forks source link

Question: How is the API of Spirit better than koa2? #13

Open irisjae opened 7 years ago

irisjae commented 7 years ago

I really appreciate the nice little project over here. But besides performance, isnt the API of spirit essentially similar to koa2? in spirit, middleware looks like (handler) => (request) => handler(request) which is similar, though more smooth, than koa2's (ctx/* == request*/, next) => next() I can't see advantages in the route definition, since if you're returning a response map, you're transmitting HTTP information too. e.g. a route in spirit might be route .define([ route .get ("/", [], () => { return "Hello World!" }) ]) whereas in koa2 i might do

var route = () => { return "Hello World!" };
app .use ((ctx, next) => { ctx .body = route (/*or whatever dependencies need be injected*/); return next (); })

I really enjoy the simple API of spirit, but I feel it might have made a bad distinction between routes and middleware; when routes have to return response maps, i feel that wouldve more elegantly been made as a middleware by default. Even more impure seems to be the dependency injection in the request; once again I feel like its the job of a middleware. If spirit aims to be pure, lets go all pure!

FlorianWendelborn commented 7 years ago

I don't really like the middleware part, but for me personally the reason to use spirit is that it's predictable, easily testable and "without magic". I usually use the return {status, body, headers} variant of the API since IMO it's the most obvious way to respond to an HTTP request.

hnry commented 7 years ago

@irisjay Hey thanks for the questions, they are pretty popular ones I've seen.

But besides performance, isnt the API of spirit essentially similar to koa2 in spirit, middleware looks like...

They aren't (at least since I last looked at koa). They do seem similar, but the distinction is, you can't test the koa version as easily (though there's probably helper tools to make it easy).

From what I recall next() is just returning undefined. While in spirit calling handler(request) actually returns a value (promise of response). So if you're going to test it, it's literally just a javascript function.

// test a middleware
const request = { url: ..., method: "GET" } // <- requests are just simple objects, no need for a mock
const returned_value = middleware(request)
expect(returned_value).toBe(...)

Also instead of doing handler() which is similar to next() we actually pass the request along, so request isn't something that's hanging out of scope or being "injected" as a context in the case of koa. Basically the "next" handler is just a javascript function too that we call normally by passing arguments and grabbing it's return.

Really what middleware in spirit does is just wrap functions together to compose them. Similar to doing response = a(b(c(request))) where a, b, c are middlewares.

There is no magic in how spirit works compared to express, koa, hapi, etc. It's simply just a function calling another function passing along a input paramter (request) and returning a value (response)

I don't care about testing, or it doesn't seem more readable to me, so what else?

There's other practical benefits. Since the implementation is just javascript, nothing fancy, not huge object manipulating or object based routing...

For example making a "time travel" addon is possible (similar to redux / elm where you can see a request or response transform along every point to see what's going on).

Even more impure seems to be the dependency injection in the request; once again I feel like its the job of a middleware. If spirit aims to be pure, lets go all pure!

The dependency injection is just doing pattern matching

let {url, method} = request // cherry pick arguments from request
fn(url, method)            // call our function with the arguments

Middleware and route functions in spirit can seem similar because by design they were both meant to be just javascript functions.

Just a route function can be made more simple (through it's argument and return) and we can further strip away the idea of 'http' from them. And for it to really be just any other function.

The difference from this and koa, is this is by design in spirit, and in koa you have to wrap it to achieve this.

In spirit don't think of there being "routes" or a "route function", it's just a normal function you're defining how / when to be called.

when routes have to return response maps, i feel that wouldve more elegantly been made as a middleware by default

I don't think you should feel that way. I don't think of 'response maps' as a res object in express or koa, I think of it as just data being passed. Since it isn't tied directly to res or some context, you have a lot of options to refactor and keep things DRY depending on how you want it.

Hope it helps, sorry for it being long.

FlorianWendelborn commented 7 years ago

request isn't something that's hanging out of scope or being "injected" as a context in the case of koa — @hnry

This isn't true anymore, koa now just passes ctx to all functions.