Browse Source

Lots of comments in web

Getty Ritter 4 years ago
parent
commit
c8a37fa3ad
1 changed files with 39 additions and 3 deletions
  1. 39 3
      lc/web.py

+ 39 - 3
lc/web.py

@@ -53,19 +53,36 @@ class Endpoint:
         return self.user
 
     def route(self, *args, **kwargs):
+        """Forward to the appropriate routing method"""
         try:
             if flask.request.method == "POST":
+                # all POST methods are "API methods": if we want to
+                # display information in response to a post, then we
+                # should redirect to the page where that information
+                # can be viewed instead of returning that
+                # information. (I think.)
                 return flask.jsonify(self.api_post(*args, **kwargs))
             elif (
                 flask.request.method in ["GET", "HEAD"]
                 and flask.request.content_type == "application/json"
             ):
+                # Here we're distinguishing between an API GET (i.e. a
+                # client trying to get JSON data about an endpoint)
+                # versus a user-level GET (i.e. a user in a browser.)
+                # I like using the HTTP headers to distinguish these
+                # cases, while other APIs tend to have a separate /api
+                # endpoint to do this.
                 return flask.jsonify(self.api_get(*args, **kwargs))
+        # if an exception arose from an "API method", then we should
+        # report it as JSON
         except e.LCException as exn:
             return ({"status": exn.http_code(), "error": str(exn)}, exn.http_code())
+        # also maybe we tried to redirect, so just do that
         except e.LCRedirect as exn:
             return flask.redirect(exn.to_path())
 
+        # if we're here, it means we're just trying to get a typical
+        # HTML request.
         try:
             return self.html(*args, **kwargs)
         except e.LCException as exn:
@@ -77,16 +94,35 @@ class Endpoint:
             return flask.redirect(exn.to_path())
 
 
-def endpoint(route):
-    def do_endpoint(cls):
+# Decorators result in some weird code in Python, especially 'cause it
+# doesn't make higher-order functions terse. Let's break this down a
+# bit. This out method, `endpoint`, takes the route...
+def endpoint(route: str):
+    """Route an endpoint using our semi-smart routing machinery"""
+    # but `endpoint` returns another function which is going to be
+    # called with the result of the definition after it. The argument
+    # to what we're calling `do_endpoint` here is going to be the
+    # class object defined afterwards.
+    def do_endpoint(endpoint_class):
+        # we'll just make that explicit here
+        assert Endpoint in endpoint_class.__bases__
+        # finally, we need a function that we'll give to Flask in
+        # order to actually dispatch to. This is the actual routing
+        # function, which is why it just creates an instance of the
+        # endpoint provided above and calls the `route` method on it
         def func(*args, **kwargs):
-            return cls().route(*args, **kwargs)
+            return endpoint_class().route(*args, **kwargs)
 
+        # use reflection over the methods defined by the endpoint
+        # class to decide if it needs to accept POST requests or not.
         methods = ["GET"]
         if "api_post" in dir(cls):
             methods.append("POST")
 
+        # this is just for making error messages nicer
         func.__name__ = cls.__name__
+
+        # finally, use the Flask routing machinery to register our callback
         return c.app.route(route, methods=methods)(func)
 
     return do_endpoint