presto

package module
v0.2.11 Latest Latest
Warning

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

Go to latest
Published: May 8, 2019 License: Apache-2.0 Imports: 4 Imported by: 0

README

Presto 🎩

GoDoc Go Report Card Build Status Codecov

Magical REST interfaces for Go

Presto is a thin wrapper library that helps structure and simplify the REST interfaces you create in Go. Its purpose is to encapsulate all of the boilerplate code that is commonly required to publish a server-side service via a REST interface. Using Presto, your route configuration code looks like this:

// Define a new service to expose online as a REST collection.
presto.NewCollection(echo.Echo, NoteFactory, "/notes").
    List().
    Post(role.InRoom).
    Get(role.InRoom).
    Put(role.InRoom, role.Owner).
    Patch(role.InRoom, role.Owner).
    Delete(role.InRoom, role.Owner).
    Method("action-name", customHandler, role.InRoom, role.CustomValue)

Design Philosophy

Clean Architecture

Presto lays the groundword to implement a REST API according to the CLEAN architecture, first published by Uncle Bob. This means decoupling business logic and databases, by injecting dependencies down through your application. To do this in a type-safe manner, Presto requires that your services and objects fit into its interfaces, which describe minimal behavior that each must support in order to be used by Presto. Once Presto is able to work with your business logic in an abstract way, the rest of the common code is repeated for each API endpoint you need to create.

REST API Design Rulebook

Presto works hard to implement REST APIs according to the patterns laid out in the "REST API Design Rulebook", by Mark Massé. This means:

  • Clear route names
  • Using HTTP methods (GET, PUT, POST, PATCH, DELETE) to determine the action being taken
  • Using POST and URL route parameters for other API endpoints that don't fit neatly into the standard HTTP method definitions.
Minimal Dependencies

Presto's only dependency is on the Echo router, which is a very fast, open-source router for creating HTTP servers in Go. Our ultimate goal with this package is to remove this as a hard dependency eventually, and refactor this code to work with multiple routers in the Go ecosystem.

Services

Presto does not replace your application business logic. It only exposes your internal services via a REST API. Each endpoint must be linked to a corresponding service (that matches Presto's required interface) to handle the actual loading, saving, and deleting of objects.

Factories

The specific work of creating services and objects is pushed out to a Factory object, which provides a map of your complete domain. The factories also manage dependencies (such as a live database connection) for each service that requires it. Here's an example factory:



User Roles

It's very likely that your API requires custom authentication and authorization for each endpoint. Since this is very custom to your application logic and environment, Presto can't automate this for you. But, Presto does make it very easy to organize the permissions for each endpoint into a single, readable location. Authorization requirements for each endpoint are baked into common functions called roles, and then passed in to Presto during system configuration.


/// IN YOUR ROUTE CONFIGURATION

presto.NewCollection(echo.Echo, NoteFactory, "/notes").
    Post(role.InRoom) // The user must have permissions to post into the Room into which they're posting.

// IN YOUR ROLES PACKAGE

// InRoom determines if the requester has access to the Room in which this object resides.
// If so, then access to it is valid, so return a TRUE..  If not, then return a FALSE.
func InRoom(ctx echo.Context, object Object) bool {

    // Get the list of rooms that this user has access to..
    // For example, using JWT tokens in the context request headers.
    allowedRoomIDs := getRoomListFromContext(ctx)

    // Uses a type switch to retrieve the roomID from the Object interface.
    roomID, err := getRoomIDFromObject(object)

    if err != nil {
        return false
    }

    // Try to find the object.RoomID in the list of allowed rooms.
    for _, allowedRoomID := range allowedRoomIDs {
        if allowedRoomID == roomID {
            return true // If so, then you're in.
        }
    }

    // Otherwise, you are not permitted to access this object.
    return false;
}

Selectors

Boilerplate REST Endpoints

Custom REST Endpoints

Documentation

Overview

Package presto gives you a strong foundation for creating REST interfaces using Go and the [Echo Router](http://echo.labstack.com)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultScope added in v0.2.11

func DefaultScope(ctx echo.Context) (data.Expression, *derp.Error)

DefaultScope maps all of the route parameters directly into a scope, matching the names used in the route itself. It is the default behavior for presto, and should serve most use cases.

func RequestInfo

func RequestInfo(context echo.Context) map[string]string

RequestInfo inspects a request and returns any information that might be useful for debugging problems. It is primarily used by internal methods whenever there's a problem with a request.

func WithCache added in v0.2.6

func WithCache(cache Cache)

WithCache sets the global cache for all presto endpoints.

func WithScopes added in v0.2.11

func WithScopes(scopes ...ScopeFunc)

WithScopes sets global settings for all collections that are managed by presto

Types

type Cache

type Cache interface {

	// Get returns the cache value (ETag) corresponding to the argument (objectID) provided.
	// If a value is not found, then Get returns empty string ("")
	Get(objectID string) string

	// Set updates the value in the cache, returning a derp.Error in case there was a problem.
	Set(objectID string, value string) *derp.Error
}

Cache maintains fast access to key/value pairs that are used to check ETags of incoming requests. By default, Presto uses a Null cache, that simply reports cache misses for every request. However, this can be extended by the user, with any external caching system that matches this interface.

type Collection

type Collection struct {
	// contains filtered or unexported fields
}

Collection provides all of the HTTP hanlers for a specific domain object, or collection of records

func NewCollection

func NewCollection(router *echo.Echo, factory ServiceFactory, name string, prefix string, token string) *Collection

NewCollection returns a fully populated Collection object

func (*Collection) Delete

func (collection *Collection) Delete(roles ...RoleFunc) *Collection

Delete returns an HTTP handler that knows how to delete records from the collection

func (*Collection) Get

func (collection *Collection) Get(roles ...RoleFunc) *Collection

Get returns an HTTP handler that knows how to retrieve a single record from the collection

func (*Collection) List

func (collection *Collection) List(roles ...RoleFunc) *Collection

List returns an HTTP handler that knows how to list a series of records from the collection

func (*Collection) Method

func (collection *Collection) Method(name string, handler echo.HandlerFunc)

Method defines a custom "method"-style endpoint

func (*Collection) Patch

func (collection *Collection) Patch(roles ...RoleFunc) *Collection

Patch returns an HTTP handler that knows how to update in the collection

func (*Collection) Post

func (collection *Collection) Post(roles ...RoleFunc) *Collection

Post returns an HTTP handler that knows how to create new objects in the collection

func (*Collection) Put

func (collection *Collection) Put(roles ...RoleFunc) *Collection

Put returns an HTTP handler that knows how to update in the collection

func (*Collection) WithCache added in v0.2.5

func (collection *Collection) WithCache(cache Cache) *Collection

WithCache adds a local ETag cache for this collection only

func (*Collection) WithScopes added in v0.2.0

func (collection *Collection) WithScopes(scopes ...ScopeFunc) *Collection

WithScopes replaces the default scope with a new list of ScopeFuncs

type ETagger added in v0.2.8

type ETagger interface {

	// ETag returns a version-unique string that helps determine if an object has changed or not.
	ETag() string
}

type RoleFunc

type RoleFunc func(context echo.Context, object data.Object) bool

RoleFunc is a function signature that validates a user's permission to access a particular object

type ScopeFunc added in v0.2.0

type ScopeFunc func(context echo.Context) (data.Expression, *derp.Error)

ScopeFunc is the function signature for a function that can limit database queries to a particular "scope". It inspects the provided context and returns criteria that will be passed to all database queries.

type Service added in v0.2.0

type Service interface {

	// NewObject creates a newly initialized object that is ready to use
	NewObject() data.Object

	// Load retrieves a single object from the database
	LoadObject(criteria data.Expression) (data.Object, *derp.Error)

	// Save inserts/updates a single object in the database
	SaveObject(object data.Object, comment string) *derp.Error

	// Delete removes a single object from the database
	DeleteObject(object data.Object, comment string) *derp.Error

	// Close cleans up any connections opened by the service.
	Close()
}

Service defines all of the functions that a service must provide to work with Presto. It relies on the generic Object interface to load and save objects of any type. GenericServices will likely include additional business logic that is triggered when a domain object is created, edited, or deleted, but this is hidden from presto.

type ServiceFactory

type ServiceFactory interface {
	Service(name string) Service
}

ServiceFactory is an interface for objects that generate service sessions. Each session represents a single HTTP request, which can potentially span multiple database calls. This gives the factory an opportunity to initialize a new database session for each HTTP request.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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