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 }}" params = case context.request.method when "GET" context.request.query_params when "POST" HTTP::Params.parse((context.request.body || "") as String) else raise "unsupported method" end do_{{ namespace.id }}_{{ method }}(context, get_method_args( 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 (?: / (?[a-z0-9_-]+) / (?[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_api_call(context, md["namespace"], md["method"]) else # api index do_api_docs(context) end else call_next(context) end end private def do_api_call( context : HTTP::Server::Context, namespace : String, method : String ) # default to success ok = true # 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, get_users, set_user, ], }) rescue e # set error ok = false # log backtrace # FIXME puts e.inspect_with_backtrace # return error to user { "error": e.to_s }.to_json end # send type, code, and body context.response.content_type = get_content_type context.response.status_code = ok ? 200 : 400 context.response << json end private def do_api_docs(context : HTTP::Server::Context) Guff::APIDocsHTMLView.run(context) end end