aboutsummaryrefslogtreecommitdiff
path: root/src/guff/handlers/api.cr
diff options
context:
space:
mode:
Diffstat (limited to 'src/guff/handlers/api.cr')
-rw-r--r--src/guff/handlers/api.cr148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/guff/handlers/api.cr b/src/guff/handlers/api.cr
new file mode 100644
index 0000000..77606ae
--- /dev/null
+++ b/src/guff/handlers/api.cr
@@ -0,0 +1,148 @@
+require "json"
+require "../handler"
+require "../api/*"
+require "../views/html/api-docs"
+
+private macro define_method_calls(hash)
+ case namespace
+ {% for namespace, methods in hash %}
+ when "{{ namespace.id }}"
+ case method
+ {% for method in methods %}
+ when "{{ method }}"
+ do_{{ namespace.id }}_{{ method }}(context, get_method_args(
+ context.request.query_params,
+ "{{ namespace.id }}",
+ "{{ method.id }}"
+ )).to_json
+ {% end %}
+ else
+ raise "unknown method"
+ end
+ {% end %}
+ else
+ raise "unknown namespace"
+ end
+end
+
+class Guff::Handlers::APIHandler < Guff::Handler
+ include API::Methods
+ include API::ContentType
+ include API::Util
+ include API::PostAPI
+ include API::DirAPI
+ include API::FileAPI
+ include API::TagAPI
+ include API::SiteAPI
+ include API::TestAPI
+
+ PATH_RE = %r{
+ ^/api
+
+ (?:
+ # method call
+ (?:
+ /
+ (?<namespace>[a-z0-9_-]+)
+ /
+ (?<method>[a-z0-9_]+)
+ )
+
+ |
+
+ # index.html
+ /(?:index(?:\.html|)|)
+
+ |
+
+ # implicit index (no trailing slash)
+ )
+
+ $
+ }mx
+
+ def call(context : HTTP::Server::Context)
+ if md = (context.request.path || "").match(PATH_RE)
+ if md["namespace"]?
+ # method call
+ do_call(context, md["namespace"], md["method"])
+ else
+ # api index
+ do_docs(context)
+ end
+ else
+ call_next(context)
+ end
+ end
+
+ private def do_call(
+ context : HTTP::Server::Context,
+ namespace : String,
+ method : String
+ )
+ # set response type
+ context.response.content_type = get_content_type
+
+ # method call
+ json = begin
+ #
+ # macro expands to equivalent of the following for each
+ # namespace and method:
+ #
+ # args = get_method_args(context, namespace, method)
+ # send("do_#{namespace}_#{method}".intern, context, args)
+ #
+ define_method_calls({
+ post: [
+ get_posts,
+ add_post,
+ update_post,
+ remove_posts,
+ set_tags,
+ ],
+
+ dir: [
+ add,
+ remove,
+ ],
+
+ file: [
+ add,
+ remove,
+ ],
+
+ tag: [
+ get_tags,
+ remove_tags,
+ ],
+
+ site: [
+ add_site,
+ remove_sites,
+ set_default,
+ set_domains,
+ ],
+
+ test: [
+ version,
+ get_posts,
+ error,
+ ],
+ })
+ rescue e
+ # log backtrace
+ # FIXME
+ puts e.inspect_with_backtrace
+
+ # return error to user
+ { "error": e.to_s }.to_json
+ end
+
+ # send body
+ context.response.puts json
+ end
+
+ private def do_docs(context : HTTP::Server::Context)
+ Guff::APIDocsHTMLView.run(context)
+ end
+end