diff options
Diffstat (limited to 'src/guff')
-rw-r--r-- | src/guff/api-content-type.cr | 12 | ||||
-rw-r--r-- | src/guff/api-handler.cr | 154 | ||||
-rw-r--r-- | src/guff/api-methods.cr | 140 |
3 files changed, 163 insertions, 143 deletions
diff --git a/src/guff/api-content-type.cr b/src/guff/api-content-type.cr new file mode 100644 index 0000000..9b6c74a --- /dev/null +++ b/src/guff/api-content-type.cr @@ -0,0 +1,12 @@ +module Guff + module APIContentType + CONTENT_TYPES = { + "development": "text/html; charset=utf-8", + "production": "application/json; charset=utf8", + } + + private def get_content_type + CONTENT_TYPES[@model.config["environment"]] + end + end +end diff --git a/src/guff/api-handler.cr b/src/guff/api-handler.cr index 3192447..dce351f 100644 --- a/src/guff/api-handler.cr +++ b/src/guff/api-handler.cr @@ -1,5 +1,6 @@ require "json" require "./handler" +require "./api-methods" private macro define_method_calls(hash) case namespace @@ -25,64 +26,8 @@ end module Guff class APIHandler < Handler - API = { - "post": { - "get_posts": { - text: "Get posts matching query.", - - args: { - "q": { - text: "Search string.", - type: :text, - required: false, - default: "", - }, - - "page": { - text: "Page number", - type: :int, - required: false, - default: "1", - }, - - "tags": { - text: "Comma-separated list of tags (union)", - type: :tags, - required: false, - default: "1", - }, - - "sort": { - text: "Sort order of results", - type: :sort, - required: false, - default: "date,desc", - }, - }, - }, - }, - - "test": { - "version": { - text: "Get version", - }, - - "get_posts": { - text: "Test get posts", - }, - - "error": { - text: "Test error response", - }, - } - } - - TYPE_CHECKS = { - text: /.*/, - int: /^\d+$/, - tags: /^[a-z0-9_,-]+$/, - sort: /^[a-z0-9_]+,(?:asc|desc)$/, - } + include APIMethods + include APIContentType PATH_RE = %r{ ^/api @@ -109,54 +54,6 @@ module Guff $ }mx - CONTENT_TYPES = { - "development": "text/html; charset=utf-8", - "production": "application/json; charset=utf8", - } - - private def get_content_type - CONTENT_TYPES[@model.config["environment"]] - end - - private def get_method_args( - params : HTTP::Params, - namespace : String, - method : String - ) - return {} of String => String unless ( - API[namespace]? && - API[namespace][method] && - API[namespace][method][:args]? - ) - - # get method args - args = API[namespace][method][:args] as \ - Hash(String, Hash(Symbol, String | Symbol | Bool)) - - args.keys.reduce({} of String => String) do |r, arg_name| - arg_data = args[arg_name] as Hash(Symbol, String|Symbol|Bool) - - # check for required parameter - if arg_data[:required] && !params.has_key?(arg_name) - raise "missing required parameter: %s" % [arg_name] - end - - # get value - val = params.fetch(arg_name, arg_data[:default] as String) - - # check value - if !TYPE_CHECKS[arg_data[:type]].match(val) - raise "invalid parameter format: %s" % [arg_name] - end - - # add value to result - r[arg_name] = val - - # return result - r - end - end - def call(context : HTTP::Server::Context) if md = (context.request.path || "").match(PATH_RE) if md["namespace"]? @@ -176,11 +73,18 @@ module Guff namespace : String, method : String ) + # set response type context.response.content_type = get_content_type # method call json = begin - # equivalent to send("do_#{namespace}_#{method}".intern, context) + # + # 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, @@ -209,41 +113,5 @@ module Guff context.response.content_type = page.content_type context.response.puts page end - - ################ - # post methods # - ################ - - private def do_post_get_posts( - context : HTTP::Server::Context, - args : Hash(String, String) - ) - [{foo: "bar"}, {foo: "asdf"}].to_json - end - - ################ - # test methods # - ################ - - private def do_test_version( - context : HTTP::Server::Context, - args : Hash(String, String) - ) - {version: Guff::VERSION}.to_json - end - - private def do_test_get_posts( - context : HTTP::Server::Context, - args : Hash(String, String) - ) - [{foo: "bar"}, {foo: "asdf"}].to_json - end - - private def do_test_error( - context : HTTP::Server::Context, - args : Hash(String, String) - ) - raise "some random error" - end end end diff --git a/src/guff/api-methods.cr b/src/guff/api-methods.cr new file mode 100644 index 0000000..dc0e1e8 --- /dev/null +++ b/src/guff/api-methods.cr @@ -0,0 +1,140 @@ +require "json" +require "./handler" + +module Guff + module APIMethods + API = { + "post": { + "get_posts": { + text: "Get posts matching query.", + + args: { + "q": { + text: "Search string.", + type: :text, + required: false, + default: "", + }, + + "page": { + text: "Page number", + type: :int, + required: false, + default: "1", + }, + + "tags": { + text: "Comma-separated list of tags (union)", + type: :tags, + required: false, + default: "1", + }, + + "sort": { + text: "Sort order of results", + type: :sort, + required: false, + default: "date,desc", + }, + }, + }, + }, + + "test": { + "version": { + text: "Get version", + }, + + "get_posts": { + text: "Test get posts", + }, + + "error": { + text: "Test error response", + }, + } + } + + TYPE_CHECKS = { + text: /.*/, + int: /^\d+$/, + tags: /^[a-z0-9_,-]+$/, + sort: /^[a-z0-9_]+,(?:asc|desc)$/, + } + + private def get_method_args( + params : HTTP::Params, + namespace : String, + method : String + ) + return {} of String => String unless ( + API[namespace]? && + API[namespace][method] && + API[namespace][method][:args]? + ) + + # get method args + args = API[namespace][method][:args] as \ + Hash(String, Hash(Symbol, String | Symbol | Bool)) + + args.keys.reduce({} of String => String) do |r, arg_name| + arg_data = args[arg_name] as Hash(Symbol, String|Symbol|Bool) + + # check for required parameter + if arg_data[:required] && !params.has_key?(arg_name) + raise "missing required parameter: %s" % [arg_name] + end + + # get value + val = params.fetch(arg_name, arg_data[:default] as String) + + # check value + if !TYPE_CHECKS[arg_data[:type]].match(val) + raise "invalid parameter format: %s" % [arg_name] + end + + # add value to result + r[arg_name] = val + + # return result + r + end + end + + ################ + # post methods # + ################ + + private def do_post_get_posts( + context : HTTP::Server::Context, + args : Hash(String, String) + ) + [{foo: "bar"}, {foo: "asdf"}].to_json + end + + ################ + # test methods # + ################ + + private def do_test_version( + context : HTTP::Server::Context, + args : Hash(String, String) + ) + {version: Guff::VERSION}.to_json + end + + private def do_test_get_posts( + context : HTTP::Server::Context, + args : Hash(String, String) + ) + [{foo: "bar"}, {foo: "asdf"}].to_json + end + + private def do_test_error( + context : HTTP::Server::Context, + args : Hash(String, String) + ) + raise "some random error" + end + end +end |