hatch-sh / hatch

🐣 Easy deployment of static websites to Amazon Web Services
https://hatch.sh
5 stars 0 forks source link

Add support for nested routes #7

Open mads-hartmann opened 7 years ago

mads-hartmann commented 7 years ago

Currently the API only supports a flat structure of folder which are used to generate the endpoints. I think it would be much nicer to allow people to specify arbitrarily deep endpoints by using annotations in the source code instead. E.g.

@hatch.url('foo/bar', methods=['GET'])
def get():
    return 'Hi There'

The tasks consists roughly of the following parts

mads-hartmann commented 7 years ago

@skovhus If you're up for a bit of a larger task I think this might be a fun one.

mads-hartmann commented 7 years ago

@skovhus We could ignore the 'nested route' part of it for now to make the task smaller and then simple have this task be to support routes from annotations. E.g. @hatch.url('/echo', methods=['GET']) rather than based on the folder names

skovhus commented 7 years ago

Wonder how we would do this for other languages like JS.

mads-hartmann commented 7 years ago

Yeah, I was thinking about that. I played around a bit with an example in Reason. My best idea right now is that we'll have to provide three things

  1. A tiny library for expressing a service in the language. This is the user facing part.
  2. A script in the language for pretty-printing the service into json or something that python can understand in order to build the python API object.
  3. a script in the language for starting the service in development mode.

Here's my example in Reason (which probably doesn't work). This is the "library" that the user imports

module Hatch = {

    type context = {
        what: string
    };

    type request = {
        httpMethod: string,
        body: string
    };

    type callback = unit => string => unit;

    /* TODO: This is the node specific type. No how we'd like to represent it in reason*/
    type handler = request => context => callback => unit;

    type endpoint =
      | Get string handler
      | Post string handler;

    type service = {
        name: string,
        endpoints: list endpoint
    };
};

Then they have a handler somewhere

let hello = fun (request: Hatch.request) (context: Hatch.context) callback => {
    ignore context; /* Smart way to ignore unused variable. */
    let response = request.body;
    callback () ("How are you?! " ^ response);
};

And finally they describe their service

let service: Hatch.service  = {
    name: "reason-example",
    endpoints: [
        Hatch.Get "/hello" hello
    ]
};

We would then need to write a little reason script that we invoke from python that imports their service and pretty-prints the service variable into json.

Similarly we would need to write a little reason script that imports their service and "runs" it.

skovhus commented 7 years ago

Nice!

pretty-prints the service variable into json.

This is for submitting it to AWS?

mads-hartmann commented 7 years ago

I definitely don't have all the details ready but it seems very doable to me :)

mads-hartmann commented 7 years ago

It might be that a similar approach is nicer in python as well. Now that I think of it this is actually what Tornado does 😄

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

You have your service description as a tornado.web.Application object that you can then later choose to run

skovhus commented 7 years ago

A wrapping object describing the routes and handlers seems generic. And useable in multiple languages.

Let us find a simple solutions that isn't too custom. Would be nice if hatch were fairly transparent. : )