diff --git a/example/petstore/app/app.go b/example/petstore/app/app.go index 13d0ec4..7e84c98 100644 --- a/example/petstore/app/app.go +++ b/example/petstore/app/app.go @@ -19,7 +19,7 @@ type Config struct { rest.Config `config:",squash"` } -func Init(ctx context.Context, cfg Config) (rest.Api, error) { +func Init(ctx context.Context, cfg Config) (*mux.Router, error) { m := mux.New( cfg.OpenApi.Title, cfg.OpenApi.Version, diff --git a/example/petstore/endpoint/endpoint.go b/example/petstore/endpoint/endpoint.go new file mode 100644 index 0000000..86f8809 --- /dev/null +++ b/example/petstore/endpoint/endpoint.go @@ -0,0 +1,20 @@ +// Copyright (c) 2025 Z5Labs and Contributors +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +package endpoint + +import "github.com/z5labs/humus/rest/mux" + +type Router interface { + Route(method, pattern string, op mux.Operation) error +} + +func mustRoute(r Router, method, pattern string, op mux.Operation) { + err := r.Route(method, pattern, op) + if err == nil { + return + } + panic(err) +} diff --git a/example/petstore/endpoint/register_pet.go b/example/petstore/endpoint/register_pet.go index 72ad9c2..180cfad 100644 --- a/example/petstore/endpoint/register_pet.go +++ b/example/petstore/endpoint/register_pet.go @@ -12,7 +12,6 @@ import ( "github.com/z5labs/humus/example/petstore/pet" "go.opentelemetry.io/otel" - "github.com/z5labs/humus/rest/mux" "github.com/z5labs/humus/rest/rpc" ) @@ -24,19 +23,25 @@ type registerPetHandler struct { store RegisterPetStore } -func RegisterPet(m mux.Muxer, store RegisterPetStore) { +func RegisterPet(r Router, store RegisterPetStore) { h := ®isterPetHandler{ store: store, } - mux.MustRoute( - m, + mustRoute( + r, http.MethodPost, "/pet/register", rpc.NewOperation( rpc.ConsumesJson( rpc.ProducesJson(h), ), + rpc.Header( + "Authorization", + rpc.ValidateHeader(nil), + ), + rpc.QueryParam("start"), + rpc.PathParam("id"), ), ) } diff --git a/rest/mux/mux.go b/rest/mux/mux.go index 673290d..8d92c4b 100644 --- a/rest/mux/mux.go +++ b/rest/mux/mux.go @@ -13,7 +13,6 @@ import ( "github.com/z5labs/humus" "github.com/z5labs/humus/health" - "github.com/z5labs/humus/rest" "github.com/z5labs/humus/rest/embedded" "github.com/go-chi/chi/v5" @@ -87,10 +86,6 @@ type router interface { Method(string, string, http.Handler) } -// always ensure [Router] implements the [rest.Api] interface. -// if [Api] is ever changed this will lead to compilation error here. -var _ rest.Api = (*Router)(nil) - // Router is a HTTP request multiplexer which implements the [rest.Api] interface. // // Router provides a set of standard features: @@ -183,20 +178,6 @@ type Operation interface { Definition() (openapi3.Operation, error) } -// Muxer -type Muxer interface { - Route(method, pattern string, op Operation) error -} - -// MustRoute -func MustRoute(m Muxer, method, pattern string, op Operation) { - err := m.Route(method, pattern, op) - if err == nil { - return - } - panic(err) -} - // Route will configure any request matching method and pattern to be // handled by the provided [Operation]. It will also register the [Operation] // with an underlying OpenAPI 3.0 schema. diff --git a/rest/mux/mux_test.go b/rest/mux/mux_test.go index 66b73e7..5fadaf9 100644 --- a/rest/mux/mux_test.go +++ b/rest/mux/mux_test.go @@ -81,11 +81,14 @@ func TestRouter_ServeHTTP(t *testing.T) { })), ) - MustRoute(r, http.MethodGet, "/", noopDefinition{ + err := r.Route(http.MethodGet, "/", noopDefinition{ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), }) + if !assert.Nil(t, err) { + return + } w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/hello", nil) @@ -109,11 +112,14 @@ func TestRouter_ServeHTTP(t *testing.T) { })), ) - MustRoute(r, http.MethodGet, "/", noopDefinition{ + err := r.Route(http.MethodGet, "/", noopDefinition{ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }), }) + if !assert.Nil(t, err) { + return + } w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(``)) diff --git a/rest/rest.go b/rest/rest.go index fe58c7a..ed7a48a 100644 --- a/rest/rest.go +++ b/rest/rest.go @@ -22,7 +22,7 @@ import ( "github.com/z5labs/humus/buildcontext" "github.com/z5labs/humus/internal" "github.com/z5labs/humus/internal/httpserver" - "github.com/z5labs/humus/rest/embedded" + "github.com/z5labs/humus/rest/mux" "github.com/z5labs/bedrock" "github.com/z5labs/bedrock/app" @@ -71,13 +71,6 @@ func (c Config) HttpServer(ctx context.Context, h http.Handler) (*http.Server, e return s, nil } -// Api represents a HTTP handler which implements a RESTful API. -type Api interface { - embedded.Api - - http.Handler -} - // BuildContext represents more dynamic properties of the app building // process such as lifecycle hooks and OS signal interrupts. type BuildContext struct { @@ -103,12 +96,12 @@ func (bc *BuildContext) InterruptOn(signals ...os.Signal) { } // Run begins by reading, parsing and unmarshaling your custom config into -// the type T. Then it calls the providing function to initialize your [Api] -// implementation. Once it has the [Api] implementation, it begins serving -// the [Api] over HTTP. Various middlewares are applied at different stages +// the type T. Then it calls the providing function to initialize your [mux.Router] +// implementation. Once it has the [mux.Router] implementation, it begins serving +// the [mux.Router] over HTTP. Various middlewares are applied at different stages // for your convenience. Some middlewares include, automattic panic recovery, // OTel SDK initialization and shutdown, and OS signal based shutdown. -func Run[T Configer](r io.Reader, f func(context.Context, T) (Api, error)) { +func Run[T Configer](r io.Reader, f func(context.Context, T) (*mux.Router, error)) { err := bedrock.Run( context.Background(), // OTel middleware will handle shutting down OTel SDK components on PostRun