crud

package module
v0.0.0-...-6069bc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2017 License: MIT Imports: 10 Imported by: 0

README

crud-go

Go library for simple CRUD operations.

Build Status GoDoc

See also https://github.com/Travix-International/crud-protocol

Documentation

Overview

Package crud is a library for simple CRUD operations.

Index

Constants

This section is empty.

Variables

View Source
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

View Source
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

View Source
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

View Source
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

View Source
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
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL