mirror of
https://github.com/rancher/steve.git
synced 2025-09-08 18:59:58 +00:00
Refactor
This commit is contained in:
258
pkg/schemaserver/server/server.go
Normal file
258
pkg/schemaserver/server/server.go
Normal file
@@ -0,0 +1,258 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/steve/pkg/schemaserver/handlers"
|
||||
"github.com/rancher/steve/pkg/schemaserver/parse"
|
||||
"github.com/rancher/steve/pkg/schemaserver/types"
|
||||
"github.com/rancher/steve/pkg/schemaserver/writer"
|
||||
"github.com/rancher/wrangler/pkg/merr"
|
||||
"github.com/rancher/wrangler/pkg/schemas/validation"
|
||||
)
|
||||
|
||||
type RequestHandler interface {
|
||||
http.Handler
|
||||
|
||||
GetSchemas() *types.APISchemas
|
||||
Handle(apiOp *types.APIRequest)
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
ResponseWriters map[string]types.ResponseWriter
|
||||
Schemas *types.APISchemas
|
||||
Defaults Defaults
|
||||
AccessControl types.AccessControl
|
||||
Parser parse.Parser
|
||||
URLParser parse.URLParser
|
||||
}
|
||||
|
||||
type Defaults struct {
|
||||
ByIDHandler types.RequestHandler
|
||||
ListHandler types.RequestListHandler
|
||||
CreateHandler types.RequestHandler
|
||||
DeleteHandler types.RequestHandler
|
||||
UpdateHandler types.RequestHandler
|
||||
Store types.Store
|
||||
ErrorHandler types.ErrorHandler
|
||||
}
|
||||
|
||||
func DefaultAPIServer() *Server {
|
||||
s := &Server{
|
||||
Schemas: types.EmptyAPISchemas(),
|
||||
ResponseWriters: map[string]types.ResponseWriter{
|
||||
"json": &writer.EncodingResponseWriter{
|
||||
ContentType: "application/json",
|
||||
Encoder: types.JSONEncoder,
|
||||
},
|
||||
"html": &writer.HTMLResponseWriter{
|
||||
EncodingResponseWriter: writer.EncodingResponseWriter{
|
||||
Encoder: types.JSONEncoder,
|
||||
ContentType: "application/json",
|
||||
},
|
||||
},
|
||||
"yaml": &writer.EncodingResponseWriter{
|
||||
ContentType: "application/yaml",
|
||||
Encoder: types.YAMLEncoder,
|
||||
},
|
||||
},
|
||||
AccessControl: &AllAccess{},
|
||||
Defaults: Defaults{
|
||||
ByIDHandler: handlers.ByIDHandler,
|
||||
CreateHandler: handlers.CreateHandler,
|
||||
DeleteHandler: handlers.DeleteHandler,
|
||||
UpdateHandler: handlers.UpdateHandler,
|
||||
ListHandler: handlers.ListHandler,
|
||||
ErrorHandler: handlers.ErrorHandler,
|
||||
},
|
||||
Parser: parse.Parse,
|
||||
URLParser: parse.MuxURLParser,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) setDefaults(ctx *types.APIRequest) {
|
||||
if ctx.ResponseWriter == nil {
|
||||
ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
|
||||
if ctx.ResponseWriter == nil {
|
||||
ctx.ResponseWriter = s.ResponseWriters["json"]
|
||||
}
|
||||
}
|
||||
|
||||
ctx.AccessControl = s.AccessControl
|
||||
|
||||
if ctx.Schemas == nil {
|
||||
ctx.Schemas = s.Schemas
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AddSchemas(schemas *types.APISchemas) error {
|
||||
var errs []error
|
||||
|
||||
for _, schema := range schemas.Schemas {
|
||||
if err := s.addSchema(*schema); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
return merr.NewErrors(errs...)
|
||||
}
|
||||
|
||||
func (s *Server) addSchema(schema types.APISchema) error {
|
||||
s.setupDefaults(&schema)
|
||||
return s.Schemas.AddSchema(schema)
|
||||
}
|
||||
|
||||
func (s *Server) setupDefaults(schema *types.APISchema) {
|
||||
if schema.Store == nil {
|
||||
schema.Store = s.Defaults.Store
|
||||
}
|
||||
|
||||
if schema.ListHandler == nil {
|
||||
schema.ListHandler = s.Defaults.ListHandler
|
||||
}
|
||||
|
||||
if schema.CreateHandler == nil {
|
||||
schema.CreateHandler = s.Defaults.CreateHandler
|
||||
}
|
||||
|
||||
if schema.ByIDHandler == nil {
|
||||
schema.ByIDHandler = s.Defaults.ByIDHandler
|
||||
}
|
||||
|
||||
if schema.UpdateHandler == nil {
|
||||
schema.UpdateHandler = s.Defaults.UpdateHandler
|
||||
}
|
||||
|
||||
if schema.DeleteHandler == nil {
|
||||
schema.DeleteHandler = s.Defaults.DeleteHandler
|
||||
}
|
||||
|
||||
if schema.ErrorHandler == nil {
|
||||
schema.ErrorHandler = s.Defaults.ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) GetSchemas() *types.APISchemas {
|
||||
return s.Schemas
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
s.Handle(&types.APIRequest{
|
||||
Request: req,
|
||||
Response: rw,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) Handle(apiOp *types.APIRequest) {
|
||||
s.handle(apiOp, s.Parser)
|
||||
}
|
||||
|
||||
func (s *Server) handle(apiOp *types.APIRequest, parser parse.Parser) {
|
||||
if err := parser(apiOp, parse.MuxURLParser); err != nil {
|
||||
// ensure defaults set so writer is assigned
|
||||
s.setDefaults(apiOp)
|
||||
s.handleError(apiOp, err)
|
||||
return
|
||||
}
|
||||
|
||||
s.setDefaults(apiOp)
|
||||
|
||||
if code, data, err := s.handleOp(apiOp); err != nil {
|
||||
s.handleError(apiOp, err)
|
||||
} else if obj, ok := data.(types.APIObject); ok {
|
||||
apiOp.WriteResponse(code, obj)
|
||||
} else if list, ok := data.(types.APIObjectList); ok {
|
||||
apiOp.WriteResponseList(code, list)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleOp(apiOp *types.APIRequest) (int, interface{}, error) {
|
||||
if err := CheckCSRF(apiOp); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
action, err := ValidateAction(apiOp)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if apiOp.Schema == nil {
|
||||
return http.StatusNotFound, nil, nil
|
||||
}
|
||||
|
||||
if action != nil {
|
||||
return http.StatusOK, nil, handleAction(apiOp)
|
||||
}
|
||||
|
||||
switch apiOp.Method {
|
||||
case http.MethodGet:
|
||||
if apiOp.Name == "" {
|
||||
data, err := handleList(apiOp, apiOp.Schema.ListHandler, s.Defaults.ListHandler)
|
||||
return http.StatusOK, data, err
|
||||
}
|
||||
data, err := handle(apiOp, apiOp.Schema.ByIDHandler, s.Defaults.ByIDHandler)
|
||||
return http.StatusOK, data, err
|
||||
case http.MethodPatch:
|
||||
fallthrough
|
||||
case http.MethodPut:
|
||||
data, err := handle(apiOp, apiOp.Schema.UpdateHandler, s.Defaults.UpdateHandler)
|
||||
return http.StatusOK, data, err
|
||||
case http.MethodPost:
|
||||
data, err := handle(apiOp, apiOp.Schema.CreateHandler, s.Defaults.CreateHandler)
|
||||
return http.StatusCreated, data, err
|
||||
case http.MethodDelete:
|
||||
data, err := handle(apiOp, apiOp.Schema.DeleteHandler, s.Defaults.DeleteHandler)
|
||||
return http.StatusOK, data, err
|
||||
}
|
||||
|
||||
return http.StatusNotFound, nil, nil
|
||||
}
|
||||
|
||||
func handleList(apiOp *types.APIRequest, custom types.RequestListHandler, handler types.RequestListHandler) (types.APIObjectList, error) {
|
||||
if custom != nil {
|
||||
return custom(apiOp)
|
||||
}
|
||||
return handler(apiOp)
|
||||
}
|
||||
|
||||
func handle(apiOp *types.APIRequest, custom types.RequestHandler, handler types.RequestHandler) (types.APIObject, error) {
|
||||
if custom != nil {
|
||||
return custom(apiOp)
|
||||
}
|
||||
return handler(apiOp)
|
||||
}
|
||||
|
||||
func handleAction(context *types.APIRequest) error {
|
||||
if err := context.AccessControl.CanAction(context, context.Schema, context.Action); err != nil {
|
||||
return err
|
||||
}
|
||||
if handler, ok := context.Schema.ActionHandlers[context.Action]; ok {
|
||||
handler.ServeHTTP(context.Response, context.Request)
|
||||
return validation.ErrComplete
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleError(apiOp *types.APIRequest, err error) {
|
||||
if apiOp.Schema != nil && apiOp.Schema.ErrorHandler != nil {
|
||||
apiOp.Schema.ErrorHandler(apiOp, err)
|
||||
} else if s.Defaults.ErrorHandler != nil {
|
||||
s.Defaults.ErrorHandler(apiOp, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) CustomAPIUIResponseWriter(cssURL, jsURL, version writer.StringGetter) {
|
||||
wi, ok := s.ResponseWriters["html"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
w, ok := wi.(*writer.HTMLResponseWriter)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
w.CSSURL = cssURL
|
||||
w.JSURL = jsURL
|
||||
w.APIUIVersion = version
|
||||
}
|
Reference in New Issue
Block a user