burrow

package module
v0.0.0-...-be55021 Latest Latest
Warning

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

Go to latest
Published: May 22, 2014 License: MIT Imports: 9 Imported by: 1

README

Burrow

Burrow is a REST API Framework designed with the following in mind:

  • Convention over Configuration
  • Simplicity
  • Ease of Use
  • Written in and for Golang

Intent

Most REST API frameworks allow API designers to specify very complex URI schemes to represent their API Objects. This approach to API frameworks has several drawbacks:

  • The URI schemes require copious documentation since they are difficult to understand intuitively.
  • URI schemes for each object must be created independently, introducing complexity and differences between similar APIs.
  • URI schemes are difficult to represent internal to the program, resulting in little to no linking between objects in an API hierarchy.

Burrow attempts to solve these by offloading the effort of defining URI schemes to the framework. This allows the developers to write API Objects without worrying about how the resulting API will look.

This allows the framework to do the following automatically:

  • Generate API endpoints
  • Generate documentation for your API endpoints (coming soon)
  • Manage links between referenced objects
  • Generate links in your API objects to make navigating your API dead simple

Introduction

The following go code will define an API for managing books, complete with links and endpoints to update records:

package main

import (
    "github.com/zfjagann/burrow"
)

type Book struct {
    Id     int `rest:"id"`
    Name   string
    ISBN   string
    Author string
}

var AllBooks []Book

func GetBook(id int) (interface{}, error) {
    if id < 0 || id >= len(AllBooks) {
        return nil, burrow.ApiError(404, "Could not find book with id: ", id)
    }
    return &AllBooks[id], nil
}

func GetBooks() ([]interface{}, error) {
    stuff := make([]interface{}, len(AllBooks))
    for i, thing := range AllBooks {
        stuff[i] = thing
    }
    return stuff, nil
}

func UpdateBook(obj interface{}) error {
    book := obj.(*Book)
    AllBooks[book.Id] = *book
    return nil
}

func init() {
    // Create dummy data...
    AllBooks = make([]Book, 3)
    AllBooks[0] = Book{0, "Great Expectations", "345678", "Charles Dickens"}
    AllBooks[1] = Book{1, "Robinson Crusoe", "234567", "Daniel Dafoe"}
    AllBooks[2] = Book{2, "Henry V", "123456", "William Shakespeare"}
}

func main() {
    api := burrow.NewApi()

    api.Add(burrow.New(Book{}, nil, GetBook, GetBooks, UpdateBook, nil))

    // Run the server!
    api.Serve("0.0.0.0", 8080)
}

For the complete example see examples/simple.go.

The API

We can start using the API immediately. Start by hitting the root of the server: http://localhost:8080/.

The response JSON looks like:

{
    "links": {
        "Book index": "http://localhost:8080/book",
        "root": "/",
        "self": "/"
    }
}

The links provided in the output indicate which endpoints are available.

Now follow the Book index link:

[
    {
        "Author": "Charles Dickens",
        "ISBN": "345678",
        "Id": 0,
        "Name": "Great Expectations",
        "links": {
            "Book index": "http://localhost:8080/book",
            "root": "/",
            "self": "http://localhost:8080/book/0"
        }
    },
    {
        "Author": "Daniel Dafoe",
        "ISBN": "234567",
        "Id": 1,
        "Name": "Robinson Crusoe",
        "links": {
            "Book index": "http://localhost:8080/book",
            "root": "/",
            "self": "http://localhost:8080/book/1"
        }
    },
    {
        "Author": "William Shakespeare",
        "ISBN": "123456",
        "Id": 2,
        "Name": "Henry V",
        "links": {
            "Book index": "http://localhost:8080/book",
            "root": "/",
            "self": "http://localhost:8080/book/2"
        }
    }
]

We get back our dummy book data that we setup. Each of the records also has a link to themselves to allow you to show an individual record.

Since we defined UpdateBook and handed it to the API, we can also update book objects:

$ curl -XPUT -d '{"Author":"Willem Dafoe"}' http://localhost:8080/book/1

Gives us back:

{
    "Author": "Willem Dafoe",
    "ISBN": "234567",
    "Id": 1,
    "Name": "Robinson Crusoe",
    "links": {
        "Book index": "http://localhost:8080/book",
        "root": "/",
        "self": "http://localhost:8080/book/1"
    }
}
The CRUD

The CRUD model defined above for managing books includes functions for viewing and modifying books. This is sufficient for a simple application, but a more thorough CRUD model would also allow deletion and addition of books.

The burrow.CRUD interface provides an interface for users to define full CRUDs.

The CRUD includes 7 methods that can be used to manipulate objects.

type CRUD interface {
    /*
        Returns the name of the type that this CRUD represents.

        This is used to determine URIs.
    */
    Name() string

    /*
        Returns the reflected type of the object this CRUD manages.
    */
    Reflect() reflect.Type

    /*
        Create a new object and return it.
    */
    Create() (interface{}, error)

    /*
        Update a given object.
        Returns nil if successful, and an error otherwise.
    */
    Update(interface{}) error

    /*
        Load and return a single object.
        The error return value will be nil if successful, and non-nil otherwise.
    */
    Read(int) (interface{}, error)

    /*
        Load and return all objects.
        The error return value will be nil if succesful, and non-nil otherwise.
    */
    Index() ([]interface{}, error)

    /*
        Delete the object specified by the given id.
        Returns nil if successful, and an error otherwise.
    */
    Delete(int) error
}

More Examples

Burrow has the ability to create links to related objects. See examples/references.go.

Dependencies

Burrow is based on Traffic, and requires that it be installed to be used.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Api

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

func NewApi

func NewApi() (api *Api)

func (*Api) Add

func (api *Api) Add(crud CRUD)

func (*Api) Serve

func (api *Api) Serve(addr string, port int)

type CRUD

type CRUD interface {
	/*
		Returns the name of the type that this CRUD represents.

		This is used to determine URIs.
	*/
	Name() string

	/*
		Returns the reflected type of the object this CRUD manages.
	*/
	Reflect() reflect.Type

	/*
		Create a new object and return it.
	*/
	Create() (interface{}, error)

	/*
		Update a given object.
		Returns nil if successful, and an error otherwise.
	*/
	Update(interface{}) error

	/*
		Load and return a single object.
		The error return value will be nil if successful, and non-nil otherwise.
	*/
	Read(int) (interface{}, error)

	/*
		Load and return all objects.
		The error return value will be nil if succesful, and non-nil otherwise.
	*/
	Index() ([]interface{}, error)

	/*
		Delete the object specified by the given id.
		Returns nil if successful, and an error otherwise.
	*/
	Delete(int) error
}

Represents the interface of interaction between the backend Object store and the API.

func New

func New(
	value interface{},
	creator func() (interface{}, error),
	reader func(int) (interface{}, error),
	indexer func() ([]interface{}, error),
	updater func(interface{}) error,
	deleter func(interface{}) error,
) CRUD

type Error

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

func ApiError

func ApiError(status int, items ...interface{}) Error

func NewError

func NewError(items ...interface{}) Error

func (Error) Error

func (e Error) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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