aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/guff/api-content-type.cr12
-rw-r--r--src/guff/api-handler.cr154
-rw-r--r--src/guff/api-methods.cr140
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