diff --git a/docs/docs.go b/docs/docs.go
index 22f2570..4ee71ed 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1,4 +1,5 @@
-// Code generated by swaggo/swag. DO NOT EDIT
+// Package docs GENERATED BY SWAG; DO NOT EDIT
+// This file was generated by swaggo/swag
 package docs
 
 import "github.com/swaggo/swag"
diff --git a/go.mod b/go.mod
index 968c80a..4b58dd7 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module dns.froth.zone/pomme
 
-go 1.19
+go 1.20
 
 require (
 	github.com/glebarez/sqlite v1.7.0
diff --git a/go.sum b/go.sum
index 2bec56b..d58a0fb 100644
--- a/go.sum
+++ b/go.sum
@@ -6,9 +6,6 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
 github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
-github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
-github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -17,15 +14,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/glebarez/go-sqlite v1.20.0 h1:6D9uRXq3Kd+W7At+hOU2eIAeahv6qcYfO8jzmvb4Dr8=
-github.com/glebarez/go-sqlite v1.20.0/go.mod h1:uTnJoqtwMQjlULmljLT73Cg7HB+2X6evsBHODyyq1ak=
 github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
 github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
-github.com/glebarez/sqlite v1.6.0 h1:ZpvDLv4zBi2cuuQPitRiVz/5Uh6sXa5d8eBu0xNTpAo=
-github.com/glebarez/sqlite v1.6.0/go.mod h1:6D6zPU/HTrFlYmVDKqBJlmQvma90P6r7sRRdkUUZOYk=
 github.com/glebarez/sqlite v1.7.0 h1:A7Xj/KN2Lvie4Z4rrgQHY8MsbebX3NyWsL3n2i82MVI=
 github.com/glebarez/sqlite v1.7.0/go.mod h1:PkeevrRlF/1BhQBCnzcMWzgrIk7IOop+qS2jUYLfHhk=
 github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
@@ -53,12 +45,9 @@ github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
 github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
 github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
+github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@@ -66,7 +55,6 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -92,10 +80,8 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
 github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
 github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
 github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
 github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
@@ -103,7 +89,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M=
 github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -126,38 +111,28 @@ github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCG
 github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo=
 github.com/swaggo/swag v1.8.10 h1:eExW4bFa52WOjqRzRD58bgWsWfdFJso50lpbeTcmTfo=
 github.com/swaggo/swag v1.8.10/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
 golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
-golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -166,11 +141,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -179,13 +151,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -198,43 +168,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
 gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE=
 gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
-lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
-lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
-modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
-modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
-modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
-modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
-modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0=
-modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
-modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
-modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
-modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
-modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA=
-modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0=
-modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
-modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
-modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
-modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
-modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
 modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
 modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
 modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
 modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
-modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
-modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
-modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
 modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
 modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
-modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
-modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
-modernc.org/sqlite v1.20.0 h1:80zmD3BGkm8BZ5fUi/4lwJQHiO3GXgIUvZRXpoIfROY=
-modernc.org/sqlite v1.20.0/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
 modernc.org/sqlite v1.20.3 h1:SqGJMMxjj1PHusLxdYxeQSodg7Jxn9WWkaAQjKrntZs=
 modernc.org/sqlite v1.20.3/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
-modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
-modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE=
-modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
-modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
diff --git a/internal/api/auth.go b/internal/api/auth.go
index 1a10922..442dd86 100644
--- a/internal/api/auth.go
+++ b/internal/api/auth.go
@@ -43,7 +43,13 @@ func Login(w http.ResponseWriter, r *http.Request) {
 
 	err := r.ParseForm()
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "unable to parse request",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -53,20 +59,34 @@ func Login(w http.ResponseWriter, r *http.Request) {
 	password := r.Form.Get("password")
 
 	if username == "" {
-		APIError(w, r, genericResponseFields{"message": "no password provided", "status": http.StatusInternalServerError})
+		logger := newResponder(Response[any]{
+			Message: "no username provided",
+			Status:  http.StatusInternalServerError,
+		})
+		logger.apiError(w, r)
 
 		return
 	}
 
 	if password == "" {
-		APIError(w, r, genericResponseFields{"message": "no password provided", "status": http.StatusInternalServerError})
+		logger := newResponder(Response[any]{
+			Message: "no password provided",
+			Status:  http.StatusInternalServerError,
+		})
+		logger.apiError(w, r)
 
 		return
 	}
 
 	db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB)
 	if !ok {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": "DB connection failed"})
+		logger := newResponder(Response[any]{
+			Message: "no password provided",
+			Status:  http.StatusInternalServerError,
+			Err:     "DB connection failed",
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -74,7 +94,13 @@ func Login(w http.ResponseWriter, r *http.Request) {
 	db.Where("username = ?", username).First(&result)
 
 	if result.Username == "" {
-		APIError(w, r, genericResponseFields{"message": "login failed", "status": http.StatusUnauthorized, "realm": "authentication"})
+		logger := newResponder(Response[any]{
+			Message: "login failed",
+			Status:  http.StatusUnauthorized,
+			Realm:   "authentication",
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -82,14 +108,26 @@ func Login(w http.ResponseWriter, r *http.Request) {
 	err = bcrypt.CompareHashAndPassword([]byte(result.HashedPassword), []byte(password))
 
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "login failed", "status": http.StatusUnauthorized, "realm": "authentication"})
+		logger := newResponder(Response[any]{
+			Message: "login failed",
+			Status:  http.StatusUnauthorized,
+			Realm:   "authentication",
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
 
 	token, err := makeToken(username)
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "internal server error",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
diff --git a/internal/api/fs.go b/internal/api/fs.go
index 07008c1..94e5189 100644
--- a/internal/api/fs.go
+++ b/internal/api/fs.go
@@ -23,14 +23,22 @@ func makeLocal(zone *ZoneRequest) error {
 
 	c, err := internal.ReadConfig()
 	if err != nil {
-		logHandler(genericResponseFields{"error": err.Error(), "message": "no config file defined"})
+		logger := newResponder(Response[any]{
+			Message: "no config file defined",
+			Err:     err.Error(),
+		})
+		logger.writeLogEntry()
 
 		return fmt.Errorf("unable to parse directory: %w", err)
 	}
 
 	path := fmt.Sprintf("%s/%s/", c.ZoneDir, zone.FileName)
 	if err = os.MkdirAll(path, 0o750); err != nil {
-		logHandler(genericResponseFields{"error": err.Error(), "message": "unable to make directory for zone files"})
+		logger := newResponder(Response[any]{
+			Message: "unable to make directory for zone files",
+			Err:     err.Error(),
+		})
+		logger.writeLogEntry()
 
 		return fmt.Errorf("unable to make zone directory: %w", err)
 	}
diff --git a/internal/api/helpers.go b/internal/api/helpers.go
index c10d169..45280f6 100644
--- a/internal/api/helpers.go
+++ b/internal/api/helpers.go
@@ -22,7 +22,11 @@ func setDBMiddleware(next http.Handler) http.Handler {
 		)
 		c, err := internal.ReadConfig()
 		if err != nil {
-			logHandler(genericResponseFields{"error": err.Error(), "message": "No config file defined:"})
+			logger := newResponder(Response[any]{
+				Message: "No config file defined",
+				Err:     err.Error(),
+			})
+			logger.writeLogEntry()
 		}
 
 		switch r.Header.Get("User-Agent") {
@@ -33,10 +37,14 @@ func setDBMiddleware(next http.Handler) http.Handler {
 		}
 
 		if err != nil && !ok {
-			logHandler(genericResponseFields{"error": err.Error(), "message": "Error initializing DB"})
+			logger := newResponder(Response[any]{
+				Message: "Error initializing DB",
+				Err:     err.Error(),
+			})
+			logger.writeLogEntry()
 			err = internal.SysKill()
 			if err != nil {
-				panic("idk what to do with this but syscall.Kill errored out.")
+				panic("this should not happen.")
 			}
 		}
 
@@ -47,15 +55,22 @@ func setDBMiddleware(next http.Handler) http.Handler {
 	})
 }
 
-func APIError[T ~map[string]any](w http.ResponseWriter, r *http.Request, v T) {
+// apiError sends unsuccessful API requests back to the user with the appropriate information.
+func (e *Response[T]) apiError(w http.ResponseWriter, r *http.Request) {
+	v := map[string]any{
+		"message": e.Message,
+		"status":  e.Status,
+		"realm":   e.Realm,
+		"error":   e.Err,
+	}
+
 	w.Header().Set("X-Content-Type-Options", "nosniff")
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 
-	logHandler(v)
-
 	switch v["realm"] {
 	default:
-		w.Header().Add("WWW-Authenticate", fmt.Sprintf(`realm="%s"`, v["realm"].(string)))
+		w.Header().Add("WWW-Authenticate", fmt.Sprintf(`realm="%v"`, e.Realm))
+		delete(v, "realm")
 
 		fallthrough
 	case nil:
@@ -64,14 +79,21 @@ func APIError[T ~map[string]any](w http.ResponseWriter, r *http.Request, v T) {
 
 	w.WriteHeader(v["status"].(int))
 
-	// remove unnecessary items from response
 	delete(v, "error")
 	delete(v, "status")
+	delete(v, "realm")
 
 	render.JSON(w, r, v)
 }
 
-func logHandler(v map[string]any) {
+// writeLogEntry takes a response struct and writes info and error level logs
+// todo: make it write to file maybe
+func (e *Response[T]) writeLogEntry() {
+	v := map[string]any{
+		"message": e.Message,
+		"error":   e.Err,
+	}
+
 	logger := httplog.NewLogger("Pomme", httplog.Options{
 		JSON: true,
 	})
diff --git a/internal/api/types.go b/internal/api/types.go
index 4efa452..34b4282 100644
--- a/internal/api/types.go
+++ b/internal/api/types.go
@@ -1,6 +1,10 @@
 package api
 
-import "gorm.io/gorm"
+import (
+	"net/http"
+
+	"gorm.io/gorm"
+)
 
 const (
 	keyPrincipalContextID key = iota
@@ -28,14 +32,6 @@ type Zone struct {
 	Body []byte `json:"body,omitempty"`
 }
 
-// GenericResponse is a generics wrapper to send responses for API Errors.
-type GenericResponse[T map[string]any] struct {
-	Response map[string]any `json:"response,omitempty"`
-}
-
-// instead of calling map[string]any{...} you can call genericResponseFields{...} when making a generic response above.
-type genericResponseFields map[string]any
-
 // ndr is an interface for new DNS requests. It's methods can be used with a ZoneRequest object.
 type ndr interface {
 	// parse() is a wrapper around miekg's NewZoneParser, which is used to validate uploaded zone files
@@ -51,3 +47,31 @@ type ndr interface {
 }
 
 var _ ndr = (*ZoneRequest)(nil)
+
+// HTTPResponder interface exists for type constraints on generic HTTP logging functions.
+type HTTPResponder interface {
+	any
+}
+
+// HTTPLogger interface handles logging and sending responses to the user.
+type HTTPLogger[T HTTPResponder] interface {
+	apiError(http.ResponseWriter, *http.Request)
+	writeLogEntry()
+}
+
+// Response is a generic response struct containing the necessary keys for a log and response action.
+type Response[T HTTPResponder] struct {
+	Message, Status, Realm, Err T
+}
+
+var _ HTTPLogger[HTTPResponder] = (*Response[HTTPResponder])(nil)
+
+// newResponder instantiates a new HTTPLogger object.
+func newResponder[T HTTPResponder](m Response[T]) HTTPLogger[T] {
+	return &Response[T]{
+		Message: m.Message,
+		Status:  m.Status,
+		Realm:   m.Realm,
+		Err:     m.Err,
+	}
+}
diff --git a/internal/api/users.go b/internal/api/users.go
index 934fe0b..4f285c4 100644
--- a/internal/api/users.go
+++ b/internal/api/users.go
@@ -8,30 +8,35 @@ import (
 	"time"
 
 	"dns.froth.zone/pomme/internal"
-	"dns.froth.zone/pomme/internal/logger"
 	"github.com/go-chi/render"
 	"golang.org/x/crypto/bcrypt"
 	"gorm.io/gorm"
 )
 
-var l = logger.NewResponder()
-
 // NewUser takes a POST request and user form and creates a user in the database.
 func NewUser(w http.ResponseWriter, r *http.Request) {
 	db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB)
 	if !ok {
-		re := logger.Response[string, int]{
+		logger := newResponder(Response[any]{
 			Message: "internal server error",
 			Status:  http.StatusInternalServerError,
-		}
-		l.NewMessage(w, r, re)
+		})
+		logger.apiError(w, r)
+
+		return
 	}
 
 	var result internal.User
 
 	err := r.ParseForm()
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "unable to parse request", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "unable to parse request",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -45,7 +50,11 @@ func NewUser(w http.ResponseWriter, r *http.Request) {
 	password := r.Form.Get("password")
 
 	if password == "" {
-		APIError(w, r, genericResponseFields{"message": "no password provided", "status": http.StatusInternalServerError})
+		logger := newResponder(Response[any]{
+			Message: "no password provided",
+			Status:  http.StatusInternalServerError,
+		})
+		logger.apiError(w, r)
 
 		return
 	}
@@ -53,14 +62,23 @@ func NewUser(w http.ResponseWriter, r *http.Request) {
 	db.Where("username = ?", username).First(&result)
 
 	if result.Username != "" {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError})
+		logger := newResponder(Response[any]{
+			Message: "internal server error",
+			Status:  http.StatusInternalServerError,
+		})
+		logger.apiError(w, r)
 
 		return
 	}
 
 	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "login failed", "status": http.StatusUnauthorized, "Realm": "authentication"})
+		logger := newResponder(Response[any]{
+			Message: "login failed",
+			Status:  http.StatusUnauthorized,
+			Realm:   "authentication",
+		})
+		logger.apiError(w, r)
 
 		return
 	}
@@ -69,7 +87,12 @@ func NewUser(w http.ResponseWriter, r *http.Request) {
 
 	token, err := makeToken(username)
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "internal server error",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
 
 		return
 	}
diff --git a/internal/api/zone.go b/internal/api/zone.go
index 28c4913..907ca89 100644
--- a/internal/api/zone.go
+++ b/internal/api/zone.go
@@ -43,7 +43,13 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
 
 	file, header, err := r.FormFile("file")
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "File upload failed", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "File upload failed",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -52,14 +58,25 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
 
 	b, err := io.ReadAll(file)
 	if err != nil {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "internal server error",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
 
 	ok := validateContentType(file)
 	if !ok {
-		APIError(w, r, genericResponseFields{"message": "file must be text/plain", "status": http.StatusUnsupportedMediaType})
+		logger := newResponder(Response[any]{
+			Message: "file type must be text/plain",
+			Status:  http.StatusUnsupportedMediaType,
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -67,14 +84,26 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
 	zoneFile := newDNSRequest(header.Filename, claims["username"].(string), b)
 
 	if err := zoneFile.parse(); err != nil {
-		APIError(w, r, genericResponseFields{"message": "Unable to parse zonefile", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "Unable to parse zonefile",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
 
 	db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB)
 	if !ok {
-		APIError(w, r, genericResponseFields{"message": "internal server error", "status": http.StatusInternalServerError, "error": "unable to connect to DB"})
+		logger := newResponder(Response[any]{
+			Message: "internal server error",
+			Status:  http.StatusInternalServerError,
+			Err:     "unable to connect to DB",
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
@@ -88,7 +117,13 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) {
 		})
 
 	if err := zoneFile.save(); err != nil {
-		APIError(w, r, genericResponseFields{"message": "Unable to save zonefile", "status": http.StatusInternalServerError, "error": err.Error()})
+		logger := newResponder(Response[any]{
+			Message: "Unable to save zonefile",
+			Status:  http.StatusInternalServerError,
+			Err:     err.Error(),
+		})
+		logger.apiError(w, r)
+		logger.writeLogEntry()
 
 		return
 	}
diff --git a/internal/logger/logger.go b/internal/logger/logger.go
index 352abe7..90c66f6 100644
--- a/internal/logger/logger.go
+++ b/internal/logger/logger.go
@@ -1,45 +1 @@
 package logger
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/go-chi/render"
-)
-
-type HTTPResponder interface {
-	comparable
-	string | int | bool
-}
-
-type Response[T string, R int] struct {
-	Message, Realm, Err T
-	Status              R
-}
-
-func NewResponder[T string, R int]() Response[T, R] {
-	return Response[T, R]{}
-}
-
-func (resp *Response[T, R]) NewMessage(w http.ResponseWriter, r *http.Request, e Response[T, R]) {
-	w.Header().Set("X-Content-Type-Options", "nosniff")
-	w.Header().Set("Content-Type", "application/json; charset=utf-8")
-	switch e.Realm {
-	default:
-		w.Header().Add("WWW-Authenticate", fmt.Sprintf(`realm="%s"`, e.Realm))
-
-		fallthrough
-	case "":
-		w.Header().Add("API Error", e.Message)
-	}
-
-	w.WriteHeader(e.Status)
-
-	v := map[string]any{
-		"message": message,
-		"status":  status,
-	}
-
-	render.JSON(w, r, v)
-	return
-}
