feat: support serverless in rest (#5001)

Signed-off-by: kevin <wanjunfeng@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Kevin Wan
2025-07-13 00:00:52 +08:00
committed by GitHub
parent a71e56de52
commit c9ff6a10d3
4 changed files with 106 additions and 2 deletions

View File

@@ -119,6 +119,16 @@ func (s *Server) Use(middleware Middleware) {
s.ngin.use(middleware) s.ngin.use(middleware)
} }
// build builds the Server and binds the routes to the router.
func (s *Server) build() error {
return s.ngin.bindRoutes(s.router)
}
// serve serves the HTTP requests using the Server's router.
func (s *Server) serve(w http.ResponseWriter, r *http.Request) {
s.router.ServeHTTP(w, r)
}
// ToMiddleware converts the given handler to a Middleware. // ToMiddleware converts the given handler to a Middleware.
func ToMiddleware(handler func(next http.Handler) http.Handler) Middleware { func ToMiddleware(handler func(next http.Handler) http.Handler) Middleware {
return func(handle http.HandlerFunc) http.HandlerFunc { return func(handle http.HandlerFunc) http.HandlerFunc {

View File

@@ -819,6 +819,6 @@ func TestServerEmbedFileSystem(t *testing.T) {
// serve(server, w, r) // serve(server, w, r)
// // verify the response // // verify the response
func serve(s *Server, w http.ResponseWriter, r *http.Request) { func serve(s *Server, w http.ResponseWriter, r *http.Request) {
s.ngin.bindRoutes(s.router) _ = s.build()
s.router.ServeHTTP(w, r) s.serve(w, r)
} }

27
rest/serverless.go Normal file
View File

@@ -0,0 +1,27 @@
package rest
import "net/http"
// Serverless is a wrapper around Server that allows it to be used in serverless environments.
type Serverless struct {
server *Server
}
// NewServerless creates a new Serverless instance from the provided Server.
func NewServerless(server *Server) (*Serverless, error) {
// Ensure the server is built before using it in a serverless context.
// Why not call server.build() when serving requests,
// is because we need to ensure fail fast behavior.
if err := server.build(); err != nil {
return nil, err
}
return &Serverless{
server: server,
}, nil
}
// Serve handles HTTP requests by delegating them to the underlying Server instance.
func (s *Serverless) Serve(w http.ResponseWriter, r *http.Request) {
s.server.serve(w, r)
}

67
rest/serverless_test.go Normal file
View File

@@ -0,0 +1,67 @@
package rest
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/logx/logtest"
)
func TestNewServerless(t *testing.T) {
logtest.Discard(t)
const configYaml = `
Name: foo
Host: localhost
Port: 0
`
var cnf RestConf
assert.Nil(t, conf.LoadFromYamlBytes([]byte(configYaml), &cnf))
svr, err := NewServer(cnf)
assert.NoError(t, err)
svr.AddRoute(Route{
Method: http.MethodGet,
Path: "/",
Handler: func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World"))
},
})
serverless, err := NewServerless(svr)
assert.NoError(t, err)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/", nil)
serverless.Serve(w, r)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "Hello World", w.Body.String())
}
func TestNewServerlessWithError(t *testing.T) {
logtest.Discard(t)
const configYaml = `
Name: foo
Host: localhost
Port: 0
`
var cnf RestConf
assert.Nil(t, conf.LoadFromYamlBytes([]byte(configYaml), &cnf))
svr, err := NewServer(cnf)
assert.NoError(t, err)
svr.AddRoute(Route{
Method: http.MethodGet,
Path: "notstartwith/",
Handler: nil,
})
_, err = NewServerless(svr)
assert.Error(t, err)
}