feat: delete link

This commit is contained in:
Juan Rodriguez
2024-05-13 10:23:20 +02:00
parent ded84e7fa5
commit 80feadfbd2
11 changed files with 86 additions and 34 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
DATABASE_URL=sqlite3://./sqlite/data.db
DATABASE_URL=sqlite3://./sqlite/data.db?journal_mode=wal&synchronous=normal
APP_URL=http://localhost:4000
+4 -3
View File
@@ -3,6 +3,7 @@
/bin/
/.shards/
*.dwarf
*.db
.env.*
url-shortener
.DS_Store
./sqlite/*
.env.production
+32 -20
View File
@@ -8,20 +8,16 @@ module App::Controllers::Link
include App::Lib
def call(env)
json_params = env.params.json.to_h
url = json_params.has_key?("url") ? json_params["url"] : nil
raise App::BadRequestException.new(env, {"url" => "Required field"}) if !url
body = parse_body(env, ["url"])
link = Link.new
link.id = UUID.v4.to_s
link.url = url.to_s
link.url = body["url"].to_s
link.slug = Random::Secure.urlsafe_base64(4)
changeset = Database.insert(link)
if !changeset.valid?
errors = {"errors" => map_changeset_errors(changeset.errors)}
raise App::UnprocessableEntityException.new(env, errors)
raise App::UnprocessableEntityException.new(env, map_changeset_errors(changeset.errors))
end
response = {"data" => App::Serializers::Link.new(link)}
@@ -36,7 +32,8 @@ module App::Controllers::Link
def call(env)
slug = env.params.url["slug"]
link = Database.get_by!(Link, slug: slug)
link = Database.get_by(Link, slug: slug)
raise App::NotFoundException.new(env) if !link
spawn do
link.click_counter = link.click_counter! + 1
@@ -47,18 +44,19 @@ module App::Controllers::Link
end
end
env.redirect link.url!
env.redirect link.url!, 301
end
end
class Get < App::Lib::BaseController
class Read < App::Lib::BaseController
include App::Models
include App::Lib
def call(env)
id = env.params.url["id"]
link = Database.get!(Link, id)
link = Database.get(Link, id)
raise App::NotFoundException.new(env) if !link
response = {"data" => App::Serializers::Link.new(link)}
response.to_json
@@ -71,20 +69,17 @@ module App::Controllers::Link
def call(env)
id = env.params.url["id"]
body = parse_body(env, ["url"])
json_params = env.params.json.to_h
url = json_params.has_key?("url") ? json_params["url"] : nil
raise App::BadRequestException.new(env, {"url" => "Required field"}) if !url
link = Database.get(Link, id)
raise App::NotFoundException.new(env) if !link
link = Database.get!(Link, id)
link.url = url.to_s
link.url = body["url"].to_s
link.click_counter = 0
changeset = Database.update(link)
if !changeset.valid?
errors = {"errors" => map_changeset_errors(changeset.errors)}
raise App::UnprocessableEntityException.new(env, errors)
raise App::UnprocessableEntityException.new(env, map_changeset_errors(changeset.errors))
end
response = {"data" => App::Serializers::Link.new(link)}
@@ -92,5 +87,22 @@ module App::Controllers::Link
end
end
# TODO: delete
class Delete < App::Lib::BaseController
include App::Models
include App::Lib
def call(env)
id = env.params.url["id"]
link = Database.get(Link, id)
raise App::NotFoundException.new(env) if !link
result = Database.raw_exec("DELETE FROM links WHERE id = (?)", link.id) # tempfix: Database.delete does not work
if result.rows_affected == 0
raise App::UnprocessableEntityException.new(env, { "id" => ["Row delete failed"] })
end
env.response.status_code = 204
end
end
end
+19 -1
View File
@@ -1,11 +1,29 @@
module App::Lib
abstract class BaseController
def map_changeset_errors(errors)
def map_changeset_errors(errors)
errors.reduce({} of String => Array(String)) do |memo, error|
memo[error[:field]] = memo[error[:field]]? || [] of String
memo[error[:field]] << error[:message]
memo
end
end
def parse_body(env, fields)
json_params = env.params.json.to_h
missing_fields = [] of String
fields.each do |field|
unless json_params.has_key?(field)
missing_fields << field
end
end
unless missing_fields.empty?
error_message = missing_fields.map { |field| "#{field}: Required field" }.join(", ")
raise App::BadRequestException.new(env, error_message)
end
json_params
end
end
end
+2 -3
View File
@@ -5,11 +5,10 @@ module App::Lib
class Database
extend Crecto::Repo
Query = Crecto::Repo::Query
Multi = Crecto::Repo::Multi
config do |conf|
conf.uri = ENV["DATABASE_URL"]
end
Crecto::DbLogger.set_handler(STDOUT)
end
end
+10 -3
View File
@@ -2,17 +2,24 @@ require "kemal"
module App
class BadRequestException < Kemal::Exceptions::CustomException
def initialize(context, message = Hash(String, String))
def initialize(context, message : String)
context.response.status_code = 400
context.response.print({ "error" => message }.to_json)
super(context)
end
end
class NotFoundException < Kemal::Exceptions::CustomException
def initialize(context)
context.response.status_code = 404
super(context)
end
end
class UnprocessableEntityException < Kemal::Exceptions::CustomException
def initialize(context, message = Hash(String, String))
def initialize(context, message : Hash(String, Array(String)))
context.response.status_code = 422
context.response.print({ "error" => message }.to_json)
context.response.print({ "errors" => message }.to_json)
super(context)
end
end
+1
View File
@@ -10,6 +10,7 @@ module App::Models
field :click_counter, Int64, default: 0
end
unique_constraint :slug
validate_required [:slug, :url]
end
end
+5 -1
View File
@@ -14,7 +14,7 @@ module App
end
get "/api/links/:id" do |env|
Controllers::Link::Get.new.call(env)
Controllers::Link::Read.new.call(env)
end
post "/api/links" do |env|
@@ -24,4 +24,8 @@ module App
put "/api/links/:id" do |env|
Controllers::Link::Update.new.call(env)
end
delete "/api/links/:id" do |env|
Controllers::Link::Delete.new.call(env)
end
end
+11
View File
@@ -0,0 +1,11 @@
meta {
name: Delete Link
type: http
seq: 7
}
delete {
url: {{baseUrl}}/api/links/ad9fb116-9e5b-45b7-b272-5285b579d2e4
body: none
auth: none
}
+1 -1
View File
@@ -5,7 +5,7 @@ meta {
}
get {
url: {{baseUrl}}/api/links/0da9dc9d-c56c-4d4e-942e-1ebf05ed7090
url: {{baseUrl}}/api/links/d017c966-c28b-4c4c-a83e-97bce81ee6e7
body: none
auth: none
}
-1
View File
@@ -9,7 +9,6 @@ require "./app/routes"
error 500 { |env| { "error" => "Internal Server Error" }.to_json }
error 401 { |env| { "error" => "Unauthorized" }.to_json }
error 403 { |env| { "error" => "Forbidden" }.to_json }
error 404 { |env| { "error" => "Not Found" }.to_json }
Kemal.run