Documentation ¶
Overview ¶
Package crud is a library for simple CRUD operations.
Index ¶
- Variables
- func ActionNotAvailableHandler(w http.ResponseWriter, r *http.Request)
- func ConstrainFilterColumns(r *DataSetRequest, allowedColumns ...string)
- func ConstrainPagingRequest(r *DataSetRequest, minPageSize, maxPageSize int)
- func ConstrainSortColumns(r *DataSetRequest, defaultColumn string, allowedColumns ...string)
- func ReadEntityFromBody(body io.ReadCloser, entity interface{}) error
- func Recovery(name string, ctx service.AppContext, w http.ResponseWriter, r *http.Request)
- func WriteOperationResult(w http.ResponseWriter, r *http.Request, opResult OperationResult)
- type DataSet
- type DataSetRequest
- type Entity
- type EntityKey
- type ErrorDetails
- type OperationResult
- func ConflictResult(err error) OperationResult
- func CreatedResult() OperationResult
- func ErrorResult(err error) OperationResult
- func NotFoundResult() OperationResult
- func NotSupportedByResourceResult() OperationResult
- func OkResult(value interface{}) OperationResult
- func ValidationFailedResult(err error) OperationResult
- type PagingInfo
- type RecoverFunc
- type Service
- type SortDirection
- type State
Constants ¶
This section is empty.
Variables ¶
var CreateCrudHandlerCreateEntity = func(ctx servicefoundation.AppContext, svc Service, resourceName string, recoverFunc RecoverFunc, createFunc func() Entity) http.HandlerFunc { logger := ctx.Logger() return func(w http.ResponseWriter, r *http.Request) { defer recoverFunc("crudHandler", ctx, w, r) entity := createFunc() err := ReadEntityFromBody(r.Body, entity) if err != nil { opResult := ValidationFailedResult(errors.New("Failed to parse entity from HTTP body: " + err.Error())) WriteOperationResult(w, r, opResult) return } logger.Debug("CreateCrudHandlerCreate", fmt.Sprintf("Interpreted as create command. Entity: %s", entity)) opResult := svc.Add(entity) WriteOperationResult(w, r, opResult) } }
CreateCrudHandlerCreateEntity is used to create a new entity
var CreateCrudHandlerDeleteByID = func(ctx servicefoundation.AppContext, svc Service, resourceName string, recoverFunc RecoverFunc) http.HandlerFunc { logger := ctx.Logger() return func(w http.ResponseWriter, r *http.Request) { defer recoverFunc("crudHandler", ctx, w, r) vars := mux.Vars(r) idVar := vars["id"] logger.Debug("CreateCrudHandlerDeleteById", fmt.Sprintf("Interpreted as DeleteByID command. ID: %v", idVar)) opResult := svc.Delete(idVar) WriteOperationResult(w, r, opResult) } }
CreateCrudHandlerDeleteByID is used to delete an item by its identifier
var CreateCrudHandlerGetByID = func(ctx servicefoundation.AppContext, svc Service, resourceName string, recoverFunc RecoverFunc) http.HandlerFunc { logger := ctx.Logger() return func(w http.ResponseWriter, r *http.Request) { defer recoverFunc("crudHandler", ctx, w, r) vars := mux.Vars(r) idVar := vars["id"] logger.Debug("CreateCrudHandlerGetByID", fmt.Sprintf("Interpreted as GetById command. ID: %v", idVar)) opResult := svc.GetByID(idVar) WriteOperationResult(w, r, opResult) } }
CreateCrudHandlerGetByID is used to get an item by its identifier
var CreateCrudHandlerGetList = func(ctx servicefoundation.AppContext, svc Service, resourceName string, recoverFunc RecoverFunc) http.HandlerFunc { logger := ctx.Logger() return func(w http.ResponseWriter, r *http.Request) { defer recoverFunc("crudHandler", ctx, w, r) logger.Debug("CrudHandlerStart", fmt.Sprintf("CRUD operation %v requested on %v", r.Method, r.URL.Path)) dsRequest := ExtractDataSetRequestFromURI(r) logger.Debug("CreateCrudHandlerGetList", fmt.Sprintf("Interpreted as GetList command. Arguments: %v", dsRequest)) opResult := svc.GetAll(dsRequest) WriteOperationResult(w, r, opResult) } }
CreateCrudHandlerGetList is used to request a list of entities
var CreateCrudHandlerUpdateEntity = func(ctx servicefoundation.AppContext, svc Service, resourceName string, recoverFunc RecoverFunc, createFunc func() Entity) http.HandlerFunc { logger := ctx.Logger() return func(w http.ResponseWriter, r *http.Request) { defer recoverFunc("crudHandler", ctx, w, r) vars := mux.Vars(r) idVar := vars["id"] entity := createFunc() err := ReadEntityFromBody(r.Body, entity) if err != nil { opResult := ValidationFailedResult(errors.New("Failed to parse entity from HTTP body: " + err.Error())) WriteOperationResult(w, r, opResult) return } logger.Debug("CreateCrudHandlerUpdateEntity", fmt.Sprintf("Interpreted as update command. Id: %v Entity: %s", idVar, entity)) opResult := svc.Update(idVar, entity) WriteOperationResult(w, r, opResult) } }
CreateCrudHandlerUpdateEntity is used to update a new entity
Functions ¶
func ActionNotAvailableHandler ¶
func ActionNotAvailableHandler(w http.ResponseWriter, r *http.Request)
ActionNotAvailableHandler should be routed for CRUD actions that do not need to be implemented for a particular resource. It basically prevents a 404 and turns it into a 405 instead.
func ConstrainFilterColumns ¶
func ConstrainFilterColumns(r *DataSetRequest, allowedColumns ...string)
ConstrainFilterColumns restricts the filtering of a request to the allowed columns, removing invalid ones
func ConstrainPagingRequest ¶
func ConstrainPagingRequest(r *DataSetRequest, minPageSize, maxPageSize int)
ConstrainPagingRequest clips the request values to reasonable amounts
func ConstrainSortColumns ¶
func ConstrainSortColumns(r *DataSetRequest, defaultColumn string, allowedColumns ...string)
ConstrainSortColumns restricts the sorting of a request to the allowed columns, defaulting to a specific one
func ReadEntityFromBody ¶
func ReadEntityFromBody(body io.ReadCloser, entity interface{}) error
ReadEntityFromBody is a utility function to parse the given entity from the request body
func Recovery ¶
func Recovery(name string, ctx service.AppContext, w http.ResponseWriter, r *http.Request)
Recovery is a sample recovery function for CRUD operations. It logs the error, and writes a 500 to the output, according to the CRUD protocol.
func WriteOperationResult ¶
func WriteOperationResult(w http.ResponseWriter, r *http.Request, opResult OperationResult)
WriteOperationResult is a utility function that takes the result of a CRUD operation, and writes the corresponding HTTP response, according to the CRUD protocol.
Types ¶
type DataSet ¶
type DataSet struct { // Items is the collection of results. Filtering and paging (if supported) have been applied, and the results are sorted. Items []interface{} `json:"items"` // PagingInfo describes which page of results is being returned. PagingInfo PagingInfo `json:"pagingInfo"` }
DataSet is a set of items
type DataSetRequest ¶
type DataSetRequest struct { // PageSize is the amount of items that is requested in one page. Note: the datasource will reply with the actual page size. This can happen when paging // is for some reason not available, is limited, or when an invalid page size is requested. Minimum of 1 item per page. Ignored if the datasource does not // support paging. PageSize int `json:"pageSize"` // PageNumber is the one-based number of the page being requested. PageNumber int `json:"pageNumber"` // SortColumn is the name of the column to sort the results by. Required field, defaults to "id". SortColumn string `json:"sortColumn"` // SortDirection describes how to sort the results. Required field. SortDirection string `json:"sortDirection"` // Filters are key/value pairs that describe which fields to apply. Each key is a column name, while the values are what to search for in those columns. // // Note that the exact filter implementation is fully dependent on the datasource, and this protocol does not guarantee how the filtering is applied. E.g. when searching // for a string, the implementer can choose whether this is 'start with', 'contains', etc. If the datasource does not support filtering on a given column, then that // filter is to be ignored. Filters map[string]string `json:"filters"` }
DataSetRequest describes the parameters used to search for a set of results. It describes things like the desired page, sorting, filtering, etc.
func ExtractDataSetRequestFromURI ¶
func ExtractDataSetRequestFromURI(r *http.Request) *DataSetRequest
ExtractDataSetRequestFromURI is a helper function to parse URI parameters into a DataSet request. Any parameters that are omitted from the URL are substituted with default values.
type Entity ¶
type Entity interface { // Validates an entity to see if it's correct Validate() error // Format is used as a way to 'fix' things like casing. It'll help make it friendlier for the end user, and/or // give a chance to set calculated fields and stuff // // isNewEntity will be true is this is a completely new entity, as opposed to an existing one Format(isNewEntity bool) }
Entity describes what CRUD entities must implement to be used in the standardized CRUD functionality
type EntityKey ¶
type EntityKey interface{}
EntityKey is the unique key of an entity. Typically an int, string, etc.
type ErrorDetails ¶
type ErrorDetails struct {
Message string `json:"message"`
}
ErrorDetails is used to communicate the details of an error back to the caller
type OperationResult ¶
type OperationResult interface { // State is the high level result of the operation - further details are to be returned in separate fields. State() State // Error can be nil, if no error occurred Error() error // Value can be nil in case of errors, or when the operation doesn't return a value. Value() interface{} }
OperationResult is the result of a CRUD operation
func ConflictResult ¶
func ConflictResult(err error) OperationResult
ConflictResult constructs an operation result for State 'Conflict'.
func CreatedResult ¶
func CreatedResult() OperationResult
CreatedResult constructs an operation result for State 'Created'.
func ErrorResult ¶
func ErrorResult(err error) OperationResult
ErrorResult constructs an operation result for State 'Error'.
func NotFoundResult ¶
func NotFoundResult() OperationResult
NotFoundResult constructs an operation result for State 'NotFound'.
func NotSupportedByResourceResult ¶
func NotSupportedByResourceResult() OperationResult
NotSupportedByResourceResult constructs an operation result for State 'NotSupportedByResource'.
func OkResult ¶
func OkResult(value interface{}) OperationResult
OkResult constructs an operation result for State 'Ok'.
value can be nil.
func ValidationFailedResult ¶
func ValidationFailedResult(err error) OperationResult
ValidationFailedResult constructs an operation result for State 'ValidationFailed'.
type PagingInfo ¶
type PagingInfo struct { // SupportsPaging indicates whether the datasource even supports paging. If false, it means that all the applicable // results are rendered on one page, page #1. SupportsPaging bool `json:"supportsPaging"` // DoesKnowTotalRecords indicates whether the datasource can accurately provide the exact amount of items in the datasource. // if false, paging might still be available (see: SupportsPaging). DoesKnowTotalRecords bool `json:"doesKnowTotalRecords"` // PageSize is the maximum number of items per page. Minimum 1. PageSize int `json:"pageSize"` // PageNumber is the number of the page. One-based. PageNumber int `json:"pageNumber"` // TotalRecordsCount indicates exactly the amount of items found. Will be zero, is DoesKnowTotalRecords is false. TotalRecordsCount int `json:"totalRecordCount"` }
PagingInfo is used to describe how results are being pages
type RecoverFunc ¶
type RecoverFunc func(name string, ctx servicefoundation.AppContext, w http.ResponseWriter, r *http.Request)
RecoverFunc is the recovery function as needed by the CRUD functionality
type Service ¶
type Service interface { // GetAll is used to get a list of entities, optionally applying paging, filtering, sorting. GetAll(request *DataSetRequest) OperationResult // GetByID returns the entity with the specified ID. GetByID(id EntityKey) OperationResult // Add will add the given entity. The returned value is the ID of the new entity. Add(entity Entity) OperationResult // Update will update an existing entity. The returned value is the new state of the entity. Update(id EntityKey, entity Entity) OperationResult // Delete will delete the entity with the specified ID. Delete(id EntityKey) OperationResult }
Service is the interface that needs to be implemented to provide the actual implementation to do CRUD on a resource.
Note that not all the operations need to be implemented
type SortDirection ¶
type SortDirection string
SortDirection describes how results are sorted
const ( // Asc sorts ascending Asc SortDirection = "Asc" // Desc sorts decending Desc SortDirection = "Desc" )
type State ¶
type State int
State is used to describe the high level state of a requested CRUD operation.
const ( // Ok means that no issues were found Ok State = 1 // ValidationFailed means that something invalid in the request was encountered ValidationFailed State = 2 // Error is a generic error, such as an unhandled error. Use when none of the other states are applicable. Error State = 3 // NotFound means that the entity with the given identity does not exist (anymore). NotFound State = 4 // Conflict means that the requested operation was understood, but conflicts with the current state of the entity. Conflict State = 5 // NotSupportedByResource means that this operation is not supported - for example, we're trying to delete an item, // but the resource doesn't support deletes at all (example: a read-only lookup table). NotSupportedByResource State = 6 // Created is the same as OK, but used to signify that the entity was created Created State = 7 )