diff --git a/.env.development b/.env.development index 8bd0b90..48e909f 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,2 @@ -DATABASE_URL=sqlite3://./sqlite/data.db?journal_mode=wal&synchronous=normal +DATABASE_URL=sqlite3://./sqlite/data.db?journal_mode=wal&synchronous=normal&foreign_keys=true APP_URL=http://localhost:4000 diff --git a/README.md b/README.md index df0b6d7..a48241a 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,13 @@ TODO: Write usage instructions here ```bash DATABASE_URL=sqlite3://./sqlite/data.db micrate up -crystal run url-shortener.cr +shards run url-shortener ``` ## Build ```bash -crystal build url-shortener.cr --release --progress -ENV=production ./url-shortener +shards build ``` ## Contributing diff --git a/app/lib/errors.cr b/app/lib/errors.cr index 46f2327..287b48a 100644 --- a/app/lib/errors.cr +++ b/app/lib/errors.cr @@ -9,6 +9,21 @@ module App end end + class UnauthorizedException < Kemal::Exceptions::CustomException + def initialize(context) + context.response.status_code = 401 + super(context) + end + end + + class ForbiddenException < Kemal::Exceptions::CustomException + def initialize(context) + context.response.status_code = 403 + context.response.print({ "error" => "Access not allowed" }.to_json) + super(context) + end + end + class NotFoundException < Kemal::Exceptions::CustomException def initialize(context) context.response.status_code = 404 diff --git a/app/middlewares/auth.cr b/app/middlewares/auth.cr new file mode 100644 index 0000000..915f830 --- /dev/null +++ b/app/middlewares/auth.cr @@ -0,0 +1,19 @@ +module App::Middlewares + class Auth < Kemal::Handler + include App::Models + include App::Lib + + exclude ["/api/ping", "/:slug"] + + def call(env) + return call_next(env) if exclude_match?(env) + begin + user = Database.get_by!(User, api_key: env.request.headers["X-Api-Key"]) + env.set "user", user + rescue exception + raise App::UnauthorizedException.new(env) + end + call_next(env) + end + end +end diff --git a/app/routes.cr b/app/routes.cr index 8bf4b82..aed584e 100644 --- a/app/routes.cr +++ b/app/routes.cr @@ -2,6 +2,12 @@ require "./controllers/**" module App before_all do |env| + env.response.headers["Access-Control-Allow-Origin"] = "*" + env.response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" + env.response.headers["Access-Control-Allow-Headers"] = "Content-Type, Accept, X-Api-Key" + end + + after_all do |env| env.response.content_type = "application/json" end @@ -13,8 +19,8 @@ module App Controllers::Link::Index.new.call(env) end - get "/api/links/:id" do |env| - Controllers::Link::Read.new.call(env) + get "/api/links" do |env| + Controllers::Link::All.new.call(env) end post "/api/links" do |env| diff --git a/bruno/Delete Link.bru b/bruno/Delete Link.bru index 59ae339..be7c1f8 100644 --- a/bruno/Delete Link.bru +++ b/bruno/Delete Link.bru @@ -5,7 +5,7 @@ meta { } delete { - url: {{baseUrl}}/api/links/ad9fb116-9e5b-45b7-b272-5285b579d2e4 + url: {{baseUrl}}/api/links/995c5abf-2506-4d3e-b664-f2168c34b936 body: none auth: none } diff --git a/bruno/Get Link.bru b/bruno/Get Link.bru deleted file mode 100644 index d0c4dca..0000000 --- a/bruno/Get Link.bru +++ /dev/null @@ -1,11 +0,0 @@ -meta { - name: Get Link - type: http - seq: 3 -} - -get { - url: {{baseUrl}}/api/links/d017c966-c28b-4c4c-a83e-97bce81ee6e7 - body: none - auth: none -} diff --git a/bruno/Index Link.bru b/bruno/Index Link.bru index b44d3a3..f1d9872 100644 --- a/bruno/Index Link.bru +++ b/bruno/Index Link.bru @@ -1,11 +1,11 @@ meta { name: Index Link type: http - seq: 4 + seq: 5 } get { - url: {{baseUrl}}/3JQV8w + url: {{baseUrl}}/HkIN8g body: none auth: none } diff --git a/bruno/Update Link.bru b/bruno/Update Link.bru index 381b108..6f62818 100644 --- a/bruno/Update Link.bru +++ b/bruno/Update Link.bru @@ -1,11 +1,11 @@ meta { name: Update Link type: http - seq: 5 + seq: 6 } put { - url: {{baseUrl}}/api/links/0da9dc9d-c56c-4d4e-942e-1ebf05ed7090 + url: {{baseUrl}}/api/links/b5a0112d-49e6-4bc9-bd2b-6d5cc10cd5d2 body: json auth: none }