From 8e44a5a585bf7285beeb5023e121587dc2dbe36f Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 11:42:20 +0200 Subject: [PATCH 1/7] refactor: Move lib packages to internal packages --- cmd/server/start.go | 2 +- {lib => internal}/context/sigterm.go | 0 {lib => internal}/log/noop.go | 0 {lib => internal}/mediatype/application.go | 0 {lib => internal}/mediatype/mediatype.go | 0 {lib => internal}/mediatype/mediatype_test.go | 2 +- {lib => internal}/middleware/accept.go | 2 +- {lib => internal}/middleware/accept_test.go | 2 +- {lib => internal}/middleware/content_type.go | 2 +- {lib => internal}/middleware/content_type_test.go | 4 ++-- {lib => internal}/resource/resource.go | 0 {lib => internal}/test/database.go | 0 {lib => internal}/test/errorreadcloser.go | 0 item/service.go | 2 +- lib/README.md | 3 --- server/handler/serialize.go | 2 +- server/handler/v1/error_handler_test.go | 2 +- server/handler/v1/errors.go | 2 +- server/handler/v1/errors_test.go | 2 +- server/handler/v1/handler_v1.go | 2 +- server/handler/v1/item_test.go | 4 ++-- server/server.go | 4 ++-- 22 files changed, 17 insertions(+), 20 deletions(-) rename {lib => internal}/context/sigterm.go (100%) rename {lib => internal}/log/noop.go (100%) rename {lib => internal}/mediatype/application.go (100%) rename {lib => internal}/mediatype/mediatype.go (100%) rename {lib => internal}/mediatype/mediatype_test.go (96%) rename {lib => internal}/middleware/accept.go (94%) rename {lib => internal}/middleware/accept_test.go (96%) rename {lib => internal}/middleware/content_type.go (94%) rename {lib => internal}/middleware/content_type_test.go (94%) rename {lib => internal}/resource/resource.go (100%) rename {lib => internal}/test/database.go (100%) rename {lib => internal}/test/errorreadcloser.go (100%) delete mode 100644 lib/README.md diff --git a/cmd/server/start.go b/cmd/server/start.go index 08c4b07..0f06e72 100644 --- a/cmd/server/start.go +++ b/cmd/server/start.go @@ -7,8 +7,8 @@ import ( "os/user" "github.com/glass-cms/glasscms/database" + ctx "github.com/glass-cms/glasscms/internal/context" "github.com/glass-cms/glasscms/item" - ctx "github.com/glass-cms/glasscms/lib/context" "github.com/glass-cms/glasscms/server" "github.com/glass-cms/glasscms/server/handler" v1 "github.com/glass-cms/glasscms/server/handler/v1" diff --git a/lib/context/sigterm.go b/internal/context/sigterm.go similarity index 100% rename from lib/context/sigterm.go rename to internal/context/sigterm.go diff --git a/lib/log/noop.go b/internal/log/noop.go similarity index 100% rename from lib/log/noop.go rename to internal/log/noop.go diff --git a/lib/mediatype/application.go b/internal/mediatype/application.go similarity index 100% rename from lib/mediatype/application.go rename to internal/mediatype/application.go diff --git a/lib/mediatype/mediatype.go b/internal/mediatype/mediatype.go similarity index 100% rename from lib/mediatype/mediatype.go rename to internal/mediatype/mediatype.go diff --git a/lib/mediatype/mediatype_test.go b/internal/mediatype/mediatype_test.go similarity index 96% rename from lib/mediatype/mediatype_test.go rename to internal/mediatype/mediatype_test.go index 8d83c48..ebbec8c 100644 --- a/lib/mediatype/mediatype_test.go +++ b/internal/mediatype/mediatype_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/glass-cms/glasscms/lib/mediatype" + "github.com/glass-cms/glasscms/internal/mediatype" ) func stringPtr(s string) *string { diff --git a/lib/middleware/accept.go b/internal/middleware/accept.go similarity index 94% rename from lib/middleware/accept.go rename to internal/middleware/accept.go index 43c2b8a..35980aa 100644 --- a/lib/middleware/accept.go +++ b/internal/middleware/accept.go @@ -4,7 +4,7 @@ import ( "net/http" "slices" - "github.com/glass-cms/glasscms/lib/mediatype" + "github.com/glass-cms/glasscms/internal/mediatype" ) // Accept generates a handler that writes a 415 Unsupported Media Type header diff --git a/lib/middleware/accept_test.go b/internal/middleware/accept_test.go similarity index 96% rename from lib/middleware/accept_test.go rename to internal/middleware/accept_test.go index 49799f8..8c6d690 100644 --- a/lib/middleware/accept_test.go +++ b/internal/middleware/accept_test.go @@ -5,7 +5,7 @@ import ( "net/http/httptest" "testing" - "github.com/glass-cms/glasscms/lib/middleware" + "github.com/glass-cms/glasscms/internal/middleware" ) func Test_Accept(t *testing.T) { diff --git a/lib/middleware/content_type.go b/internal/middleware/content_type.go similarity index 94% rename from lib/middleware/content_type.go rename to internal/middleware/content_type.go index 327a394..11e6287 100644 --- a/lib/middleware/content_type.go +++ b/internal/middleware/content_type.go @@ -4,7 +4,7 @@ import ( "net/http" "slices" - "github.com/glass-cms/glasscms/lib/mediatype" + "github.com/glass-cms/glasscms/internal/mediatype" ) // ContentType generates a handler that writes a 415 Unsupported Media Type header diff --git a/lib/middleware/content_type_test.go b/internal/middleware/content_type_test.go similarity index 94% rename from lib/middleware/content_type_test.go rename to internal/middleware/content_type_test.go index 20c60d1..81d6a11 100644 --- a/lib/middleware/content_type_test.go +++ b/internal/middleware/content_type_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/glass-cms/glasscms/lib/mediatype" - "github.com/glass-cms/glasscms/lib/middleware" + "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/internal/middleware" ) func Test_ContentType(t *testing.T) { diff --git a/lib/resource/resource.go b/internal/resource/resource.go similarity index 100% rename from lib/resource/resource.go rename to internal/resource/resource.go diff --git a/lib/test/database.go b/internal/test/database.go similarity index 100% rename from lib/test/database.go rename to internal/test/database.go diff --git a/lib/test/errorreadcloser.go b/internal/test/errorreadcloser.go similarity index 100% rename from lib/test/errorreadcloser.go rename to internal/test/errorreadcloser.go diff --git a/item/service.go b/item/service.go index 74f97bd..e134d3d 100644 --- a/item/service.go +++ b/item/service.go @@ -5,7 +5,7 @@ import ( "errors" "github.com/glass-cms/glasscms/database" - "github.com/glass-cms/glasscms/lib/resource" + "github.com/glass-cms/glasscms/internal/resource" ) // Service is a service for managing items. diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index 44edbc3..0000000 --- a/lib/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Libs - -The libs folder contains modules and files that are auxiliary to the application. Libraries contain utility functions that are non-specific to the application domain. They are used to encapsulate code that is used in multiple places in the application. The libs folder is not a place for domain-specific code. \ No newline at end of file diff --git a/server/handler/serialize.go b/server/handler/serialize.go index 5f0023d..f3ebada 100644 --- a/server/handler/serialize.go +++ b/server/handler/serialize.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "net/http" - "github.com/glass-cms/glasscms/lib/mediatype" + "github.com/glass-cms/glasscms/internal/mediatype" ) // SerializeResponse writes the provided data to the response writer in the diff --git a/server/handler/v1/error_handler_test.go b/server/handler/v1/error_handler_test.go index 4226d8f..45522b8 100644 --- a/server/handler/v1/error_handler_test.go +++ b/server/handler/v1/error_handler_test.go @@ -9,7 +9,7 @@ import ( "testing" api "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/lib/resource" + "github.com/glass-cms/glasscms/internal/resource" v1 "github.com/glass-cms/glasscms/server/handler/v1" ) diff --git a/server/handler/v1/errors.go b/server/handler/v1/errors.go index b323ebc..6c0df37 100644 --- a/server/handler/v1/errors.go +++ b/server/handler/v1/errors.go @@ -5,7 +5,7 @@ import ( "fmt" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/lib/resource" + "github.com/glass-cms/glasscms/internal/resource" ) // ErrorMapperAlreadyExistsError maps a resource.AlreadyExistsError to an API error response. diff --git a/server/handler/v1/errors_test.go b/server/handler/v1/errors_test.go index 6de00b0..9ce81a8 100644 --- a/server/handler/v1/errors_test.go +++ b/server/handler/v1/errors_test.go @@ -5,7 +5,7 @@ import ( "testing" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/lib/resource" + "github.com/glass-cms/glasscms/internal/resource" v1_handler "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/require" ) diff --git a/server/handler/v1/handler_v1.go b/server/handler/v1/handler_v1.go index fb715b8..f55bd47 100644 --- a/server/handler/v1/handler_v1.go +++ b/server/handler/v1/handler_v1.go @@ -7,8 +7,8 @@ import ( "reflect" v1 "github.com/glass-cms/glasscms/api/v1" + "github.com/glass-cms/glasscms/internal/resource" "github.com/glass-cms/glasscms/item" - "github.com/glass-cms/glasscms/lib/resource" "github.com/glass-cms/glasscms/server/handler" ) diff --git a/server/handler/v1/item_test.go b/server/handler/v1/item_test.go index fd9ef35..f2ef092 100644 --- a/server/handler/v1/item_test.go +++ b/server/handler/v1/item_test.go @@ -9,9 +9,9 @@ import ( api "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/log" + "github.com/glass-cms/glasscms/internal/test" "github.com/glass-cms/glasscms/item" - "github.com/glass-cms/glasscms/lib/log" - "github.com/glass-cms/glasscms/lib/test" v1 "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/assert" ) diff --git a/server/server.go b/server/server.go index 4d00a49..9d549fa 100644 --- a/server/server.go +++ b/server/server.go @@ -7,8 +7,8 @@ import ( "net/http" "time" - "github.com/glass-cms/glasscms/lib/mediatype" - "github.com/glass-cms/glasscms/lib/middleware" + "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/internal/middleware" "github.com/glass-cms/glasscms/server/handler" ) From c4b9c3c8614726e3f3f1b1a21dc09debe19e45d7 Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 11:46:23 +0200 Subject: [PATCH 2/7] refactor: Move item package to internal pkg --- api/v1/item.go | 2 +- api/v1/item_test.go | 2 +- cmd/convert.go | 2 +- cmd/server/start.go | 2 +- {item => internal/item}/item.go | 0 {item => internal/item}/repository.go | 0 {item => internal/item}/repository_test.go | 2 +- {item => internal/item}/service.go | 0 parser/parser.go | 2 +- server/handler/v1/handler_v1.go | 2 +- server/handler/v1/item_test.go | 2 +- 11 files changed, 8 insertions(+), 8 deletions(-) rename {item => internal/item}/item.go (100%) rename {item => internal/item}/repository.go (100%) rename {item => internal/item}/repository_test.go (99%) rename {item => internal/item}/service.go (100%) diff --git a/api/v1/item.go b/api/v1/item.go index b59f5c5..29fbbda 100644 --- a/api/v1/item.go +++ b/api/v1/item.go @@ -1,7 +1,7 @@ package v1 import ( - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/parser" ) diff --git a/api/v1/item_test.go b/api/v1/item_test.go index f6ab786..e39138c 100644 --- a/api/v1/item_test.go +++ b/api/v1/item_test.go @@ -5,7 +5,7 @@ import ( "time" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/parser" "github.com/stretchr/testify/assert" ) diff --git a/cmd/convert.go b/cmd/convert.go index 111a723..52fe1fc 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -8,7 +8,7 @@ import ( "os" "path" - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/parser" "github.com/glass-cms/glasscms/sourcer" "github.com/lmittmann/tint" diff --git a/cmd/server/start.go b/cmd/server/start.go index 0f06e72..a40c957 100644 --- a/cmd/server/start.go +++ b/cmd/server/start.go @@ -8,7 +8,7 @@ import ( "github.com/glass-cms/glasscms/database" ctx "github.com/glass-cms/glasscms/internal/context" - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/server" "github.com/glass-cms/glasscms/server/handler" v1 "github.com/glass-cms/glasscms/server/handler/v1" diff --git a/item/item.go b/internal/item/item.go similarity index 100% rename from item/item.go rename to internal/item/item.go diff --git a/item/repository.go b/internal/item/repository.go similarity index 100% rename from item/repository.go rename to internal/item/repository.go diff --git a/item/repository_test.go b/internal/item/repository_test.go similarity index 99% rename from item/repository_test.go rename to internal/item/repository_test.go index 3e81272..d2a1a28 100644 --- a/item/repository_test.go +++ b/internal/item/repository_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/glass-cms/glasscms/database" - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/item/service.go b/internal/item/service.go similarity index 100% rename from item/service.go rename to internal/item/service.go diff --git a/parser/parser.go b/parser/parser.go index 28fc216..88a23eb 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/glass-cms/glasscms/item" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/sourcer" "github.com/mozillazg/go-slugify" "gopkg.in/yaml.v3" diff --git a/server/handler/v1/handler_v1.go b/server/handler/v1/handler_v1.go index f55bd47..d015ca8 100644 --- a/server/handler/v1/handler_v1.go +++ b/server/handler/v1/handler_v1.go @@ -7,8 +7,8 @@ import ( "reflect" v1 "github.com/glass-cms/glasscms/api/v1" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/internal/resource" - "github.com/glass-cms/glasscms/item" "github.com/glass-cms/glasscms/server/handler" ) diff --git a/server/handler/v1/item_test.go b/server/handler/v1/item_test.go index f2ef092..387c996 100644 --- a/server/handler/v1/item_test.go +++ b/server/handler/v1/item_test.go @@ -9,9 +9,9 @@ import ( api "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/internal/log" "github.com/glass-cms/glasscms/internal/test" - "github.com/glass-cms/glasscms/item" v1 "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/assert" ) From 9268c745eb188f0308685237b2c442f49ae324f7 Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 11:47:29 +0200 Subject: [PATCH 3/7] refactor: Move sourcer pkg to pkg --- cmd/convert.go | 2 +- parser/parser.go | 2 +- {sourcer => pkg/sourcer}/file_source.go | 0 {sourcer => pkg/sourcer}/file_source_test.go | 2 +- {sourcer => pkg/sourcer}/file_system.go | 0 {sourcer => pkg/sourcer}/file_system_test.go | 2 +- {sourcer => pkg/sourcer}/nil_source.go | 0 {sourcer => pkg/sourcer}/source.go | 0 {sourcer => pkg/sourcer}/sourcer.go | 0 9 files changed, 4 insertions(+), 4 deletions(-) rename {sourcer => pkg/sourcer}/file_source.go (100%) rename {sourcer => pkg/sourcer}/file_source_test.go (94%) rename {sourcer => pkg/sourcer}/file_system.go (100%) rename {sourcer => pkg/sourcer}/file_system_test.go (98%) rename {sourcer => pkg/sourcer}/nil_source.go (100%) rename {sourcer => pkg/sourcer}/source.go (100%) rename {sourcer => pkg/sourcer}/sourcer.go (100%) diff --git a/cmd/convert.go b/cmd/convert.go index 52fe1fc..1de32dd 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -10,7 +10,7 @@ import ( "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/parser" - "github.com/glass-cms/glasscms/sourcer" + "github.com/glass-cms/glasscms/pkg/sourcer" "github.com/lmittmann/tint" "github.com/spf13/cobra" "github.com/spf13/viper" diff --git a/parser/parser.go b/parser/parser.go index 88a23eb..8cf859e 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/sourcer" + "github.com/glass-cms/glasscms/pkg/sourcer" "github.com/mozillazg/go-slugify" "gopkg.in/yaml.v3" ) diff --git a/sourcer/file_source.go b/pkg/sourcer/file_source.go similarity index 100% rename from sourcer/file_source.go rename to pkg/sourcer/file_source.go diff --git a/sourcer/file_source_test.go b/pkg/sourcer/file_source_test.go similarity index 94% rename from sourcer/file_source_test.go rename to pkg/sourcer/file_source_test.go index 6981846..3d88cc7 100644 --- a/sourcer/file_source_test.go +++ b/pkg/sourcer/file_source_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/djherbis/times" - "github.com/glass-cms/glasscms/sourcer" + "github.com/glass-cms/glasscms/pkg/sourcer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/sourcer/file_system.go b/pkg/sourcer/file_system.go similarity index 100% rename from sourcer/file_system.go rename to pkg/sourcer/file_system.go diff --git a/sourcer/file_system_test.go b/pkg/sourcer/file_system_test.go similarity index 98% rename from sourcer/file_system_test.go rename to pkg/sourcer/file_system_test.go index c495aee..2056e3d 100644 --- a/sourcer/file_system_test.go +++ b/pkg/sourcer/file_system_test.go @@ -7,7 +7,7 @@ import ( "path/filepath" "testing" - "github.com/glass-cms/glasscms/sourcer" + "github.com/glass-cms/glasscms/pkg/sourcer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/sourcer/nil_source.go b/pkg/sourcer/nil_source.go similarity index 100% rename from sourcer/nil_source.go rename to pkg/sourcer/nil_source.go diff --git a/sourcer/source.go b/pkg/sourcer/source.go similarity index 100% rename from sourcer/source.go rename to pkg/sourcer/source.go diff --git a/sourcer/sourcer.go b/pkg/sourcer/sourcer.go similarity index 100% rename from sourcer/sourcer.go rename to pkg/sourcer/sourcer.go From 8a4df661ca278e5aa0f117e762b7c41f155820f7 Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 11:48:43 +0200 Subject: [PATCH 4/7] refactor: Move parser pkg to pkg --- api/v1/item.go | 2 +- api/v1/item_test.go | 2 +- cmd/convert.go | 2 +- {parser => pkg/parser}/parser.go | 0 {parser => pkg/parser}/parser_test.go | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename {parser => pkg/parser}/parser.go (100%) rename {parser => pkg/parser}/parser_test.go (95%) diff --git a/api/v1/item.go b/api/v1/item.go index 29fbbda..70273ab 100644 --- a/api/v1/item.go +++ b/api/v1/item.go @@ -2,7 +2,7 @@ package v1 import ( "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/parser" + "github.com/glass-cms/glasscms/pkg/parser" ) // ToItem converts an api.ItemCreate to an item.Item. diff --git a/api/v1/item_test.go b/api/v1/item_test.go index e39138c..baced5d 100644 --- a/api/v1/item_test.go +++ b/api/v1/item_test.go @@ -6,7 +6,7 @@ import ( v1 "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/parser" + "github.com/glass-cms/glasscms/pkg/parser" "github.com/stretchr/testify/assert" ) diff --git a/cmd/convert.go b/cmd/convert.go index 1de32dd..e840c3b 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -9,7 +9,7 @@ import ( "path" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/parser" + "github.com/glass-cms/glasscms/pkg/parser" "github.com/glass-cms/glasscms/pkg/sourcer" "github.com/lmittmann/tint" "github.com/spf13/cobra" diff --git a/parser/parser.go b/pkg/parser/parser.go similarity index 100% rename from parser/parser.go rename to pkg/parser/parser.go diff --git a/parser/parser_test.go b/pkg/parser/parser_test.go similarity index 95% rename from parser/parser_test.go rename to pkg/parser/parser_test.go index 175078f..fc63718 100644 --- a/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/glass-cms/glasscms/parser" + "github.com/glass-cms/glasscms/pkg/parser" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) From 0b652708ee6c22596cdec4d0d7970f2c5d72a36b Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 12:09:25 +0200 Subject: [PATCH 5/7] refactor: Move codegen to api package --- api/v1/item.go | 2 +- api/v1/item_test.go | 2 +- cmd/convert.go | 4 +- cmd/migrate.go | 2 +- cmd/server/server.go | 2 +- cmd/server/start.go | 4 +- generate.go | 2 +- {database => internal/database}/config.go | 0 {database => internal/database}/error.go | 0 {database => internal/database}/error_test.go | 2 +- {database => internal/database}/migrate.go | 0 .../database}/migrations/1_create_items.sql | 0 .../{test/database.go => database/test.go} | 13 +- internal/item/repository.go | 2 +- internal/item/repository_test.go | 2 +- internal/item/service.go | 4 +- {pkg => internal}/parser/parser.go | 2 +- {pkg => internal}/parser/parser_test.go | 2 +- {pkg => internal}/sourcer/file_source.go | 0 {pkg => internal}/sourcer/file_source_test.go | 2 +- {pkg => internal}/sourcer/file_system.go | 0 {pkg => internal}/sourcer/file_system_test.go | 2 +- {pkg => internal}/sourcer/nil_source.go | 0 {pkg => internal}/sourcer/source.go | 0 {pkg => internal}/sourcer/sourcer.go | 0 ...en.cfg.v1.yaml => oapi-codegen-config.yaml | 4 +- openapi/openapi.v1.yaml => openapi.yaml | 2 +- pkg/api/api.gen.go | 252 ++++++++++++++++++ {internal => pkg}/context/sigterm.go | 0 {internal => pkg}/log/noop.go | 0 {internal => pkg}/mediatype/application.go | 0 {internal => pkg}/mediatype/mediatype.go | 0 {internal => pkg}/mediatype/mediatype_test.go | 2 +- {internal => pkg}/middleware/accept.go | 2 +- {internal => pkg}/middleware/accept_test.go | 2 +- {internal => pkg}/middleware/content_type.go | 2 +- .../middleware/content_type_test.go | 4 +- {internal => pkg}/resource/resource.go | 0 {internal => pkg}/test/errorreadcloser.go | 0 scripts/compile-spec.sh | 2 +- server/handler/serialize.go | 2 +- server/handler/v1/error_handler_test.go | 2 +- server/handler/v1/errors.go | 2 +- server/handler/v1/errors_test.go | 2 +- server/handler/v1/handler_v1.go | 2 +- server/handler/v1/item_test.go | 9 +- server/server.go | 4 +- typespec/main.tsp | 2 - 48 files changed, 297 insertions(+), 49 deletions(-) rename {database => internal/database}/config.go (100%) rename {database => internal/database}/error.go (100%) rename {database => internal/database}/error_test.go (95%) rename {database => internal/database}/migrate.go (100%) rename {database => internal/database}/migrations/1_create_items.sql (100%) rename internal/{test/database.go => database/test.go} (53%) rename {pkg => internal}/parser/parser.go (97%) rename {pkg => internal}/parser/parser_test.go (95%) rename {pkg => internal}/sourcer/file_source.go (100%) rename {pkg => internal}/sourcer/file_source_test.go (94%) rename {pkg => internal}/sourcer/file_system.go (100%) rename {pkg => internal}/sourcer/file_system_test.go (98%) rename {pkg => internal}/sourcer/nil_source.go (100%) rename {pkg => internal}/sourcer/source.go (100%) rename {pkg => internal}/sourcer/sourcer.go (100%) rename openapi/codegen.cfg.v1.yaml => oapi-codegen-config.yaml (55%) rename openapi/openapi.v1.yaml => openapi.yaml (99%) create mode 100644 pkg/api/api.gen.go rename {internal => pkg}/context/sigterm.go (100%) rename {internal => pkg}/log/noop.go (100%) rename {internal => pkg}/mediatype/application.go (100%) rename {internal => pkg}/mediatype/mediatype.go (100%) rename {internal => pkg}/mediatype/mediatype_test.go (96%) rename {internal => pkg}/middleware/accept.go (94%) rename {internal => pkg}/middleware/accept_test.go (96%) rename {internal => pkg}/middleware/content_type.go (94%) rename {internal => pkg}/middleware/content_type_test.go (94%) rename {internal => pkg}/resource/resource.go (100%) rename {internal => pkg}/test/errorreadcloser.go (100%) diff --git a/api/v1/item.go b/api/v1/item.go index 70273ab..045e21e 100644 --- a/api/v1/item.go +++ b/api/v1/item.go @@ -2,7 +2,7 @@ package v1 import ( "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/pkg/parser" + "github.com/glass-cms/glasscms/internal/parser" ) // ToItem converts an api.ItemCreate to an item.Item. diff --git a/api/v1/item_test.go b/api/v1/item_test.go index baced5d..967b428 100644 --- a/api/v1/item_test.go +++ b/api/v1/item_test.go @@ -6,7 +6,7 @@ import ( v1 "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/pkg/parser" + "github.com/glass-cms/glasscms/internal/parser" "github.com/stretchr/testify/assert" ) diff --git a/cmd/convert.go b/cmd/convert.go index e840c3b..eec9fa7 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -9,8 +9,8 @@ import ( "path" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/pkg/parser" - "github.com/glass-cms/glasscms/pkg/sourcer" + "github.com/glass-cms/glasscms/internal/parser" + "github.com/glass-cms/glasscms/internal/sourcer" "github.com/lmittmann/tint" "github.com/spf13/cobra" "github.com/spf13/viper" diff --git a/cmd/migrate.go b/cmd/migrate.go index b01d7bf..a1c524b 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -4,7 +4,7 @@ import ( "log/slog" "os" - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" "github.com/lmittmann/tint" "github.com/spf13/cobra" "github.com/spf13/viper" diff --git a/cmd/server/server.go b/cmd/server/server.go index 6e3618b..6273db2 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -1,7 +1,7 @@ package server import ( - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" "github.com/spf13/cobra" ) diff --git a/cmd/server/start.go b/cmd/server/start.go index a40c957..8df548f 100644 --- a/cmd/server/start.go +++ b/cmd/server/start.go @@ -6,9 +6,9 @@ import ( "os" "os/user" - "github.com/glass-cms/glasscms/database" - ctx "github.com/glass-cms/glasscms/internal/context" + "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" + ctx "github.com/glass-cms/glasscms/pkg/context" "github.com/glass-cms/glasscms/server" "github.com/glass-cms/glasscms/server/handler" v1 "github.com/glass-cms/glasscms/server/handler/v1" diff --git a/generate.go b/generate.go index f5d43e7..0ed89ea 100644 --- a/generate.go +++ b/generate.go @@ -1,3 +1,3 @@ package main -//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=openapi/codegen.cfg.v1.yaml openapi/openapi.v1.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=oapi-codegen-config.yaml openapi.yaml diff --git a/database/config.go b/internal/database/config.go similarity index 100% rename from database/config.go rename to internal/database/config.go diff --git a/database/error.go b/internal/database/error.go similarity index 100% rename from database/error.go rename to internal/database/error.go diff --git a/database/error_test.go b/internal/database/error_test.go similarity index 95% rename from database/error_test.go rename to internal/database/error_test.go index 545ecbc..0f57d0c 100644 --- a/database/error_test.go +++ b/internal/database/error_test.go @@ -6,7 +6,7 @@ import ( "errors" "testing" - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/assert" ) diff --git a/database/migrate.go b/internal/database/migrate.go similarity index 100% rename from database/migrate.go rename to internal/database/migrate.go diff --git a/database/migrations/1_create_items.sql b/internal/database/migrations/1_create_items.sql similarity index 100% rename from database/migrations/1_create_items.sql rename to internal/database/migrations/1_create_items.sql diff --git a/internal/test/database.go b/internal/database/test.go similarity index 53% rename from internal/test/database.go rename to internal/database/test.go index d485601..03bbdea 100644 --- a/internal/test/database.go +++ b/internal/database/test.go @@ -1,27 +1,26 @@ -package test +package database import ( "database/sql" "fmt" - "github.com/glass-cms/glasscms/database" "github.com/google/uuid" ) // NewDB creates a new in-memory SQLite database with the necessary schema // for testing purposes. -func NewDB() (*sql.DB, error) { - config := database.Config{ - Driver: database.DriverName[int32(database.DriverSqlite)], +func NewTestDB() (*sql.DB, error) { + config := Config{ + Driver: DriverName[int32(DriverSqlite)], DSN: fmt.Sprintf("file:%s?mode=memory&cache=shared", uuid.New().String()), } - db, err := database.NewConnection(config) + db, err := NewConnection(config) if err != nil { return nil, err } - if err = database.MigrateDatabase(db, config); err != nil { + if err = MigrateDatabase(db, config); err != nil { return nil, err } diff --git a/internal/item/repository.go b/internal/item/repository.go index 7cc8b1a..b26963e 100644 --- a/internal/item/repository.go +++ b/internal/item/repository.go @@ -7,7 +7,7 @@ import ( "errors" "fmt" - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" ) type Repository interface { diff --git a/internal/item/repository_test.go b/internal/item/repository_test.go index d2a1a28..93360c5 100644 --- a/internal/item/repository_test.go +++ b/internal/item/repository_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/assert" diff --git a/internal/item/service.go b/internal/item/service.go index e134d3d..8cb99db 100644 --- a/internal/item/service.go +++ b/internal/item/service.go @@ -4,8 +4,8 @@ import ( "context" "errors" - "github.com/glass-cms/glasscms/database" - "github.com/glass-cms/glasscms/internal/resource" + "github.com/glass-cms/glasscms/internal/database" + "github.com/glass-cms/glasscms/pkg/resource" ) // Service is a service for managing items. diff --git a/pkg/parser/parser.go b/internal/parser/parser.go similarity index 97% rename from pkg/parser/parser.go rename to internal/parser/parser.go index 8cf859e..fc7e0d4 100644 --- a/pkg/parser/parser.go +++ b/internal/parser/parser.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/pkg/sourcer" + "github.com/glass-cms/glasscms/internal/sourcer" "github.com/mozillazg/go-slugify" "gopkg.in/yaml.v3" ) diff --git a/pkg/parser/parser_test.go b/internal/parser/parser_test.go similarity index 95% rename from pkg/parser/parser_test.go rename to internal/parser/parser_test.go index fc63718..93fdae3 100644 --- a/pkg/parser/parser_test.go +++ b/internal/parser/parser_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/glass-cms/glasscms/pkg/parser" + "github.com/glass-cms/glasscms/internal/parser" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/sourcer/file_source.go b/internal/sourcer/file_source.go similarity index 100% rename from pkg/sourcer/file_source.go rename to internal/sourcer/file_source.go diff --git a/pkg/sourcer/file_source_test.go b/internal/sourcer/file_source_test.go similarity index 94% rename from pkg/sourcer/file_source_test.go rename to internal/sourcer/file_source_test.go index 3d88cc7..de8fbf6 100644 --- a/pkg/sourcer/file_source_test.go +++ b/internal/sourcer/file_source_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/djherbis/times" - "github.com/glass-cms/glasscms/pkg/sourcer" + "github.com/glass-cms/glasscms/internal/sourcer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/sourcer/file_system.go b/internal/sourcer/file_system.go similarity index 100% rename from pkg/sourcer/file_system.go rename to internal/sourcer/file_system.go diff --git a/pkg/sourcer/file_system_test.go b/internal/sourcer/file_system_test.go similarity index 98% rename from pkg/sourcer/file_system_test.go rename to internal/sourcer/file_system_test.go index 2056e3d..d91077c 100644 --- a/pkg/sourcer/file_system_test.go +++ b/internal/sourcer/file_system_test.go @@ -7,7 +7,7 @@ import ( "path/filepath" "testing" - "github.com/glass-cms/glasscms/pkg/sourcer" + "github.com/glass-cms/glasscms/internal/sourcer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/sourcer/nil_source.go b/internal/sourcer/nil_source.go similarity index 100% rename from pkg/sourcer/nil_source.go rename to internal/sourcer/nil_source.go diff --git a/pkg/sourcer/source.go b/internal/sourcer/source.go similarity index 100% rename from pkg/sourcer/source.go rename to internal/sourcer/source.go diff --git a/pkg/sourcer/sourcer.go b/internal/sourcer/sourcer.go similarity index 100% rename from pkg/sourcer/sourcer.go rename to internal/sourcer/sourcer.go diff --git a/openapi/codegen.cfg.v1.yaml b/oapi-codegen-config.yaml similarity index 55% rename from openapi/codegen.cfg.v1.yaml rename to oapi-codegen-config.yaml index 967befe..7dcda91 100644 --- a/openapi/codegen.cfg.v1.yaml +++ b/oapi-codegen-config.yaml @@ -1,5 +1,5 @@ -package: v1 +package: api generate: std-http-server: true models: true -output: api/v1/api.gen.go \ No newline at end of file +output: pkg/api/api.gen.go \ No newline at end of file diff --git a/openapi/openapi.v1.yaml b/openapi.yaml similarity index 99% rename from openapi/openapi.v1.yaml rename to openapi.yaml index 6d56859..c804cf8 100644 --- a/openapi/openapi.v1.yaml +++ b/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: GlassCMS API - version: v1 + version: 0.0.0 tags: [] paths: /items: diff --git a/pkg/api/api.gen.go b/pkg/api/api.gen.go new file mode 100644 index 0000000..f5a561d --- /dev/null +++ b/pkg/api/api.gen.go @@ -0,0 +1,252 @@ +//go:build go1.22 + +// Package api provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +package api + +import ( + "fmt" + "net/http" + "time" + + "github.com/oapi-codegen/runtime" +) + +// Defines values for ErrorCode. +const ( + ParameterInvalid ErrorCode = "parameter_invalid" + ParameterMissing ErrorCode = "parameter_missing" + ProcessingError ErrorCode = "processing_error" + ResourceAlreadyExists ErrorCode = "resource_already_exists" + ResourceMissing ErrorCode = "resource_missing" +) + +// Defines values for ErrorType. +const ( + ApiError ErrorType = "api_error" + InvalidRequestError ErrorType = "invalid_request_error" +) + +// Error Error is the response model when an API call is unsuccessful. +type Error struct { + Code ErrorCode `json:"code"` + Details map[string]interface{} `json:"details"` + Message string `json:"message"` + Type ErrorType `json:"type"` +} + +// ErrorCode defines model for ErrorCode. +type ErrorCode string + +// ErrorType defines model for ErrorType. +type ErrorType string + +// Item Item represents an individual content item. +type Item struct { + Content string `json:"content"` + CreateTime time.Time `json:"create_time"` + DeleteTime *time.Time `json:"delete_time,omitempty"` + DisplayName string `json:"display_name"` + Metadata map[string]interface{} `json:"metadata"` + Name string `json:"name"` + Properties map[string]interface{} `json:"properties"` + UpdateTime time.Time `json:"update_time"` +} + +// ItemCreate Resource create operation model. +type ItemCreate struct { + Content string `json:"content"` + CreateTime time.Time `json:"create_time"` + DisplayName string `json:"display_name"` + Metadata map[string]interface{} `json:"metadata"` + Name string `json:"name"` + Properties map[string]interface{} `json:"properties"` + UpdateTime time.Time `json:"update_time"` +} + +// ItemKey defines model for ItemKey. +type ItemKey = string + +// ItemsCreateJSONRequestBody defines body for ItemsCreate for application/json ContentType. +type ItemsCreateJSONRequestBody = ItemCreate + +// ServerInterface represents all server handlers. +type ServerInterface interface { + + // (POST /items) + ItemsCreate(w http.ResponseWriter, r *http.Request) + + // (GET /items/{name}) + ItemsGet(w http.ResponseWriter, r *http.Request, name ItemKey) +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +type MiddlewareFunc func(http.Handler) http.Handler + +// ItemsCreate operation middleware +func (siw *ServerInterfaceWrapper) ItemsCreate(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ItemsCreate(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + +// ItemsGet operation middleware +func (siw *ServerInterfaceWrapper) ItemsGet(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var err error + + // ------------- Path parameter "name" ------------- + var name ItemKey + + err = runtime.BindStyledParameterWithOptions("simple", "name", r.PathValue("name"), &name, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ItemsGet(w, r, name) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + +type UnescapedCookieParamError struct { + ParamName string + Err error +} + +func (e *UnescapedCookieParamError) Error() string { + return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) +} + +func (e *UnescapedCookieParamError) Unwrap() error { + return e.Err +} + +type UnmarshalingParamError struct { + ParamName string + Err error +} + +func (e *UnmarshalingParamError) Error() string { + return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) +} + +func (e *UnmarshalingParamError) Unwrap() error { + return e.Err +} + +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +type RequiredHeaderError struct { + ParamName string + Err error +} + +func (e *RequiredHeaderError) Error() string { + return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) +} + +func (e *RequiredHeaderError) Unwrap() error { + return e.Err +} + +type InvalidParamFormatError struct { + ParamName string + Err error +} + +func (e *InvalidParamFormatError) Error() string { + return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) +} + +func (e *InvalidParamFormatError) Unwrap() error { + return e.Err +} + +type TooManyValuesForParamError struct { + ParamName string + Count int +} + +func (e *TooManyValuesForParamError) Error() string { + return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) +} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{}) +} + +type StdHTTPServerOptions struct { + BaseURL string + BaseRouter *http.ServeMux + Middlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. +func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{ + BaseRouter: m, + }) +} + +func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{ + BaseURL: baseURL, + BaseRouter: m, + }) +} + +// HandlerWithOptions creates http.Handler with additional options +func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { + m := options.BaseRouter + + if m == nil { + m = http.NewServeMux() + } + if options.ErrorHandlerFunc == nil { + options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, + } + + m.HandleFunc("POST "+options.BaseURL+"/items", wrapper.ItemsCreate) + m.HandleFunc("GET "+options.BaseURL+"/items/{name}", wrapper.ItemsGet) + + return m +} diff --git a/internal/context/sigterm.go b/pkg/context/sigterm.go similarity index 100% rename from internal/context/sigterm.go rename to pkg/context/sigterm.go diff --git a/internal/log/noop.go b/pkg/log/noop.go similarity index 100% rename from internal/log/noop.go rename to pkg/log/noop.go diff --git a/internal/mediatype/application.go b/pkg/mediatype/application.go similarity index 100% rename from internal/mediatype/application.go rename to pkg/mediatype/application.go diff --git a/internal/mediatype/mediatype.go b/pkg/mediatype/mediatype.go similarity index 100% rename from internal/mediatype/mediatype.go rename to pkg/mediatype/mediatype.go diff --git a/internal/mediatype/mediatype_test.go b/pkg/mediatype/mediatype_test.go similarity index 96% rename from internal/mediatype/mediatype_test.go rename to pkg/mediatype/mediatype_test.go index ebbec8c..add0e21 100644 --- a/internal/mediatype/mediatype_test.go +++ b/pkg/mediatype/mediatype_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/pkg/mediatype" ) func stringPtr(s string) *string { diff --git a/internal/middleware/accept.go b/pkg/middleware/accept.go similarity index 94% rename from internal/middleware/accept.go rename to pkg/middleware/accept.go index 35980aa..7d22913 100644 --- a/internal/middleware/accept.go +++ b/pkg/middleware/accept.go @@ -4,7 +4,7 @@ import ( "net/http" "slices" - "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/pkg/mediatype" ) // Accept generates a handler that writes a 415 Unsupported Media Type header diff --git a/internal/middleware/accept_test.go b/pkg/middleware/accept_test.go similarity index 96% rename from internal/middleware/accept_test.go rename to pkg/middleware/accept_test.go index 8c6d690..70f6665 100644 --- a/internal/middleware/accept_test.go +++ b/pkg/middleware/accept_test.go @@ -5,7 +5,7 @@ import ( "net/http/httptest" "testing" - "github.com/glass-cms/glasscms/internal/middleware" + "github.com/glass-cms/glasscms/pkg/middleware" ) func Test_Accept(t *testing.T) { diff --git a/internal/middleware/content_type.go b/pkg/middleware/content_type.go similarity index 94% rename from internal/middleware/content_type.go rename to pkg/middleware/content_type.go index 11e6287..d3c060a 100644 --- a/internal/middleware/content_type.go +++ b/pkg/middleware/content_type.go @@ -4,7 +4,7 @@ import ( "net/http" "slices" - "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/pkg/mediatype" ) // ContentType generates a handler that writes a 415 Unsupported Media Type header diff --git a/internal/middleware/content_type_test.go b/pkg/middleware/content_type_test.go similarity index 94% rename from internal/middleware/content_type_test.go rename to pkg/middleware/content_type_test.go index 81d6a11..92b9d2c 100644 --- a/internal/middleware/content_type_test.go +++ b/pkg/middleware/content_type_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/glass-cms/glasscms/internal/mediatype" - "github.com/glass-cms/glasscms/internal/middleware" + "github.com/glass-cms/glasscms/pkg/mediatype" + "github.com/glass-cms/glasscms/pkg/middleware" ) func Test_ContentType(t *testing.T) { diff --git a/internal/resource/resource.go b/pkg/resource/resource.go similarity index 100% rename from internal/resource/resource.go rename to pkg/resource/resource.go diff --git a/internal/test/errorreadcloser.go b/pkg/test/errorreadcloser.go similarity index 100% rename from internal/test/errorreadcloser.go rename to pkg/test/errorreadcloser.go diff --git a/scripts/compile-spec.sh b/scripts/compile-spec.sh index 2e9b613..c8ca696 100755 --- a/scripts/compile-spec.sh +++ b/scripts/compile-spec.sh @@ -6,5 +6,5 @@ current_dir=$(pwd) cd typespec || exit -tsp compile . --emit @typespec/openapi3 --option "@typespec/openapi3.emitter-output-dir=${current_dir}/openapi" +tsp compile . --emit @typespec/openapi3 --option "@typespec/openapi3.emitter-output-dir=${current_dir}" cd "$current_dir" || exit diff --git a/server/handler/serialize.go b/server/handler/serialize.go index f3ebada..95d108a 100644 --- a/server/handler/serialize.go +++ b/server/handler/serialize.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "net/http" - "github.com/glass-cms/glasscms/internal/mediatype" + "github.com/glass-cms/glasscms/pkg/mediatype" ) // SerializeResponse writes the provided data to the response writer in the diff --git a/server/handler/v1/error_handler_test.go b/server/handler/v1/error_handler_test.go index 45522b8..094e879 100644 --- a/server/handler/v1/error_handler_test.go +++ b/server/handler/v1/error_handler_test.go @@ -9,7 +9,7 @@ import ( "testing" api "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/resource" + "github.com/glass-cms/glasscms/pkg/resource" v1 "github.com/glass-cms/glasscms/server/handler/v1" ) diff --git a/server/handler/v1/errors.go b/server/handler/v1/errors.go index 6c0df37..005e292 100644 --- a/server/handler/v1/errors.go +++ b/server/handler/v1/errors.go @@ -5,7 +5,7 @@ import ( "fmt" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/resource" + "github.com/glass-cms/glasscms/pkg/resource" ) // ErrorMapperAlreadyExistsError maps a resource.AlreadyExistsError to an API error response. diff --git a/server/handler/v1/errors_test.go b/server/handler/v1/errors_test.go index 9ce81a8..b0c0425 100644 --- a/server/handler/v1/errors_test.go +++ b/server/handler/v1/errors_test.go @@ -5,7 +5,7 @@ import ( "testing" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/resource" + "github.com/glass-cms/glasscms/pkg/resource" v1_handler "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/require" ) diff --git a/server/handler/v1/handler_v1.go b/server/handler/v1/handler_v1.go index d015ca8..8ce772e 100644 --- a/server/handler/v1/handler_v1.go +++ b/server/handler/v1/handler_v1.go @@ -8,7 +8,7 @@ import ( v1 "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/internal/resource" + "github.com/glass-cms/glasscms/pkg/resource" "github.com/glass-cms/glasscms/server/handler" ) diff --git a/server/handler/v1/item_test.go b/server/handler/v1/item_test.go index 387c996..ea11b94 100644 --- a/server/handler/v1/item_test.go +++ b/server/handler/v1/item_test.go @@ -8,10 +8,9 @@ import ( "testing" api "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/database" + "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/internal/log" - "github.com/glass-cms/glasscms/internal/test" + "github.com/glass-cms/glasscms/pkg/log" v1 "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/assert" ) @@ -46,7 +45,7 @@ func TestAPIHandler_ItemsCreate(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - testdb, err := test.NewDB() + testdb, err := database.NewTestDB() if err != nil { t.Fatal(err) } @@ -92,7 +91,7 @@ func TestAPIHandler_ItemsGet(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - testdb, err := test.NewDB() + testdb, err := database.NewTestDB() if err != nil { t.Fatal(err) } diff --git a/server/server.go b/server/server.go index 9d549fa..073c110 100644 --- a/server/server.go +++ b/server/server.go @@ -7,8 +7,8 @@ import ( "net/http" "time" - "github.com/glass-cms/glasscms/internal/mediatype" - "github.com/glass-cms/glasscms/internal/middleware" + "github.com/glass-cms/glasscms/pkg/mediatype" + "github.com/glass-cms/glasscms/pkg/middleware" "github.com/glass-cms/glasscms/server/handler" ) diff --git a/typespec/main.tsp b/typespec/main.tsp index 7fbd8c0..4e71eff 100644 --- a/typespec/main.tsp +++ b/typespec/main.tsp @@ -1,7 +1,6 @@ import "@typespec/http"; import "@typespec/rest"; import "@typespec/openapi3"; -import "@typespec/versioning"; import "./error.tsp"; using TypeSpec.Http; @@ -10,7 +9,6 @@ using TypeSpec.Rest; @service({ title: "GlassCMS API", }) -@TypeSpec.Versioning.versioned(Versions) namespace GlassCMSCore; enum Versions { From c9215f62c13c3c173c75406919158929eda1a6cd Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 12:11:13 +0200 Subject: [PATCH 6/7] refactor: Move server to internal package --- cmd/server/start.go | 6 +++--- {server => internal/server}/handler/handler.go | 0 {server => internal/server}/handler/serialize.go | 0 {server => internal/server}/handler/v1/error_handler.go | 2 +- .../server}/handler/v1/error_handler_test.go | 2 +- {server => internal/server}/handler/v1/errors.go | 0 {server => internal/server}/handler/v1/errors_test.go | 2 +- {server => internal/server}/handler/v1/handler_v1.go | 2 +- {server => internal/server}/handler/v1/item.go | 2 +- {server => internal/server}/handler/v1/item_test.go | 2 +- {server => internal/server}/options.go | 0 {server => internal/server}/server.go | 2 +- 12 files changed, 10 insertions(+), 10 deletions(-) rename {server => internal/server}/handler/handler.go (100%) rename {server => internal/server}/handler/serialize.go (100%) rename {server => internal/server}/handler/v1/error_handler.go (96%) rename {server => internal/server}/handler/v1/error_handler_test.go (97%) rename {server => internal/server}/handler/v1/errors.go (100%) rename {server => internal/server}/handler/v1/errors_test.go (97%) rename {server => internal/server}/handler/v1/handler_v1.go (96%) rename {server => internal/server}/handler/v1/item.go (95%) rename {server => internal/server}/handler/v1/item_test.go (97%) rename {server => internal/server}/options.go (100%) rename {server => internal/server}/server.go (96%) diff --git a/cmd/server/start.go b/cmd/server/start.go index 8df548f..0f75407 100644 --- a/cmd/server/start.go +++ b/cmd/server/start.go @@ -8,10 +8,10 @@ import ( "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" + "github.com/glass-cms/glasscms/internal/server" + "github.com/glass-cms/glasscms/internal/server/handler" + v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" ctx "github.com/glass-cms/glasscms/pkg/context" - "github.com/glass-cms/glasscms/server" - "github.com/glass-cms/glasscms/server/handler" - v1 "github.com/glass-cms/glasscms/server/handler/v1" "github.com/lmittmann/tint" "github.com/spf13/cobra" "github.com/spf13/viper" diff --git a/server/handler/handler.go b/internal/server/handler/handler.go similarity index 100% rename from server/handler/handler.go rename to internal/server/handler/handler.go diff --git a/server/handler/serialize.go b/internal/server/handler/serialize.go similarity index 100% rename from server/handler/serialize.go rename to internal/server/handler/serialize.go diff --git a/server/handler/v1/error_handler.go b/internal/server/handler/v1/error_handler.go similarity index 96% rename from server/handler/v1/error_handler.go rename to internal/server/handler/v1/error_handler.go index d71b604..b2989f9 100644 --- a/server/handler/v1/error_handler.go +++ b/internal/server/handler/v1/error_handler.go @@ -5,7 +5,7 @@ import ( "reflect" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/server/handler" + "github.com/glass-cms/glasscms/internal/server/handler" ) // ErrorMapper is a function that maps an error to an API error response. diff --git a/server/handler/v1/error_handler_test.go b/internal/server/handler/v1/error_handler_test.go similarity index 97% rename from server/handler/v1/error_handler_test.go rename to internal/server/handler/v1/error_handler_test.go index 094e879..5d1f037 100644 --- a/server/handler/v1/error_handler_test.go +++ b/internal/server/handler/v1/error_handler_test.go @@ -9,8 +9,8 @@ import ( "testing" api "github.com/glass-cms/glasscms/api/v1" + v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" "github.com/glass-cms/glasscms/pkg/resource" - v1 "github.com/glass-cms/glasscms/server/handler/v1" ) func TestErrorHandler_HandleError(t *testing.T) { diff --git a/server/handler/v1/errors.go b/internal/server/handler/v1/errors.go similarity index 100% rename from server/handler/v1/errors.go rename to internal/server/handler/v1/errors.go diff --git a/server/handler/v1/errors_test.go b/internal/server/handler/v1/errors_test.go similarity index 97% rename from server/handler/v1/errors_test.go rename to internal/server/handler/v1/errors_test.go index b0c0425..e5f5a5d 100644 --- a/server/handler/v1/errors_test.go +++ b/internal/server/handler/v1/errors_test.go @@ -5,8 +5,8 @@ import ( "testing" v1 "github.com/glass-cms/glasscms/api/v1" + v1_handler "github.com/glass-cms/glasscms/internal/server/handler/v1" "github.com/glass-cms/glasscms/pkg/resource" - v1_handler "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/require" ) diff --git a/server/handler/v1/handler_v1.go b/internal/server/handler/v1/handler_v1.go similarity index 96% rename from server/handler/v1/handler_v1.go rename to internal/server/handler/v1/handler_v1.go index 8ce772e..7835342 100644 --- a/server/handler/v1/handler_v1.go +++ b/internal/server/handler/v1/handler_v1.go @@ -8,8 +8,8 @@ import ( v1 "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/item" + "github.com/glass-cms/glasscms/internal/server/handler" "github.com/glass-cms/glasscms/pkg/resource" - "github.com/glass-cms/glasscms/server/handler" ) type APIHandler struct { diff --git a/server/handler/v1/item.go b/internal/server/handler/v1/item.go similarity index 95% rename from server/handler/v1/item.go rename to internal/server/handler/v1/item.go index ea04dd3..4b7f78f 100644 --- a/server/handler/v1/item.go +++ b/internal/server/handler/v1/item.go @@ -7,7 +7,7 @@ import ( "net/http" v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/server/handler" + "github.com/glass-cms/glasscms/internal/server/handler" ) func (s *APIHandler) ItemsCreate(w http.ResponseWriter, r *http.Request) { diff --git a/server/handler/v1/item_test.go b/internal/server/handler/v1/item_test.go similarity index 97% rename from server/handler/v1/item_test.go rename to internal/server/handler/v1/item_test.go index ea11b94..9f6d228 100644 --- a/server/handler/v1/item_test.go +++ b/internal/server/handler/v1/item_test.go @@ -10,8 +10,8 @@ import ( api "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" + v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" "github.com/glass-cms/glasscms/pkg/log" - v1 "github.com/glass-cms/glasscms/server/handler/v1" "github.com/stretchr/testify/assert" ) diff --git a/server/options.go b/internal/server/options.go similarity index 100% rename from server/options.go rename to internal/server/options.go diff --git a/server/server.go b/internal/server/server.go similarity index 96% rename from server/server.go rename to internal/server/server.go index 073c110..4921b34 100644 --- a/server/server.go +++ b/internal/server/server.go @@ -7,9 +7,9 @@ import ( "net/http" "time" + "github.com/glass-cms/glasscms/internal/server/handler" "github.com/glass-cms/glasscms/pkg/mediatype" "github.com/glass-cms/glasscms/pkg/middleware" - "github.com/glass-cms/glasscms/server/handler" ) const ( From 113fa9f97a90704507e02b9b452436509109c515 Mon Sep 17 00:00:00 2001 From: Maikel Veen Date: Sat, 28 Sep 2024 12:39:35 +0200 Subject: [PATCH 7/7] refactor: Simplify server and remove versioned handlers --- api/v1/api.gen.go | 252 ------------------ api/v1/error.go | 11 - api/v1/item.go | 40 --- api/v1/item_test.go | 121 --------- cmd/server/start.go | 5 +- .../server/{handler/v1 => }/error_handler.go | 19 +- .../{handler/v1 => }/error_handler_test.go | 8 +- internal/server/{handler/v1 => }/errors.go | 29 +- .../server/{handler/v1 => }/errors_test.go | 30 +-- internal/server/handler/handler.go | 9 - internal/server/handler/v1/handler_v1.go | 67 ----- internal/server/handler/v1/item.go | 53 ---- internal/server/item.go | 88 ++++++ internal/server/{handler/v1 => }/item_test.go | 22 +- internal/server/{handler => }/serialize.go | 2 +- internal/server/server.go | 58 +++- 16 files changed, 199 insertions(+), 615 deletions(-) delete mode 100644 api/v1/api.gen.go delete mode 100644 api/v1/error.go delete mode 100644 api/v1/item.go delete mode 100644 api/v1/item_test.go rename internal/server/{handler/v1 => }/error_handler.go (72%) rename internal/server/{handler/v1 => }/error_handler_test.go (93%) rename internal/server/{handler/v1 => }/errors.go (57%) rename internal/server/{handler/v1 => }/errors_test.go (74%) delete mode 100644 internal/server/handler/handler.go delete mode 100644 internal/server/handler/v1/handler_v1.go delete mode 100644 internal/server/handler/v1/item.go create mode 100644 internal/server/item.go rename internal/server/{handler/v1 => }/item_test.go (88%) rename internal/server/{handler => }/serialize.go (98%) diff --git a/api/v1/api.gen.go b/api/v1/api.gen.go deleted file mode 100644 index 235bbdb..0000000 --- a/api/v1/api.gen.go +++ /dev/null @@ -1,252 +0,0 @@ -//go:build go1.22 - -// Package v1 provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. -package v1 - -import ( - "fmt" - "net/http" - "time" - - "github.com/oapi-codegen/runtime" -) - -// Defines values for ErrorCode. -const ( - ParameterInvalid ErrorCode = "parameter_invalid" - ParameterMissing ErrorCode = "parameter_missing" - ProcessingError ErrorCode = "processing_error" - ResourceAlreadyExists ErrorCode = "resource_already_exists" - ResourceMissing ErrorCode = "resource_missing" -) - -// Defines values for ErrorType. -const ( - ApiError ErrorType = "api_error" - InvalidRequestError ErrorType = "invalid_request_error" -) - -// Error Error is the response model when an API call is unsuccessful. -type Error struct { - Code ErrorCode `json:"code"` - Details map[string]interface{} `json:"details"` - Message string `json:"message"` - Type ErrorType `json:"type"` -} - -// ErrorCode defines model for ErrorCode. -type ErrorCode string - -// ErrorType defines model for ErrorType. -type ErrorType string - -// Item Item represents an individual content item. -type Item struct { - Content string `json:"content"` - CreateTime time.Time `json:"create_time"` - DeleteTime *time.Time `json:"delete_time,omitempty"` - DisplayName string `json:"display_name"` - Metadata map[string]interface{} `json:"metadata"` - Name string `json:"name"` - Properties map[string]interface{} `json:"properties"` - UpdateTime time.Time `json:"update_time"` -} - -// ItemCreate Resource create operation model. -type ItemCreate struct { - Content string `json:"content"` - CreateTime time.Time `json:"create_time"` - DisplayName string `json:"display_name"` - Metadata map[string]interface{} `json:"metadata"` - Name string `json:"name"` - Properties map[string]interface{} `json:"properties"` - UpdateTime time.Time `json:"update_time"` -} - -// ItemKey defines model for ItemKey. -type ItemKey = string - -// ItemsCreateJSONRequestBody defines body for ItemsCreate for application/json ContentType. -type ItemsCreateJSONRequestBody = ItemCreate - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (POST /items) - ItemsCreate(w http.ResponseWriter, r *http.Request) - - // (GET /items/{name}) - ItemsGet(w http.ResponseWriter, r *http.Request, name ItemKey) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -type MiddlewareFunc func(http.Handler) http.Handler - -// ItemsCreate operation middleware -func (siw *ServerInterfaceWrapper) ItemsCreate(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ItemsCreate(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -// ItemsGet operation middleware -func (siw *ServerInterfaceWrapper) ItemsGet(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // ------------- Path parameter "name" ------------- - var name ItemKey - - err = runtime.BindStyledParameterWithOptions("simple", "name", r.PathValue("name"), &name, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) - return - } - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ItemsGet(w, r, name) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -type UnescapedCookieParamError struct { - ParamName string - Err error -} - -func (e *UnescapedCookieParamError) Error() string { - return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) -} - -func (e *UnescapedCookieParamError) Unwrap() error { - return e.Err -} - -type UnmarshalingParamError struct { - ParamName string - Err error -} - -func (e *UnmarshalingParamError) Error() string { - return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) -} - -func (e *UnmarshalingParamError) Unwrap() error { - return e.Err -} - -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -type RequiredHeaderError struct { - ParamName string - Err error -} - -func (e *RequiredHeaderError) Error() string { - return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) -} - -func (e *RequiredHeaderError) Unwrap() error { - return e.Err -} - -type InvalidParamFormatError struct { - ParamName string - Err error -} - -func (e *InvalidParamFormatError) Error() string { - return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) -} - -func (e *InvalidParamFormatError) Unwrap() error { - return e.Err -} - -type TooManyValuesForParamError struct { - ParamName string - Count int -} - -func (e *TooManyValuesForParamError) Error() string { - return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) -} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{}) -} - -type StdHTTPServerOptions struct { - BaseURL string - BaseRouter *http.ServeMux - Middlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{ - BaseRouter: m, - }) -} - -func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{ - BaseURL: baseURL, - BaseRouter: m, - }) -} - -// HandlerWithOptions creates http.Handler with additional options -func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { - m := options.BaseRouter - - if m == nil { - m = http.NewServeMux() - } - if options.ErrorHandlerFunc == nil { - options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, - } - - m.HandleFunc("POST "+options.BaseURL+"/items", wrapper.ItemsCreate) - m.HandleFunc("GET "+options.BaseURL+"/items/{name}", wrapper.ItemsGet) - - return m -} diff --git a/api/v1/error.go b/api/v1/error.go deleted file mode 100644 index d823379..0000000 --- a/api/v1/error.go +++ /dev/null @@ -1,11 +0,0 @@ -package v1 - -import "net/http" - -var ErrorCodeMapping = map[ErrorCode]int{ - ParameterInvalid: http.StatusBadRequest, - ParameterMissing: http.StatusBadRequest, - ProcessingError: http.StatusInternalServerError, - ResourceAlreadyExists: http.StatusConflict, - ResourceMissing: http.StatusNotFound, -} diff --git a/api/v1/item.go b/api/v1/item.go deleted file mode 100644 index 045e21e..0000000 --- a/api/v1/item.go +++ /dev/null @@ -1,40 +0,0 @@ -package v1 - -import ( - "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/internal/parser" -) - -// ToItem converts an api.ItemCreate to an item.Item. -func (i *ItemCreate) ToItem() *item.Item { - if i == nil { - return nil - } - - return &item.Item{ - Name: i.Name, - DisplayName: i.DisplayName, - Content: i.Content, - Hash: parser.HashContent([]byte(i.Content)), - CreateTime: i.CreateTime, - UpdateTime: i.UpdateTime, - Properties: i.Properties, - Metadata: i.Metadata, - } -} - -func FromItem(item *item.Item) *Item { - if item == nil { - return nil - } - - return &Item{ - Name: item.Name, - DisplayName: item.DisplayName, - Content: item.Content, - CreateTime: item.CreateTime, - UpdateTime: item.UpdateTime, - Properties: item.Properties, - Metadata: item.Metadata, - } -} diff --git a/api/v1/item_test.go b/api/v1/item_test.go deleted file mode 100644 index 967b428..0000000 --- a/api/v1/item_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package v1_test - -import ( - "testing" - "time" - - v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/internal/parser" - "github.com/stretchr/testify/assert" -) - -func TestItem_MapToDomain(t *testing.T) { - t.Parallel() - - type fields struct { - Content string - CreateTime time.Time - DisplayName string - ID string - Name string - Properties map[string]interface{} - UpdateTime time.Time - } - - tests := []struct { - name string - fields fields - want *item.Item - }{ - { - name: "Complete Item Mapping", - fields: fields{ - Content: "Test Content", - CreateTime: time.Now().Add(-24 * time.Hour), - DisplayName: "Test Display Name", - ID: "1234", - Name: "Test Name", - Properties: map[string]interface{}{"key1": "value1", "key2": "value2"}, - UpdateTime: time.Now(), - }, - want: &item.Item{ - Name: "Test Name", - DisplayName: "Test Display Name", - Content: "Test Content", - Hash: parser.HashContent([]byte("Test Content")), - CreateTime: time.Now().Add(-24 * time.Hour), - UpdateTime: time.Now(), - Properties: map[string]any{"key1": "value1", "key2": "value2"}, - }, - }, - { - name: "Empty Item Mapping", - fields: fields{ - Content: "", - CreateTime: time.Time{}, - DisplayName: "", - ID: "", - Name: "", - Properties: nil, - UpdateTime: time.Time{}, - }, - want: &item.Item{ - Name: "", - DisplayName: "", - Content: "", - Hash: parser.HashContent([]byte("")), - CreateTime: time.Time{}, - UpdateTime: time.Time{}, - Properties: nil, - }, - }, - { - name: "Nil Properties Mapping", - fields: fields{ - Content: "Test Content", - CreateTime: time.Now().Add(-24 * time.Hour), - DisplayName: "Test Display Name", - ID: "5678", - Name: "Test Name 2", - Properties: nil, - UpdateTime: time.Now(), - }, - want: &item.Item{ - Name: "Test Name 2", - Content: "Test Content", - DisplayName: "Test Display Name", - Hash: parser.HashContent([]byte("Test Content")), - CreateTime: time.Now().Add(-24 * time.Hour), - UpdateTime: time.Now(), - Properties: nil, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - apiItem := &v1.ItemCreate{ - Content: tt.fields.Content, - CreateTime: tt.fields.CreateTime, - DisplayName: tt.fields.DisplayName, - Name: tt.fields.Name, - Properties: tt.fields.Properties, - UpdateTime: tt.fields.UpdateTime, - } - got := apiItem.ToItem() - - // Adjust for potential differences in time (e.g., slight differences due to test execution timing) - if !got.CreateTime.IsZero() && !tt.want.CreateTime.IsZero() { - got.CreateTime = tt.want.CreateTime - } - if !got.UpdateTime.IsZero() && !tt.want.UpdateTime.IsZero() { - got.UpdateTime = tt.want.UpdateTime - } - - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/cmd/server/start.go b/cmd/server/start.go index 0f75407..06808d3 100644 --- a/cmd/server/start.go +++ b/cmd/server/start.go @@ -9,8 +9,6 @@ import ( "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" "github.com/glass-cms/glasscms/internal/server" - "github.com/glass-cms/glasscms/internal/server/handler" - v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" ctx "github.com/glass-cms/glasscms/pkg/context" "github.com/lmittmann/tint" "github.com/spf13/cobra" @@ -95,9 +93,8 @@ func (c *StartCommand) Execute(cmd *cobra.Command, _ []string) error { repo := item.NewRepository(db, errHandler) service := item.NewService(repo) - v1Handler := v1.NewAPIHandler(c.logger, service) - server, err := server.New(c.logger, []handler.VersionedHandler{v1Handler}) + server, err := server.New(c.logger, service) if err != nil { return err } diff --git a/internal/server/handler/v1/error_handler.go b/internal/server/error_handler.go similarity index 72% rename from internal/server/handler/v1/error_handler.go rename to internal/server/error_handler.go index b2989f9..b44cdc5 100644 --- a/internal/server/handler/v1/error_handler.go +++ b/internal/server/error_handler.go @@ -1,15 +1,14 @@ -package v1 +package server import ( "net/http" "reflect" - v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/server/handler" + "github.com/glass-cms/glasscms/pkg/api" ) // ErrorMapper is a function that maps an error to an API error response. -type ErrorMapper func(error) *v1.Error +type ErrorMapper func(error) *api.Error type ErrorHandler struct { Mappers map[reflect.Type]ErrorMapper @@ -37,20 +36,20 @@ func (h *ErrorHandler) HandleError(w http.ResponseWriter, r *http.Request, err e if mapper, exists := h.Mappers[errType]; exists { errResp := mapper(err) - statusCode, ok := v1.ErrorCodeMapping[errResp.Code] + statusCode, ok := ErrorCodeMapping[errResp.Code] if !ok { statusCode = http.StatusInternalServerError } - handler.SerializeResponse(w, r, statusCode, errResp) + SerializeResponse(w, r, statusCode, errResp) return } // Fallback on generic error response if we don't have a specific error mapper. - errResp := &v1.Error{ - Code: v1.ProcessingError, + errResp := &api.Error{ + Code: api.ProcessingError, Message: "An error occurred while processing the request.", - Type: v1.ApiError, + Type: api.ApiError, } - handler.SerializeResponse(w, r, http.StatusInternalServerError, errResp) + SerializeResponse(w, r, http.StatusInternalServerError, errResp) } diff --git a/internal/server/handler/v1/error_handler_test.go b/internal/server/error_handler_test.go similarity index 93% rename from internal/server/handler/v1/error_handler_test.go rename to internal/server/error_handler_test.go index 5d1f037..fd7fcf1 100644 --- a/internal/server/handler/v1/error_handler_test.go +++ b/internal/server/error_handler_test.go @@ -1,4 +1,4 @@ -package v1_test +package server_test import ( "encoding/json" @@ -8,15 +8,15 @@ import ( "reflect" "testing" - api "github.com/glass-cms/glasscms/api/v1" - v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" + "github.com/glass-cms/glasscms/internal/server" + "github.com/glass-cms/glasscms/pkg/api" "github.com/glass-cms/glasscms/pkg/resource" ) func TestErrorHandler_HandleError(t *testing.T) { t.Parallel() - errorHandler := v1.NewErrorHandler() + errorHandler := server.NewErrorHandler() errorHandler.RegisterErrorMapper(reflect.TypeOf(&resource.AlreadyExistsError{}), func(_ error) *api.Error { return &api.Error{ Code: api.ResourceAlreadyExists, diff --git a/internal/server/handler/v1/errors.go b/internal/server/errors.go similarity index 57% rename from internal/server/handler/v1/errors.go rename to internal/server/errors.go index 005e292..e5ed6c9 100644 --- a/internal/server/handler/v1/errors.go +++ b/internal/server/errors.go @@ -1,24 +1,25 @@ -package v1 +package server import ( "errors" "fmt" + "net/http" - v1 "github.com/glass-cms/glasscms/api/v1" + "github.com/glass-cms/glasscms/pkg/api" "github.com/glass-cms/glasscms/pkg/resource" ) // ErrorMapperAlreadyExistsError maps a resource.AlreadyExistsError to an API error response. -func ErrorMapperAlreadyExistsError(err error) *v1.Error { +func ErrorMapperAlreadyExistsError(err error) *api.Error { var alreadyExistsErr *resource.AlreadyExistsError if !errors.As(err, &alreadyExistsErr) { panic("error is not a resource.AlreadyExistsError") } - return &v1.Error{ - Code: v1.ResourceAlreadyExists, + return &api.Error{ + Code: api.ResourceAlreadyExists, Message: fmt.Sprintf("An %s with the name already exists", alreadyExistsErr.Resource), - Type: v1.ApiError, + Type: api.ApiError, Details: map[string]interface{}{ "resource": alreadyExistsErr.Resource, "name": alreadyExistsErr.Name, @@ -26,19 +27,27 @@ func ErrorMapperAlreadyExistsError(err error) *v1.Error { } } -func ErrorMapperNotFoundError(err error) *v1.Error { +func ErrorMapperNotFoundError(err error) *api.Error { var notFoundErr *resource.NotFoundError if !errors.As(err, ¬FoundErr) { panic("error is not a resource.NotFoundError") } - return &v1.Error{ - Code: v1.ResourceMissing, + return &api.Error{ + Code: api.ResourceMissing, Message: fmt.Sprintf("The %s with the name was not found", notFoundErr.Resource), - Type: v1.ApiError, + Type: api.ApiError, Details: map[string]interface{}{ "resource": notFoundErr.Resource, "name": notFoundErr.Name, }, } } + +var ErrorCodeMapping = map[api.ErrorCode]int{ + api.ParameterInvalid: http.StatusBadRequest, + api.ParameterMissing: http.StatusBadRequest, + api.ProcessingError: http.StatusInternalServerError, + api.ResourceAlreadyExists: http.StatusConflict, + api.ResourceMissing: http.StatusNotFound, +} diff --git a/internal/server/handler/v1/errors_test.go b/internal/server/errors_test.go similarity index 74% rename from internal/server/handler/v1/errors_test.go rename to internal/server/errors_test.go index e5f5a5d..e78b279 100644 --- a/internal/server/handler/v1/errors_test.go +++ b/internal/server/errors_test.go @@ -1,11 +1,11 @@ -package v1_test +package server_test import ( "errors" "testing" - v1 "github.com/glass-cms/glasscms/api/v1" - v1_handler "github.com/glass-cms/glasscms/internal/server/handler/v1" + "github.com/glass-cms/glasscms/internal/server" + "github.com/glass-cms/glasscms/pkg/api" "github.com/glass-cms/glasscms/pkg/resource" "github.com/stretchr/testify/require" ) @@ -18,17 +18,17 @@ func TestErrorMapperAlreadyExistsError(t *testing.T) { } tests := map[string]struct { args args - want *v1.Error + want *api.Error expectPanics bool }{ "maps resource.AlreadyExistsError to an API error response": { args: args{ err: resource.NewAlreadyExistsError("item1", "item", errors.New("underlying error")), }, - want: &v1.Error{ - Code: v1.ResourceAlreadyExists, + want: &api.Error{ + Code: api.ResourceAlreadyExists, Message: "An item with the name already exists", - Type: v1.ApiError, + Type: api.ApiError, Details: map[string]interface{}{ "resource": "item", "name": "item1", @@ -48,12 +48,12 @@ func TestErrorMapperAlreadyExistsError(t *testing.T) { if tt.expectPanics { require.Panics(t, func() { - v1_handler.ErrorMapperAlreadyExistsError(tt.args.err) + server.ErrorMapperAlreadyExistsError(tt.args.err) }) return } - require.Equal(t, tt.want, v1_handler.ErrorMapperAlreadyExistsError(tt.args.err)) + require.Equal(t, tt.want, server.ErrorMapperAlreadyExistsError(tt.args.err)) }) } } @@ -66,17 +66,17 @@ func TestErrorMapperNotFoundError(t *testing.T) { } tests := map[string]struct { args args - want *v1.Error + want *api.Error expectPanics bool }{ "maps resource.NotFoundError to an API error response": { args: args{ err: resource.NewNotFoundError("item1", "item", errors.New("underlying error")), }, - want: &v1.Error{ - Code: v1.ResourceMissing, + want: &api.Error{ + Code: api.ResourceMissing, Message: "The item with the name was not found", - Type: v1.ApiError, + Type: api.ApiError, Details: map[string]interface{}{ "resource": "item", "name": "item1", @@ -96,12 +96,12 @@ func TestErrorMapperNotFoundError(t *testing.T) { if tt.expectPanics { require.Panics(t, func() { - v1_handler.ErrorMapperNotFoundError(tt.args.err) + server.ErrorMapperNotFoundError(tt.args.err) }) return } - require.Equal(t, tt.want, v1_handler.ErrorMapperNotFoundError(tt.args.err)) + require.Equal(t, tt.want, server.ErrorMapperNotFoundError(tt.args.err)) }) } } diff --git a/internal/server/handler/handler.go b/internal/server/handler/handler.go deleted file mode 100644 index c581fae..0000000 --- a/internal/server/handler/handler.go +++ /dev/null @@ -1,9 +0,0 @@ -package handler - -import "net/http" - -// VersionedHandler is an interface that defines an HTTP handler. -type VersionedHandler interface { - // HttpHandler returns an http.Handler that implements the API for a specific version. - Handler(baseRouter *http.ServeMux, middlewares []func(http.Handler) http.Handler) http.Handler -} diff --git a/internal/server/handler/v1/handler_v1.go b/internal/server/handler/v1/handler_v1.go deleted file mode 100644 index 7835342..0000000 --- a/internal/server/handler/v1/handler_v1.go +++ /dev/null @@ -1,67 +0,0 @@ -// Package v1 implements the API handlers for the v1 version of the Glass CMS API. -package v1 - -import ( - "log/slog" - "net/http" - "reflect" - - v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/item" - "github.com/glass-cms/glasscms/internal/server/handler" - "github.com/glass-cms/glasscms/pkg/resource" -) - -type APIHandler struct { - logger *slog.Logger - itemService *item.Service - - errorHandler *ErrorHandler -} - -// NewAPIHandler returns a new instance of ApiHandler. -func NewAPIHandler( - logger *slog.Logger, - service *item.Service, -) *APIHandler { - return &APIHandler{ - logger: logger, - itemService: service, - errorHandler: NewErrorHandler(), - } -} - -// Handler returns an http.Handler that implements the API. -func (s *APIHandler) Handler( - baseRouter *http.ServeMux, - middlewares []func(http.Handler) http.Handler, -) http.Handler { - convertedMiddlewares := make([]v1.MiddlewareFunc, len(middlewares)) - for i, mw := range middlewares { - convertedMiddlewares[i] = v1.MiddlewareFunc(mw) - } - - s.registerErrorMappers() - - return v1.HandlerWithOptions(s, v1.StdHTTPServerOptions{ - BaseURL: "/v1", - BaseRouter: baseRouter, - Middlewares: convertedMiddlewares, - ErrorHandlerFunc: s.errorHandler.HandleError, - }) -} - -func (s *APIHandler) registerErrorMappers() { - s.errorHandler.RegisterErrorMapper( - reflect.TypeOf(&resource.AlreadyExistsError{}), - ErrorMapperAlreadyExistsError, - ) - - s.errorHandler.RegisterErrorMapper( - reflect.TypeOf(&resource.NotFoundError{}), - ErrorMapperNotFoundError, - ) -} - -var _ v1.ServerInterface = (*APIHandler)(nil) -var _ handler.VersionedHandler = (*APIHandler)(nil) diff --git a/internal/server/handler/v1/item.go b/internal/server/handler/v1/item.go deleted file mode 100644 index 4b7f78f..0000000 --- a/internal/server/handler/v1/item.go +++ /dev/null @@ -1,53 +0,0 @@ -package v1 - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - - v1 "github.com/glass-cms/glasscms/api/v1" - "github.com/glass-cms/glasscms/internal/server/handler" -) - -func (s *APIHandler) ItemsCreate(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.logger.ErrorContext(ctx, fmt.Errorf("failed to read request body: %w", err).Error()) - s.errorHandler.HandleError(w, r, err) - return - } - - var request *v1.ItemsCreateJSONRequestBody - if err = json.Unmarshal(reqBody, &request); err != nil { - s.logger.ErrorContext(ctx, fmt.Errorf("failed to unmarshal request body: %w", err).Error()) - s.errorHandler.HandleError(w, r, err) - return - } - - err = s.itemService.CreateItem(ctx, request.ToItem()) - if err != nil { - s.logger.ErrorContext(ctx, fmt.Errorf("failed to create item: %w", err).Error()) - s.errorHandler.HandleError(w, r, err) - return - } - - // TODO: Write response. - - w.WriteHeader(http.StatusCreated) -} - -func (s *APIHandler) ItemsGet(w http.ResponseWriter, r *http.Request, name v1.ItemKey) { - ctx := r.Context() - - item, err := s.itemService.GetItem(ctx, name) - if err != nil { - s.logger.ErrorContext(ctx, fmt.Errorf("failed to get item: %w", err).Error()) - s.errorHandler.HandleError(w, r, err) - return - } - - handler.SerializeResponse(w, r, http.StatusOK, item) -} diff --git a/internal/server/item.go b/internal/server/item.go new file mode 100644 index 0000000..5f3b1b7 --- /dev/null +++ b/internal/server/item.go @@ -0,0 +1,88 @@ +package server + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/glass-cms/glasscms/internal/item" + "github.com/glass-cms/glasscms/internal/parser" + "github.com/glass-cms/glasscms/pkg/api" +) + +func (s *Server) ItemsCreate(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + reqBody, err := io.ReadAll(r.Body) + if err != nil { + s.logger.ErrorContext(ctx, fmt.Errorf("failed to read request body: %w", err).Error()) + s.errorHandler.HandleError(w, r, err) + return + } + + var request *api.ItemsCreateJSONRequestBody + if err = json.Unmarshal(reqBody, &request); err != nil { + s.logger.ErrorContext(ctx, fmt.Errorf("failed to unmarshal request body: %w", err).Error()) + s.errorHandler.HandleError(w, r, err) + return + } + + err = s.itemService.CreateItem(ctx, ToItem(request)) + if err != nil { + s.logger.ErrorContext(ctx, fmt.Errorf("failed to create item: %w", err).Error()) + s.errorHandler.HandleError(w, r, err) + return + } + + // TODO: Write response. + + w.WriteHeader(http.StatusCreated) +} + +func (s *Server) ItemsGet(w http.ResponseWriter, r *http.Request, name api.ItemKey) { + ctx := r.Context() + + item, err := s.itemService.GetItem(ctx, name) + if err != nil { + s.logger.ErrorContext(ctx, fmt.Errorf("failed to get item: %w", err).Error()) + s.errorHandler.HandleError(w, r, err) + return + } + + SerializeResponse(w, r, http.StatusOK, item) +} + +// ToItem converts an api.ItemCreate to an item.Item. +func ToItem(i *api.ItemCreate) *item.Item { + if i == nil { + return nil + } + + return &item.Item{ + Name: i.Name, + DisplayName: i.DisplayName, + Content: i.Content, + Hash: parser.HashContent([]byte(i.Content)), + CreateTime: i.CreateTime, + UpdateTime: i.UpdateTime, + Properties: i.Properties, + Metadata: i.Metadata, + } +} + +func FromItem(item *item.Item) *api.Item { + if item == nil { + return nil + } + + return &api.Item{ + Name: item.Name, + DisplayName: item.DisplayName, + Content: item.Content, + CreateTime: item.CreateTime, + UpdateTime: item.UpdateTime, + Properties: item.Properties, + Metadata: item.Metadata, + } +} diff --git a/internal/server/handler/v1/item_test.go b/internal/server/item_test.go similarity index 88% rename from internal/server/handler/v1/item_test.go rename to internal/server/item_test.go index 9f6d228..eaf3aa4 100644 --- a/internal/server/handler/v1/item_test.go +++ b/internal/server/item_test.go @@ -1,4 +1,4 @@ -package v1_test +package server_test import ( "bytes" @@ -7,10 +7,10 @@ import ( "net/http/httptest" "testing" - api "github.com/glass-cms/glasscms/api/v1" "github.com/glass-cms/glasscms/internal/database" "github.com/glass-cms/glasscms/internal/item" - v1 "github.com/glass-cms/glasscms/internal/server/handler/v1" + "github.com/glass-cms/glasscms/internal/server" + "github.com/glass-cms/glasscms/pkg/api" "github.com/glass-cms/glasscms/pkg/log" "github.com/stretchr/testify/assert" ) @@ -53,10 +53,14 @@ func TestAPIHandler_ItemsCreate(t *testing.T) { repo := item.NewRepository(testdb, &database.SqliteErrorHandler{}) - handler := v1.NewAPIHandler( + handler, err := server.New( log.NoopLogger(), item.NewService(repo), ) + if err != nil { + t.Fatal(err) + return + } rr := httptest.NewRecorder() request := tt.req() @@ -99,17 +103,21 @@ func TestAPIHandler_ItemsGet(t *testing.T) { repo := item.NewRepository(testdb, &database.SqliteErrorHandler{}) - handler := v1.NewAPIHandler( + server, err := server.New( log.NoopLogger(), item.NewService(repo), - ).Handler(http.NewServeMux(), []func(http.Handler) http.Handler{}) + ) + if err != nil { + t.Fatal(err) + return + } rr := httptest.NewRecorder() request := tt.req() request.Header.Set("Accept", "application/json") // Make the request - handler.ServeHTTP(rr, request) + server.Handler().ServeHTTP(rr, request) // Assert assert.Equal(t, tt.expected, rr.Code) diff --git a/internal/server/handler/serialize.go b/internal/server/serialize.go similarity index 98% rename from internal/server/handler/serialize.go rename to internal/server/serialize.go index 95d108a..5ecc518 100644 --- a/internal/server/handler/serialize.go +++ b/internal/server/serialize.go @@ -1,4 +1,4 @@ -package handler +package server import ( "encoding/json" diff --git a/internal/server/server.go b/internal/server/server.go index 4921b34..e5520d8 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -5,11 +5,14 @@ import ( "fmt" "log/slog" "net/http" + "reflect" "time" - "github.com/glass-cms/glasscms/internal/server/handler" + "github.com/glass-cms/glasscms/internal/item" + "github.com/glass-cms/glasscms/pkg/api" "github.com/glass-cms/glasscms/pkg/mediatype" "github.com/glass-cms/glasscms/pkg/middleware" + "github.com/glass-cms/glasscms/pkg/resource" ) const ( @@ -19,31 +22,47 @@ const ( DefaultWriteTimeout = 10 * time.Second ) +var _ api.ServerInterface = (*Server)(nil) + type Server struct { logger *slog.Logger server *http.Server + + itemService *item.Service + errorHandler *ErrorHandler + + handler http.Handler } func New( logger *slog.Logger, - handlers []handler.VersionedHandler, + itemService *item.Service, opts ...Option, ) (*Server, error) { + serveMux := http.NewServeMux() + server := &Server{ - logger: logger, + logger: logger, + itemService: itemService, + errorHandler: NewErrorHandler(), } - serveMux := http.NewServeMux() - - for _, h := range handlers { - _ = h.Handler(serveMux, []func(http.Handler) http.Handler{ - middleware.ContentType(mediatype.ApplicationJSON), - middleware.Accept(mediatype.ApplicationJSON), - }) + middlewares := []func(http.Handler) http.Handler{ + middleware.ContentType(mediatype.ApplicationJSON), + middleware.Accept(mediatype.ApplicationJSON), } + convertedMiddlewares := make([]api.MiddlewareFunc, len(middlewares)) + for i, mw := range middlewares { + convertedMiddlewares[i] = api.MiddlewareFunc(mw) + } + + server.handler = api.HandlerWithOptions(server, api.StdHTTPServerOptions{ + BaseURL: "", + BaseRouter: serveMux, + }) server.server = &http.Server{ - Handler: serveMux, + Handler: server.handler, Addr: fmt.Sprintf(":%v", DefaultPort), ReadTimeout: DefaultReadTimeout, WriteTimeout: DefaultWriteTimeout, @@ -55,6 +74,7 @@ func New( } } + server.registerErrorMappers() return server, nil } @@ -76,3 +96,19 @@ func (s *Server) Shutdown() { s.logger.Info("server stopped") } + +func (s *Server) Handler() http.Handler { + return s.handler +} + +func (s *Server) registerErrorMappers() { + s.errorHandler.RegisterErrorMapper( + reflect.TypeOf(&resource.AlreadyExistsError{}), + ErrorMapperAlreadyExistsError, + ) + + s.errorHandler.RegisterErrorMapper( + reflect.TypeOf(&resource.NotFoundError{}), + ErrorMapperNotFoundError, + ) +}