diff --git a/api/builtin/api_root.go b/api/builtin/api_root.go
new file mode 100644
index 000000000..7ff1b366d
--- /dev/null
+++ b/api/builtin/api_root.go
@@ -0,0 +1,123 @@
+package builtin
+
+import (
+ "github.com/rancher/norman/store/empty"
+ "github.com/rancher/norman/types"
+ "github.com/rancher/norman/types/convert"
+)
+
+func APIRootFormatter(apiContext *types.APIContext, resource *types.RawResource) {
+ path, _ := resource.Values["path"].(string)
+ if path == "" {
+ return
+ }
+
+ delete(resource.Values, "path")
+
+ resource.Links["root"] = apiContext.URLBuilder.RelativeToRoot(path)
+
+ data, _ := resource.Values["apiVersion"].(map[string]interface{})
+ apiVersion := apiVersionFromMap(apiContext.Schemas, data)
+
+ resource.Links["self"] = apiContext.URLBuilder.Version(apiVersion)
+
+ if len(apiVersion.SubContexts) > 0 {
+ subContextToSchema := apiContext.Schemas.SubContextSchemas()
+ if len(subContextToSchema) > 0 {
+ for _, schema := range subContextToSchema {
+ addCollectionLink(apiContext, schema, resource.Links)
+ }
+
+ for _, schema := range getNonReferencedSchemas(apiContext.Schemas.SchemasForVersion(apiVersion),
+ subContextToSchema) {
+ addCollectionLink(apiContext, schema, resource.Links)
+ }
+
+ return
+ }
+ }
+
+ for _, schema := range apiContext.Schemas.SchemasForVersion(apiVersion) {
+ addCollectionLink(apiContext, schema, resource.Links)
+ }
+
+ return
+}
+
+func getNonReferencedSchemas(schemas map[string]*types.Schema, subContexts map[string]*types.Schema) []*types.Schema {
+ var result []*types.Schema
+ typeNames := map[string]bool{}
+
+ for _, subContext := range subContexts {
+ ref := convert.ToReference(subContext.ID)
+ fullRef := convert.ToFullReference(subContext.Version.Path, subContext.ID)
+ typeNames[ref] = true
+ typeNames[fullRef] = true
+ }
+
+outer:
+ for _, schema := range schemas {
+ for _, field := range schema.ResourceFields {
+ if typeNames[field.Type] {
+ continue outer
+ }
+ }
+
+ result = append(result, schema)
+ }
+
+ return result
+}
+
+func addCollectionLink(apiContext *types.APIContext, schema *types.Schema, links map[string]string) {
+ collectionLink := getSchemaCollectionLink(apiContext, schema, nil)
+ if collectionLink != "" {
+ links[schema.PluralName] = collectionLink
+ }
+}
+
+type APIRootStore struct {
+ empty.Store
+ roots []string
+}
+
+func NewAPIRootStore(roots []string) types.Store {
+ return &APIRootStore{roots: roots}
+}
+
+func (a *APIRootStore) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
+ for _, version := range apiContext.Schemas.Versions() {
+ if version.Path == id {
+ return apiVersionToAPIRootMap(version), nil
+ }
+ }
+ return nil, nil
+}
+
+func (a *APIRootStore) List(apiContext *types.APIContext, schema *types.Schema, opt types.QueryOptions) ([]map[string]interface{}, error) {
+ var roots []map[string]interface{}
+
+ for _, version := range apiContext.Schemas.Versions() {
+ roots = append(roots, apiVersionToAPIRootMap(version))
+ }
+
+ for _, root := range a.roots {
+ roots = append(roots, map[string]interface{}{
+ "path": root,
+ })
+ }
+
+ return roots, nil
+}
+
+func apiVersionToAPIRootMap(version types.APIVersion) map[string]interface{} {
+ return map[string]interface{}{
+ "type": "/v1-meta/schemas/apiRoot",
+ "apiVersion": map[string]interface{}{
+ "version": version.Version,
+ "group": version.Group,
+ "path": version.Path,
+ },
+ "path": version.Path,
+ }
+}
diff --git a/api/builtin/builtin.go b/api/builtin/schema.go
similarity index 53%
rename from api/builtin/builtin.go
rename to api/builtin/schema.go
index b3cfe3d25..10bc37fb0 100644
--- a/api/builtin/builtin.go
+++ b/api/builtin/schema.go
@@ -3,16 +3,15 @@ package builtin
import (
"net/http"
- "github.com/rancher/norman/store/empty"
"github.com/rancher/norman/store/schema"
"github.com/rancher/norman/types"
)
var (
Version = types.APIVersion{
- Group: "io.cattle.builtin",
- Version: "v3",
- Path: "/v3",
+ Group: "meta.cattle.io",
+ Version: "v1",
+ Path: "/v1-meta",
}
Schema = types.Schema{
@@ -23,7 +22,7 @@ var (
ResourceFields: map[string]types.Field{
"collectionActions": {Type: "map[json]"},
"collectionFields": {Type: "map[json]"},
- "collectionFitlers": {Type: "map[json]"},
+ "collectionFilters": {Type: "map[json]"},
"collectionMethods": {Type: "array[string]"},
"pluralName": {Type: "string"},
"resourceActions": {Type: "map[json]"},
@@ -41,10 +40,11 @@ var (
ResourceMethods: []string{},
CollectionMethods: []string{},
ResourceFields: map[string]types.Field{
- "code": {Type: "string"},
- "detail": {Type: "string"},
- "message": {Type: "string"},
- "status": {Type: "int"},
+ "code": {Type: "string"},
+ "detail": {Type: "string", Nullable: true},
+ "message": {Type: "string", Nullable: true},
+ "fieldName": {Type: "string", Nullable: true},
+ "status": {Type: "int"},
},
}
@@ -81,32 +81,46 @@ var (
AddSchema(&APIRoot)
)
-func apiVersionFromMap(apiVersion map[string]interface{}) types.APIVersion {
+func apiVersionFromMap(schemas *types.Schemas, apiVersion map[string]interface{}) types.APIVersion {
path, _ := apiVersion["path"].(string)
version, _ := apiVersion["version"].(string)
group, _ := apiVersion["group"].(string)
- return types.APIVersion{
+ apiVersionObj := types.APIVersion{
Path: path,
Version: version,
Group: group,
}
+
+ for _, testVersion := range schemas.Versions() {
+ if testVersion.Equals(&apiVersionObj) {
+ return testVersion
+ }
+ }
+
+ return apiVersionObj
}
func SchemaFormatter(apiContext *types.APIContext, resource *types.RawResource) {
data, _ := resource.Values["version"].(map[string]interface{})
- apiVersion := apiVersionFromMap(data)
+ apiVersion := apiVersionFromMap(apiContext.Schemas, data)
schema := apiContext.Schemas.Schema(&apiVersion, resource.ID)
- collectionLink := getSchemaCollectionLink(apiContext, schema)
+ if schema == nil {
+ return
+ }
+
+ collectionLink := getSchemaCollectionLink(apiContext, schema, &apiVersion)
if collectionLink != "" {
resource.Links["collection"] = collectionLink
}
+
+ resource.Links["self"] = apiContext.URLBuilder.SchemaLink(schema)
}
-func getSchemaCollectionLink(apiContext *types.APIContext, schema *types.Schema) string {
+func getSchemaCollectionLink(apiContext *types.APIContext, schema *types.Schema, apiVersion *types.APIVersion) string {
if schema != nil && contains(schema.CollectionMethods, http.MethodGet) {
- return apiContext.URLBuilder.Collection(schema)
+ return apiContext.URLBuilder.Collection(schema, apiVersion)
}
return ""
}
@@ -119,68 +133,3 @@ func contains(list []string, needle string) bool {
}
return false
}
-
-func APIRootFormatter(apiContext *types.APIContext, resource *types.RawResource) {
- path, _ := resource.Values["path"].(string)
- if path == "" {
- return
- }
-
- resource.Links["root"] = apiContext.URLBuilder.RelativeToRoot(path)
-
- data, _ := resource.Values["apiVersion"].(map[string]interface{})
- apiVersion := apiVersionFromMap(data)
-
- for name, schema := range apiContext.Schemas.SchemasForVersion(apiVersion) {
- collectionLink := getSchemaCollectionLink(apiContext, schema)
- if collectionLink != "" {
- resource.Links[name] = collectionLink
- }
- }
-}
-
-type APIRootStore struct {
- empty.Store
- roots []string
-}
-
-func NewAPIRootStore(roots []string) types.Store {
- return &APIRootStore{roots: roots}
-}
-
-func (a *APIRootStore) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
- for _, version := range apiContext.Schemas.Versions() {
- if version.Path == id {
- return apiVersionToAPIRootMap(version), nil
- }
- }
- return nil, nil
-}
-
-func (a *APIRootStore) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
- roots := []map[string]interface{}{}
-
- for _, version := range apiContext.Schemas.Versions() {
- roots = append(roots, apiVersionToAPIRootMap(version))
- }
-
- for _, root := range a.roots {
- roots = append(roots, map[string]interface{}{
- "path": root,
- })
- }
-
- return roots, nil
-}
-
-func apiVersionToAPIRootMap(version types.APIVersion) map[string]interface{} {
- return map[string]interface{}{
- "type": "/v3/apiRoot",
- "apiVersion": map[string]interface{}{
- "version": version.Version,
- "group": version.Group,
- "path": version.Path,
- },
- "path": version.Path,
- }
-}
diff --git a/api/formatter/subcontext_filter.go b/api/formatter/subcontext_filter.go
new file mode 100644
index 000000000..1a1c0ee1d
--- /dev/null
+++ b/api/formatter/subcontext_filter.go
@@ -0,0 +1,25 @@
+package formatter
+
+import (
+ "github.com/rancher/norman/types"
+ "github.com/rancher/norman/types/convert"
+)
+
+func SubContextFormatter(apiContext *types.APIContext, resource *types.RawResource) {
+ if resource.Schema.SubContext == "" {
+ return
+ }
+
+ ref := convert.ToReference(resource.Schema.ID)
+ fullRef := convert.ToFullReference(resource.Schema.Version.Path, resource.Schema.ID)
+
+outer:
+ for _, schema := range apiContext.Schemas.Schemas() {
+ for _, field := range schema.ResourceFields {
+ if (field.Type == ref || field.Type == fullRef) && schema.Version.SubContexts[resource.Schema.SubContext] {
+ resource.Links[schema.PluralName] = apiContext.URLBuilder.SubContextCollection(resource.Schema, resource.ID, schema)
+ continue outer
+ }
+ }
+ }
+}
diff --git a/api/handler/create.go b/api/handler/create.go
new file mode 100644
index 000000000..8f3f1249d
--- /dev/null
+++ b/api/handler/create.go
@@ -0,0 +1,27 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/rancher/norman/types"
+)
+
+func CreateHandler(apiContext *types.APIContext) error {
+ var err error
+
+ data, err := ParseAndValidateBody(apiContext)
+ if err != nil {
+ return err
+ }
+
+ store := apiContext.Schema.Store
+ if store != nil {
+ data, err = store.Create(apiContext, apiContext.Schema, data)
+ if err != nil {
+ return err
+ }
+ }
+
+ apiContext.WriteResponse(http.StatusCreated, data)
+ return nil
+}
diff --git a/api/handlers/delete.go b/api/handler/delete.go
similarity index 94%
rename from api/handlers/delete.go
rename to api/handler/delete.go
index b6718bf27..348ea5e64 100644
--- a/api/handlers/delete.go
+++ b/api/handler/delete.go
@@ -1,4 +1,4 @@
-package handlers
+package handler
import (
"net/http"
diff --git a/api/handlers/list.go b/api/handler/list.go
similarity index 76%
rename from api/handlers/list.go
rename to api/handler/list.go
index 714a31059..3f664eefa 100644
--- a/api/handlers/list.go
+++ b/api/handler/list.go
@@ -1,4 +1,4 @@
-package handlers
+package handler
import (
"net/http"
@@ -19,8 +19,8 @@ func ListHandler(request *types.APIContext) error {
}
if request.ID == "" {
- request.QueryOptions = parse.QueryOptions(request.Request, request.Schema)
- data, err = store.List(request, request.Schema, request.QueryOptions)
+ opts := parse.QueryOptions(request, request.Schema)
+ data, err = store.List(request, request.Schema, opts)
} else if request.Link == "" {
data, err = store.ByID(request, request.Schema, request.ID)
} else {
diff --git a/api/handler/query.go b/api/handler/query.go
new file mode 100644
index 000000000..e199a8838
--- /dev/null
+++ b/api/handler/query.go
@@ -0,0 +1,121 @@
+package handler
+
+import (
+ "sort"
+
+ "github.com/rancher/norman/types"
+ "github.com/rancher/norman/types/convert"
+)
+
+func QueryFilter(opts types.QueryOptions, data []map[string]interface{}) []map[string]interface{} {
+ return ApplyQueryOptions(opts, data)
+}
+
+func ApplyQueryOptions(options types.QueryOptions, data []map[string]interface{}) []map[string]interface{} {
+ data = ApplyQueryConditions(options.Conditions, data)
+ data = ApplySort(options.Sort, data)
+ return ApplyPagination(options.Pagination, data)
+}
+
+func ApplySort(sortOpts types.Sort, data []map[string]interface{}) []map[string]interface{} {
+ name := sortOpts.Name
+ if name == "" {
+ name = "id"
+ }
+
+ sort.Slice(data, func(i, j int) bool {
+ left, right := i, j
+ if sortOpts.Order == types.DESC {
+ left, right = j, i
+ }
+
+ return convert.ToString(data[left][name]) < convert.ToString(data[right][name])
+ })
+
+ return data
+}
+
+func ApplyQueryConditions(conditions []*types.QueryCondition, data []map[string]interface{}) []map[string]interface{} {
+ var result []map[string]interface{}
+
+outer:
+ for _, item := range data {
+ for _, condition := range conditions {
+ if !condition.Valid(item) {
+ continue outer
+ }
+ }
+
+ result = append(result, item)
+ }
+
+ return result
+}
+
+func ApplyPagination(pagination *types.Pagination, data []map[string]interface{}) []map[string]interface{} {
+ if pagination == nil || pagination.Limit == nil {
+ return data
+ }
+
+ limit := *pagination.Limit
+ if limit < 0 {
+ limit = 0
+ }
+
+ total := int64(len(data))
+
+ // Reset fields
+ pagination.Next = ""
+ pagination.Previous = ""
+ pagination.Partial = false
+ pagination.Total = &total
+ pagination.First = ""
+
+ if len(data) == 0 {
+ return data
+ }
+
+ // startIndex is guaranteed to be a valid index
+ startIndex := int64(0)
+ if pagination.Marker != "" {
+ for i, item := range data {
+ id, _ := item["id"].(string)
+ if id == pagination.Marker {
+ startIndex = int64(i)
+ break
+ }
+ }
+ }
+
+ previousIndex := startIndex - limit
+ if previousIndex <= 0 {
+ previousIndex = 0
+ }
+ nextIndex := startIndex + limit
+ if nextIndex > int64(len(data)) {
+ nextIndex = int64(len(data))
+ }
+
+ if previousIndex < startIndex {
+ pagination.Previous, _ = data[previousIndex]["id"].(string)
+ }
+
+ if nextIndex > startIndex && nextIndex < int64(len(data)) {
+ pagination.Next, _ = data[nextIndex]["id"].(string)
+ }
+
+ if startIndex > 0 || nextIndex < int64(len(data)) {
+ pagination.Partial = true
+ }
+
+ if pagination.Partial {
+ pagination.First, _ = data[0]["id"].(string)
+
+ lastIndex := int64(len(data)) - limit
+ if lastIndex > 0 && lastIndex < int64(len(data)) {
+ pagination.Last, _ = data[lastIndex]["id"].(string)
+ }
+ }
+
+ return data[startIndex:nextIndex]
+}
diff --git a/api/handler/update.go b/api/handler/update.go
new file mode 100644
index 000000000..47e584a31
--- /dev/null
+++ b/api/handler/update.go
@@ -0,0 +1,25 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/rancher/norman/types"
+)
+
+func UpdateHandler(apiContext *types.APIContext) error {
+ data, err := ParseAndValidateBody(apiContext)
+ if err != nil {
+ return err
+ }
+
+ store := apiContext.Schema.Store
+ if store != nil {
+ data, err = store.Update(apiContext, apiContext.Schema, data, apiContext.ID)
+ if err != nil {
+ return err
+ }
+ }
+
+ apiContext.WriteResponse(http.StatusOK, data)
+ return nil
+}
diff --git a/api/handler/validate.go b/api/handler/validate.go
new file mode 100644
index 000000000..c83b87b60
--- /dev/null
+++ b/api/handler/validate.go
@@ -0,0 +1,26 @@
+package handler
+
+import (
+ "github.com/rancher/norman/parse"
+ "github.com/rancher/norman/parse/builder"
+ "github.com/rancher/norman/types"
+)
+
+func ParseAndValidateBody(apiContext *types.APIContext) (map[string]interface{}, error) {
+ data, err := parse.Body(apiContext.Request)
+ if err != nil {
+ return nil, err
+ }
+
+ b := builder.NewBuilder(apiContext)
+
+ data, err = b.Construct(apiContext.Schema, data, builder.Create)
+ validator := apiContext.Schema.Validator
+ if validator != nil {
+ if err := validator(apiContext, data); err != nil {
+ return nil, err
+ }
+ }
+
+ return data, nil
+}
diff --git a/api/handlers/create.go b/api/handlers/create.go
deleted file mode 100644
index 68384d313..000000000
--- a/api/handlers/create.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package handlers
-
-import (
- "net/http"
-
- "github.com/rancher/norman/types"
-)
-
-func CreateHandler(request *types.APIContext) error {
- var err error
-
- validator := request.Schema.Validator
- if validator != nil {
- if err := validator(request, request.Body); err != nil {
- return err
- }
- }
-
- data := request.Body
-
- store := request.Schema.Store
- if store != nil {
- data, err = store.Create(request, request.Schema, data)
- if err != nil {
- return err
- }
- }
-
- request.WriteResponse(http.StatusCreated, data)
- return nil
-}
diff --git a/api/handlers/update.go b/api/handlers/update.go
deleted file mode 100644
index 94a5978ec..000000000
--- a/api/handlers/update.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package handlers
-
-import (
- "net/http"
-
- "github.com/rancher/norman/types"
-)
-
-func UpdateHandler(request *types.APIContext) error {
- var err error
-
- validator := request.Schema.Validator
- if validator != nil {
- if err := validator(request, request.Body); err != nil {
- return err
- }
- }
-
- data := request.Body
- store := request.Schema.Store
- if store != nil {
- data, err = store.Update(request, request.Schema, data, request.ID)
- if err != nil {
- return err
- }
- }
-
- request.WriteResponse(http.StatusOK, data)
- return nil
-}
diff --git a/api/headers.go b/api/headers.go
index fa253e891..ed49c169c 100644
--- a/api/headers.go
+++ b/api/headers.go
@@ -16,7 +16,7 @@ func addSchemasHeader(apiContext *types.APIContext) error {
return nil
}
- apiContext.Response.Header().Set("X-Api-Schemas", apiContext.URLBuilder.Collection(schema))
+ apiContext.Response.Header().Set("X-Api-Schemas", apiContext.URLBuilder.Collection(schema, apiContext.Version))
return nil
}
diff --git a/api/server.go b/api/server.go
index 909cfdfe1..130e97fb0 100644
--- a/api/server.go
+++ b/api/server.go
@@ -1,27 +1,35 @@
package api
import (
- "context"
"net/http"
+ "sync"
+
"github.com/rancher/norman/api/builtin"
- "github.com/rancher/norman/api/handlers"
+ "github.com/rancher/norman/api/handler"
"github.com/rancher/norman/api/writer"
"github.com/rancher/norman/authorization"
"github.com/rancher/norman/httperror"
"github.com/rancher/norman/parse"
- "github.com/rancher/norman/parse/builder"
+ "github.com/rancher/norman/store/wrapper"
"github.com/rancher/norman/types"
)
+type StoreWrapper func(types.Store) types.Store
+
type Parser func(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error)
type Server struct {
- IgnoreBuiltin bool
- Parser Parser
- ResponseWriters map[string]ResponseWriter
- schemas *types.Schemas
- Defaults Defaults
+ initBuiltin sync.Once
+ IgnoreBuiltin bool
+ Parser Parser
+ Resolver parse.ResolverFunc
+ SubContextAttributeProvider types.SubContextAttributeProvider
+ ResponseWriters map[string]ResponseWriter
+ schemas *types.Schemas
+ QueryFilter types.QueryFilter
+ StoreWrapper StoreWrapper
+ Defaults Defaults
}
type Defaults struct {
@@ -42,35 +50,44 @@ func NewAPIServer() *Server {
"json": &writer.JSONResponseWriter{},
"html": &writer.HTMLResponseWriter{},
},
+ SubContextAttributeProvider: &parse.DefaultSubContextAttributeProvider{},
+ Resolver: parse.DefaultResolver,
Defaults: Defaults{
- CreateHandler: handlers.CreateHandler,
- DeleteHandler: handlers.DeleteHandler,
- UpdateHandler: handlers.UpdateHandler,
- ListHandler: handlers.ListHandler,
+ CreateHandler: handler.CreateHandler,
+ DeleteHandler: handler.DeleteHandler,
+ UpdateHandler: handler.UpdateHandler,
+ ListHandler: handler.ListHandler,
LinkHandler: func(*types.APIContext) error {
- return httperror.NewAPIError(httperror.NOT_FOUND, "Link not found")
+ return httperror.NewAPIError(httperror.NotFound, "Link not found")
},
ErrorHandler: httperror.ErrorHandler,
},
+ StoreWrapper: wrapper.Wrap,
+ QueryFilter: handler.QueryFilter,
}
- s.Parser = func(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
- ctx, err := parse.Parse(rw, req, s.schemas)
- ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
- if ctx.ResponseWriter == nil {
- ctx.ResponseWriter = s.ResponseWriters["json"]
- }
+ s.Parser = s.parser
+ return s
+}
- ctx.AccessControl = &authorization.AllAccess{}
+func (s *Server) parser(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
+ ctx, err := parse.Parse(rw, req, s.schemas, s.Resolver)
+ ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
+ if ctx.ResponseWriter == nil {
+ ctx.ResponseWriter = s.ResponseWriters["json"]
+ }
- return ctx, err
+ if ctx.QueryFilter == nil {
+ ctx.QueryFilter = s.QueryFilter
}
- return s
-}
+ if ctx.SubContextAttributeProvider == nil {
+ ctx.SubContextAttributeProvider = s.SubContextAttributeProvider
+ }
-func (s *Server) Start(ctx context.Context) error {
- return s.addBuiltins(ctx)
+ ctx.AccessControl = &authorization.AllAccess{}
+
+ return ctx, err
}
func (s *Server) AddSchemas(schemas *types.Schemas) error {
@@ -78,6 +95,16 @@ func (s *Server) AddSchemas(schemas *types.Schemas) error {
return schemas.Err()
}
+ s.initBuiltin.Do(func() {
+ if s.IgnoreBuiltin {
+ return
+ }
+ for _, schema := range builtin.Schemas.Schemas() {
+ s.setupDefaults(schema)
+ s.schemas.AddSchema(schema)
+ }
+ })
+
for _, schema := range schemas.Schemas() {
s.setupDefaults(schema)
s.schemas.AddSchema(schema)
@@ -118,6 +145,10 @@ func (s *Server) setupDefaults(schema *types.Schema) {
if schema.ErrorHandler == nil {
schema.ErrorHandler = s.Defaults.ErrorHandler
}
+
+ if schema.Store != nil && s.StoreWrapper != nil {
+ schema.Store = s.StoreWrapper(schema.Store)
+ }
}
func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
@@ -149,23 +180,17 @@ func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APICo
return apiRequest, nil
}
- b := builder.NewBuilder(apiRequest)
-
if action == nil && apiRequest.Type != "" {
var handler types.RequestHandler
switch apiRequest.Method {
case http.MethodGet:
handler = apiRequest.Schema.ListHandler
- apiRequest.Body = nil
case http.MethodPost:
handler = apiRequest.Schema.CreateHandler
- apiRequest.Body, err = b.Construct(apiRequest.Schema, apiRequest.Body, builder.Create)
case http.MethodPut:
handler = apiRequest.Schema.UpdateHandler
- apiRequest.Body, err = b.Construct(apiRequest.Schema, apiRequest.Body, builder.Update)
case http.MethodDelete:
handler = apiRequest.Schema.DeleteHandler
- apiRequest.Body = nil
}
if err != nil {
@@ -173,7 +198,7 @@ func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APICo
}
if handler == nil {
- return apiRequest, httperror.NewAPIError(httperror.NOT_FOUND, "")
+ return apiRequest, httperror.NewAPIError(httperror.NotFound, "")
}
return apiRequest, handler(apiRequest)
@@ -195,15 +220,3 @@ func (s *Server) handleError(apiRequest *types.APIContext, err error) {
apiRequest.Schema.ErrorHandler(apiRequest, err)
}
}
-
-func (s *Server) addBuiltins(ctx context.Context) error {
- if s.IgnoreBuiltin {
- return nil
- }
-
- if err := s.AddSchemas(builtin.Schemas); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/api/validate.go b/api/validate.go
index a2c1b6f7d..0b417f106 100644
--- a/api/validate.go
+++ b/api/validate.go
@@ -28,17 +28,17 @@ func ValidateAction(request *types.APIContext) (*types.Action, error) {
action, ok := actions[request.Action]
if !ok {
- return nil, httperror.NewAPIError(httperror.INVALID_ACTION, fmt.Sprintf("Invalid action: %s", request.Action))
+ return nil, httperror.NewAPIError(httperror.InvalidAction, fmt.Sprintf("Invalid action: %s", request.Action))
}
if request.ID != "" {
resource := request.ReferenceValidator.Lookup(request.Type, request.ID)
if resource == nil {
- return nil, httperror.NewAPIError(httperror.NOT_FOUND, fmt.Sprintf("Failed to find type: %s id: %s", request.Type, request.ID))
+ return nil, httperror.NewAPIError(httperror.NotFound, fmt.Sprintf("Failed to find type: %s id: %s", request.Type, request.ID))
}
if _, ok := resource.Actions[request.Action]; !ok {
- return nil, httperror.NewAPIError(httperror.INVALID_ACTION, fmt.Sprintf("Invalid action: %s", request.Action))
+ return nil, httperror.NewAPIError(httperror.InvalidAction, fmt.Sprintf("Invalid action: %s", request.Action))
}
}
@@ -55,7 +55,7 @@ func CheckCSRF(rw http.ResponseWriter, req *http.Request) error {
bytes := make([]byte, 5)
_, err := rand.Read(bytes)
if err != nil {
- return httperror.WrapAPIError(err, httperror.SERVER_ERROR, "Failed in CSRF processing")
+ return httperror.WrapAPIError(err, httperror.ServerError, "Failed in CSRF processing")
}
cookie = &http.Cookie{
@@ -63,7 +63,7 @@ func CheckCSRF(rw http.ResponseWriter, req *http.Request) error {
Value: hex.EncodeToString(bytes),
}
} else if err != nil {
- return httperror.NewAPIError(httperror.INVALID_CSRF_TOKEN, "Failed to parse cookies")
+ return httperror.NewAPIError(httperror.InvalidCSRFToken, "Failed to parse cookies")
} else if req.Method != http.MethodGet {
/*
* Very important to use request.getMethod() and not httpRequest.getMethod(). The client can override the HTTP method with _method
@@ -73,7 +73,7 @@ func CheckCSRF(rw http.ResponseWriter, req *http.Request) error {
} else if cookie.Value == req.URL.Query().Get(csrfCookie) {
// Good
} else {
- return httperror.NewAPIError(httperror.INVALID_CSRF_TOKEN, "Invalid CSRF token")
+ return httperror.NewAPIError(httperror.InvalidCSRFToken, "Invalid CSRF token")
}
}
diff --git a/api/writer/html.go b/api/writer/html.go
index 59b33635e..f12a0aa38 100644
--- a/api/writer/html.go
+++ b/api/writer/html.go
@@ -3,6 +3,7 @@ package writer
import (
"strings"
+ "github.com/rancher/norman/api/builtin"
"github.com/rancher/norman/types"
)
@@ -11,8 +12,8 @@ var (
-
-
+
+