diff options
-rw-r--r-- | src/guff/api-handler.cr | 122 | ||||
-rw-r--r-- | src/guff/handler.cr | 3 | ||||
-rw-r--r-- | src/guff/handlers.cr | 62 | ||||
-rw-r--r-- | src/guff/model.cr | 1 | ||||
-rw-r--r-- | src/guff/run.cr | 2 | ||||
-rw-r--r-- | src/guff/server.cr | 31 | ||||
-rw-r--r-- | src/guff/test-handler.cr | 14 |
7 files changed, 211 insertions, 24 deletions
diff --git a/src/guff/api-handler.cr b/src/guff/api-handler.cr new file mode 100644 index 0000000..7928d3c --- /dev/null +++ b/src/guff/api-handler.cr @@ -0,0 +1,122 @@ +require "./handler" + +module Guff + record APIContext, + context : HTTP::Server::Context, + model : Model + + API = { + "posts": { + "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", + }, + }, + + method: ->(c : APIContext) { + "get_posts" + } + }, + }, + } + + API_PATH_RE = %r{ + ^/api + + (?: + # method call + (?: + / + (?<namespace>[a-z0-9_-]+) + / + (?<method>[a-z0-9]+) + ) + + | + + # index.html + /(?:index(?:\.html|)|) + + | + + # implicit index (no trailing slash) + ) + + $ + }mx + + class APIHandler < Handler + def call(context : HTTP::Server::Context) + if md = (context.request.path || "").match(API_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 + ) + # method call +# +# fn = API[namespace][method][:method] as Proc(APIContext, String) +# context.response.puts fn.call(APIContext.new(context, @model)) +# + page = HTMLPageView.new( + "TODO: API Call", + "<p>API Call: namespace = %s, call = %s</p>" % [ + namespace, + method + ] + ) + + context.response.content_type = page.content_type + context.response.puts page + end + + private def do_docs(context : HTTP::Server::Context) + page = HTMLPageView.new( + "API Documentation", + "<p>API Documentation</p>" + ) + + context.response.content_type = page.content_type + context.response.puts page + end + end +end diff --git a/src/guff/handler.cr b/src/guff/handler.cr index e665585..125e7e7 100644 --- a/src/guff/handler.cr +++ b/src/guff/handler.cr @@ -3,9 +3,8 @@ require "http/server" module Guff class Handler < ::HTTP::Handler getter :model - getter :config - def initialize(@model : Model, @config : Config) + def initialize(@model : Model) end def call(context : HTTP::Server::Context) diff --git a/src/guff/handlers.cr b/src/guff/handlers.cr new file mode 100644 index 0000000..4ebeae7 --- /dev/null +++ b/src/guff/handlers.cr @@ -0,0 +1,62 @@ +require "http/server" +require "./config" +require "./model" +require "./blog-handler" + +module Guff + module Handlers + HANDLERS = [{ + # TODO: add production error handler + env: %w{development}, + init: ->(model : Model) { + HTTP::ErrorHandler.new as HTTP::Handler + }, + }, { + init: ->(model : Model) { + HTTP::LogHandler.new as HTTP::Handler + }, + }, { + init: ->(model : Model) { + HTTP::DeflateHandler.new as HTTP::Handler + }, + }, { + env: %w{development}, + init: ->(model : Model) { + TestHandler.new(model) as HTTP::Handler + }, + }, { + init: ->(model : Model) { + APIHandler.new(model) as HTTP::Handler + }, + }, { + init: ->(model : Model) { + BlogHandler.new(model) as HTTP::Handler + }, + }, { + init: ->(model : Model) { + SlugHandler.new(model) as HTTP::Handler + }, + }, { + init: ->(model : Model) { + HTTP::StaticFileHandler.new(model.config["public"]) as HTTP::Handler + }, + }, { + init: ->(model : Model) { + NotFoundHandler.new(model) as HTTP::Handler + }, + }] + + def self.get(model : Model) : Array(HTTP::Handler) + HANDLERS.select { |h| + if h.has_key?(:env) + (h[:env] as Array(String)).includes?(model.config["environment"]) + else + true + end + }.map { |h| + init = (h[:init] as Proc(Model, HTTP::Handler)) + init.call(model) + } + end + end +end diff --git a/src/guff/model.cr b/src/guff/model.cr index 370229c..0bc0e78 100644 --- a/src/guff/model.cr +++ b/src/guff/model.cr @@ -1,5 +1,6 @@ module Guff class Model + getter :config getter :db def initialize(@config : Config) diff --git a/src/guff/run.cr b/src/guff/run.cr index 2b7e966..90afbae 100644 --- a/src/guff/run.cr +++ b/src/guff/run.cr @@ -11,6 +11,6 @@ module Guff model = Model.new(config) # create and run server - Server.run(model, config) + Server.run(model) end end diff --git a/src/guff/server.cr b/src/guff/server.cr index bc4494c..1d87db7 100644 --- a/src/guff/server.cr +++ b/src/guff/server.cr @@ -1,41 +1,30 @@ require "http/server" require "./config" require "./model" -require "./blog-handler" +require "./handlers" module Guff class Server - def self.run(model : Model, config : Config) - new(model, config).run + def self.run(model : Model) + new(model).run end - def initialize(@model : Model, @config : Config) + def initialize(@model : Model) # create server @server = HTTP::Server.new( - config["host"], - config["port"].to_i, - get_handlers(model, config) + @model.config["host"], + @model.config["port"].to_i, + get_handlers(@model) ) end def run - puts "listening on %s:%s" % %w{host port}.map { |k| @config[k] } + puts "listening on %s:%s" % %w{host port}.map { |k| @model.config[k] } @server.listen end - private def get_handlers( - model : Model, - config : Config - ) : Array(HTTP::Handler) - @handlers ||= [ - HTTP::ErrorHandler.new, - HTTP::LogHandler.new, - HTTP::DeflateHandler.new, - BlogHandler.new(model, config), - SlugHandler.new(model, config), - HTTP::StaticFileHandler.new(config["public"]), - NotFoundHandler.new(model, config), - ] + private def get_handlers(model : Model) : Array(HTTP::Handler) + @handlers ||= Handlers.get(model) end end end diff --git a/src/guff/test-handler.cr b/src/guff/test-handler.cr new file mode 100644 index 0000000..3856400 --- /dev/null +++ b/src/guff/test-handler.cr @@ -0,0 +1,14 @@ +require "./handler" + +module Guff + class TestHandler < Handler + def call(context : HTTP::Server::Context) + if ((context.request.path || "").match(/^\/test\//)) + context.response.content_type = "text/html" + context.response.puts "test" + else + call_next(context) + end + end + end +end |