mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Per route api extensions (#542)
* Extend extension mechanism to support per-route API extensions * Tidy up comment * Remove print statement * Minor improvement to README * Avoid calling c.Request.Context() twice
This commit is contained in:
@@ -59,6 +59,54 @@ func (s *Server) apiAppHandlerWrapperFunc(apiHandler ApiAppHandler) gin.HandlerF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// per Route
|
||||||
|
|
||||||
|
type ApiRouteHandler interface {
|
||||||
|
// Handle(ctx context.Context)
|
||||||
|
ServeHTTP(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiRouteHandlerFunc func(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route)
|
||||||
|
|
||||||
|
// ServeHTTP calls f(w, r).
|
||||||
|
func (f ApiRouteHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route) {
|
||||||
|
f(w, r, app, route)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) apiRouteHandlerWrapperFunc(apiHandler ApiRouteHandler) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
context := c.Request.Context()
|
||||||
|
// get the app
|
||||||
|
appName := c.Param(api.CApp)
|
||||||
|
app, err := s.Datastore.GetApp(context, appName)
|
||||||
|
if err != nil {
|
||||||
|
handleErrorResponse(c, err)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if app == nil {
|
||||||
|
handleErrorResponse(c, models.ErrAppsNotFound)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// get the route TODO
|
||||||
|
routePath := "/" + c.Param(api.CRoute)
|
||||||
|
route, err := s.Datastore.GetRoute(context, appName, routePath)
|
||||||
|
if err != nil {
|
||||||
|
handleErrorResponse(c, err)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if route == nil {
|
||||||
|
handleErrorResponse(c, models.ErrRoutesNotFound)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(c.Writer, c.Request, app, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddEndpoint adds an endpoint to /v1/x
|
// AddEndpoint adds an endpoint to /v1/x
|
||||||
func (s *Server) AddEndpoint(method, path string, handler ApiHandler) {
|
func (s *Server) AddEndpoint(method, path string, handler ApiHandler) {
|
||||||
v1 := s.Router.Group("/v1")
|
v1 := s.Router.Group("/v1")
|
||||||
@@ -81,3 +129,14 @@ func (s *Server) AddAppEndpoint(method, path string, handler ApiAppHandler) {
|
|||||||
func (s *Server) AddAppEndpointFunc(method, path string, handler func(w http.ResponseWriter, r *http.Request, app *models.App)) {
|
func (s *Server) AddAppEndpointFunc(method, path string, handler func(w http.ResponseWriter, r *http.Request, app *models.App)) {
|
||||||
s.AddAppEndpoint(method, path, ApiAppHandlerFunc(handler))
|
s.AddAppEndpoint(method, path, ApiAppHandlerFunc(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRouteEndpoint adds an endpoints to /v1/apps/:app/routes/:route/x
|
||||||
|
func (s *Server) AddRouteEndpoint(method, path string, handler ApiRouteHandler) {
|
||||||
|
v1 := s.Router.Group("/v1")
|
||||||
|
v1.Handle(method, "/apps/:app/routes/:route"+path, s.apiRouteHandlerWrapperFunc(handler)) // conflicts with existing wildcard
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRouteEndpoint adds an endpoints to /v1/apps/:app/routes/:route/x
|
||||||
|
func (s *Server) AddRouteEndpointFunc(method, path string, handler func(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route)) {
|
||||||
|
s.AddRouteEndpoint(method, path, ApiRouteHandlerFunc(handler))
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ func (s *Server) handleRouteGet(c *gin.Context) {
|
|||||||
ctx := c.Request.Context()
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
appName := c.MustGet(api.AppName).(string)
|
appName := c.MustGet(api.AppName).(string)
|
||||||
routePath := path.Clean(c.MustGet(api.Path).(string))
|
routePath := path.Clean("/" + c.MustGet(api.Path).(string))
|
||||||
|
|
||||||
route, err := s.Datastore.GetRoute(ctx, appName, routePath)
|
route, err := s.Datastore.GetRoute(ctx, appName, routePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleErrorResponse(c, err)
|
handleErrorResponse(c, err)
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ func (s *Server) bindHandlers(ctx context.Context) {
|
|||||||
|
|
||||||
apps.GET("/routes", s.handleRouteList)
|
apps.GET("/routes", s.handleRouteList)
|
||||||
apps.POST("/routes", s.handleRoutesPostPutPatch)
|
apps.POST("/routes", s.handleRoutesPostPutPatch)
|
||||||
apps.GET("/routes/*route", s.handleRouteGet)
|
apps.GET("/routes/:route", s.handleRouteGet)
|
||||||
apps.PATCH("/routes/*route", s.handleRoutesPostPutPatch)
|
apps.PATCH("/routes/*route", s.handleRoutesPostPutPatch)
|
||||||
apps.PUT("/routes/*route", s.handleRoutesPostPutPatch)
|
apps.PUT("/routes/*route", s.handleRoutesPostPutPatch)
|
||||||
apps.DELETE("/routes/*route", s.handleRouteDelete)
|
apps.DELETE("/routes/*route", s.handleRouteDelete)
|
||||||
|
|||||||
@@ -9,14 +9,13 @@ go build
|
|||||||
./extensions
|
./extensions
|
||||||
```
|
```
|
||||||
|
|
||||||
Then test with:
|
First create an app `myapp` and a function `myroute`. Then test with:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# First, create an app
|
|
||||||
fn apps create myapp
|
|
||||||
# And test
|
|
||||||
curl http://localhost:8080/v1/custom1
|
curl http://localhost:8080/v1/custom1
|
||||||
curl http://localhost:8080/v1/custom2
|
curl http://localhost:8080/v1/custom2
|
||||||
curl http://localhost:8080/v1/apps/myapp/custom3
|
curl http://localhost:8080/v1/apps/myapp/custom3
|
||||||
curl http://localhost:8080/v1/apps/myapp/custom4
|
curl http://localhost:8080/v1/apps/myapp/custom4
|
||||||
|
curl http://localhost:8080/v1/apps/myapp/routes/myroute/custom5
|
||||||
|
curl http://localhost:8080/v1/apps/myapp/routes/myroute/custom5
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ func main() {
|
|||||||
fmt.Println("Custom4Handler called")
|
fmt.Println("Custom4Handler called")
|
||||||
fmt.Fprintf(w, "Hello app %v func, %q", app.Name, html.EscapeString(r.URL.Path))
|
fmt.Fprintf(w, "Hello app %v func, %q", app.Name, html.EscapeString(r.URL.Path))
|
||||||
})
|
})
|
||||||
|
// the following will be at /v1/apps/:app_name/routes/:route_name/custom5
|
||||||
|
// and /v1/apps/:app_name/routes/:route_name/custom6
|
||||||
|
funcServer.AddRouteEndpoint("GET", "/custom5", &Custom5Handler{})
|
||||||
|
funcServer.AddRouteEndpointFunc("GET", "/custom6", func(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route) {
|
||||||
|
// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
|
||||||
|
fmt.Println("Custom6Handler called")
|
||||||
|
fmt.Fprintf(w, "Hello app %v, route %v, request %q", app.Name, route.Path, html.EscapeString(r.URL.Path))
|
||||||
|
})
|
||||||
funcServer.Start(ctx)
|
funcServer.Start(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,3 +55,11 @@ func (h *Custom3Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, app *
|
|||||||
fmt.Println("Custom3Handler called")
|
fmt.Println("Custom3Handler called")
|
||||||
fmt.Fprintf(w, "Hello app %v, %q", app.Name, html.EscapeString(r.URL.Path))
|
fmt.Fprintf(w, "Hello app %v, %q", app.Name, html.EscapeString(r.URL.Path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Custom5Handler struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Custom5Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, app *models.App, route *models.Route) {
|
||||||
|
fmt.Println("Custom5Handler called")
|
||||||
|
fmt.Fprintf(w, "Hello! app %v, route %v, request %q", app.Name, route.Path, html.EscapeString(r.URL.Path))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user