diff --git a/builder.go b/builder.go index d2d45f2..f7daa50 100644 --- a/builder.go +++ b/builder.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "io" "net/http" ) @@ -91,6 +92,12 @@ type Builder struct { writer func(writer http.ResponseWriter) } +// RawBuilder is a raw response that can be used +// to return a raw [http.Builder] from a [Handler]. +type RawBuilder struct { + http.Handler +} + var ( // ErrWriterRequiresFlusher is an error that determines that // the given response writer needs a flusher in order to push @@ -99,6 +106,12 @@ var ( ErrWriterRequiresFlusher = errors.New("response writer requires a flusher") ) +// Error implements the error interface +// for the Raw builder. +func (raw RawBuilder) Error() string { + return fmt.Sprintf("%v", raw.Handler) +} + // writeHeaders writes the given response headers by calling // [http.ResponseWriter]'s `WriteHeader` method. // @@ -231,6 +244,15 @@ func DefaultResponderHandler(writer http.ResponseWriter, request *http.Request, } } +// Raw is a used to create a [RawBuilder] response +// that can be used to return a [http.Handler] directly +// on [Handler] functions. +func Raw(handler http.Handler) RawBuilder { + return RawBuilder{ + Handler: handler, + } +} + // Response is used to create a builder with the given // HTTP status. // diff --git a/handler.go b/handler.go index a7862ed..d8c04f1 100644 --- a/handler.go +++ b/handler.go @@ -46,6 +46,11 @@ func handle(writer http.ResponseWriter, request *http.Request, err error, parent return } + if raw, ok := err.(RawResponder); ok { + raw.ServeHTTP(writer, request) + return + } + if responder, ok := err.(Responder); ok { handleResponder(writer, request, parent, responder) return @@ -67,6 +72,12 @@ func handle(writer http.ResponseWriter, request *http.Request, err error, parent Handle(writer, request) } +func RawHandler(handler http.Handler) Handler { + return func(*http.Request) error { + return Raw(handler) + } +} + // ServeHTTP implements the [http.Handler] interface to have // compatibility with the http package. func (handler Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { diff --git a/handler_test.go b/handler_test.go new file mode 100644 index 0000000..eaccdfb --- /dev/null +++ b/handler_test.go @@ -0,0 +1,46 @@ +package akumu_test + +import ( + "net/http" + "testing" + + "github.com/studiolambda/akumu" +) + +func exampleRawResponse(request *http.Request) error { + return akumu.Raw( + http.RedirectHandler("foo", http.StatusTemporaryRedirect), + ) +} + +func TestRawHandler(t *testing.T) { + handler := akumu.RawHandler(http.RedirectHandler("foo", http.StatusTemporaryRedirect)) + + request, err := http.NewRequest(http.MethodGet, "/", nil) + + if err != nil { + t.Fatal("failed to create http request") + } + + response := handler.Record(request) + + if expected := http.StatusTemporaryRedirect; response.Code != expected { + t.Fatalf("expected status code %d but got %d", expected, response.Code) + } +} + +func TestRawResponse(t *testing.T) { + handler := akumu.Handler(exampleRawResponse) + + request, err := http.NewRequest(http.MethodGet, "/", nil) + + if err != nil { + t.Fatal("failed to create http request") + } + + response := handler.Record(request) + + if expected := http.StatusTemporaryRedirect; response.Code != expected { + t.Fatalf("expected status code %d but got %d", expected, response.Code) + } +} diff --git a/responder.go b/responder.go index 675ed69..6830f51 100644 --- a/responder.go +++ b/responder.go @@ -14,3 +14,9 @@ import "net/http" type Responder interface { Respond(request *http.Request) Builder } + +// RawBuilder is a raw response that can be used +// to return a raw [http.Builder] from a [Handler]. +type RawResponder interface { + http.Handler +}