goweb

package
v0.0.0-...-86643de Latest Latest
Warning

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

Go to latest
Published: May 10, 2019 License: BSD-2-Clause Imports: 11 Imported by: 5

README

Goweb

A lightweight RESTful web framework for Go.

Goweb A lightweight RESTful web framework for Go.

Who uses Goweb?

  • "Using Goweb has greatly simplified the creation, maintenance, and consistency of several of our internal services, allowing us to focus our effort on the underlying behavior of the services themselves." Derek Buitenhuis, Vimeo
  • "We are actively developing with Goweb to implement the REST api in-front of a neural network application" Jon McMillan, MCN Healthcare
  • "We are developing an API on top of Goweb that will power our platform as well as allow customers to access our data via a REST API." Robert Mulley, CB Insights
Are you using Goweb?

We are looking to put together a list of companies / people that are using Goweb. If you would like to help promote Goweb, and be included in the list, please comment on our issue and we'll get it going. Thanks.

Get started

  • To install, run go get github.com/stretchr/goweb
  • Import the package as usual with import "github.com/stretchr/goweb" in your code.
  • Look at the example_webapp project for some ideas of how to get going
  • Read the Goweb API Documentation
  • To update to the latest version of goweb, just run go get -u github.com/stretchr/goweb

Features

  • Drastically improved path matching
  • Cleaner interface for responding (e.g. goweb.API.RespondWithData, and goweb.Respond.WithRedirect)
  • More control over standard response object for API responses
  • Cleaner RESTful interface design
    • Default OPTIONS implementation that informs clients what methods the controller exposes
  • Easily publish static files as well as code driven output
  • Much easier to write testable code
  • Better package structure
  • Modular design, making adding new stuff easy
  • Handler mechanism to easily add pre and post handlers to certain requests
  • Uses stretchr/codecs package allowing better support for multiple formats
  • Easily match paths using Regex instead
  • Better error management
  • Performance improvements from Goweb 1

Interesting articles

People who use Goweb also use

  • Gomniauth - Authentication package (OAuth2 etc.)

Requirements

  • Goweb runs on Go 1.1

Contributing

Please feel free to submit issues, fork the repository and send pull requests. Be sure to check out our development practices before you get going.

When submitting an issue, we ask that you please include steps to reproduce the issue so we can see it on our end also!

Licence

Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell

Please consider promoting this project if you find it useful.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Goweb - A simple, powerful web framework for Go.

Overview

Goweb follows the MVC pattern where you build controller objects, and map them to routes of URLs using the goweb.MapController function. Controller objects should adhear to one or more of the controllers.Restful* interfaces in order to be mapped correctly.

If you are not following RESTful patterns, you can do custom routing using the goweb.Map function.

See some real world examples of how to use Goweb by checking out the example web app code: https://github.com/stretchr/goweb/blob/master/example_webapp/main.go

Example

Your controllers, following a RESTful pattern, might look like this:

// PeopleController controls the 'people' resources.
type PeopleController struct {}

// ReadMany reads many people.
func (c *PeopleController) ReadMany(ctx context.Context) error {

  // TODO: show all people

}

// Read reads one person.
func (c *PeopleController) Read(id string, ctx context.Context) error {

  // TODO: show one person

}

// Create creates a new person.
func (c *PeopleController) Create(ctx context.Context) error {

  // TODO: create a person, and redirect to the Read method

}

In the above controller code, we are providing three RESTful methods, Read, ReadMany and Create.

To map this in Goweb, we use the MapController function like this:

mapErr := goweb.MapController(&PeopleController{})

This will map the two functions (since they follow the standards defined in the controllers package) to the appropriate RESTful URLs:

GET /people - ReadMany
GET /people/{id} - Read
POST /people - Create

To add more RESTful features (like Update and Delete), you just have to add the relevant methods to the controller and Goweb will do the rest for you.

For a full list of the supported methods, see the MapController function.

Mapping paths

If you want to map specific paths with Goweb, you can use the `goweb.Map` function with the following kinds of paths:

/literals - Normal text will be considered literal, meaning the path would
            have to match it exactly.

{variable} - Curly braces represent a segment of path that can be anything,
             and which will be made available via the `context.PathParam` method.

[optional-variable] - Square braces represent an optional segment.  If present,
                      will be made available via the `context.PathParam` method
                      but otherwise the path will still be a match.

* - A single `*` is similar to using `{}`, except the value is ignored.

*** - Three `*`'s matches anything in this segment, and any subsequent segments.
      For example, `/people/***` would match `/people`, `/people/123` and `/people/123/books/456`.

For some real examples of mapping paths, see the goweb.Map function, or check out the example_webapp in the code.

Responding

Goweb makes it easy to respond to requests using an extensible Responder pattern.

If you're building an API, you can respond using the `goweb.API` object, if you just need to respond in a normal HTTP manner, you can use the `goweb.Respond` object.

For details on how to make normal HTTP responses, see http://godoc.org/github.com/stretchr/goweb/responders#HTTPResponder

For details on how to make API responses, see http://godoc.org/github.com/stretchr/goweb/responders#APIResponder

Writing tests

Writing unit tests for your Goweb code is made possible via the `goweb.Test` and `goweb.TestOn` functions, and with a little help from the Testify HTTP package, see http://godoc.org/github.com/stretchr/testify/http

For a real example of what tests look like, see the tests in the example web app: https://github.com/stretchr/goweb/blob/master/example_webapp/main_test.go

Working with JSONP

If you are working in an environment that always requires a 200 response, simply do:

uri?always200=true

Additionally, if you need to override the HTTP Method used, simply pass it in a similar manner:

uri?method=GET

Changes from Goweb 1

Goweb 2 changes two key things about Goweb; mapping and responding.

Instead of `MapFunc`, the `Map` method is now very flexible accepting all sorts of input. See goweb.Map below for more details.

Instead of responding via the context.Context object, we have abstracted it out to responders, that allow you to easily respond in various ways. See Responding above for more information.

We have tried to include relevant panics when you try to use old Goweb style coding to help you update any old code, but if you get stuck please ask us for help on our group: https://groups.google.com/forum/?fromgroups#!forum/golang-goweb

Index

Constants

This section is empty.

Variables

View Source
var (
	// TestHttpRequest represents the current http.Request object
	// that is being tested.
	TestHttpRequest *http.Request

	// TestResponseWriter is the ResponseWriter that goweb.Test will
	// write to, in order to allow for testing.
	TestResponseWriter *testifyhttp.TestResponseWriter
)

API is a responders.APIResponder which provides the ability to make API responses.

This allows a simple interface for making API responses such as the following:

return goweb.API.Respond(ctx, 404, nil, []string{"File not found"})

CodecService is the service class that provides codec capabilities to Goweb.

Respond is a responders.HTTPResponder which provides the ability to make HTTP responses.

This allows a simple interface for making normal web responses such as the following:

return goweb.Respond.WithStatus(ctx, 404)

Functions

func DefaultHttpHandler

func DefaultHttpHandler() *handlers.HttpHandler

DefaultHttpHandler gets the HttpHandler that can be used to handle requests.

If nothing has been set using SetDefaultHttpHandler(), a fresh one will be created and served each time this function is called.

func Map

func Map(options ...interface{}) (handlers.Handler, error)

Map adds a new mapping to the DefaultHttpHandler.

The Map function has many flavours.

1. Implementing and passing in your own handlers.Handler object will just map the handler directly.

2. The path pattern, and the handler function, followed by any optional matcher funcs will cause the func to be executed when the path pattern matches.

(pathPattern, func [, matcherFuncs])

3. The HTTP method (or an array of HTTP methods), the path pettern, the handler function, followed by optional matcher funcs will cause the func to be executed when the path and HTTP method match.

(method|methods, pathPattern, func [, matcherFuncs])

4. Just the handler function, and any optional matcher funcs will add a catch-all handler. This should be the last call to Map that you make.

(func [, matcherFuncs])

Each matcherFunc argument can be one of three types:

  1. handlers.MatcherFunc
  2. []handlers.MatcherFunc
  3. func(context.Context) (MatcherFuncDecision, error)

Examples

The following code snippets are real examples of how to use the Map function:

// POST /events
handler.Map(http.MethodPost, "/events", func(c context.Context) error {

  // TODO: Add an event

  // no errors
  return nil

})

// POST|PUT /events
handler.Map([]string{http.MethodPost, http.MethodPut}, "/events", func(c context.Context) error {

  // TODO: Add an event

  // no errors
  return nil

})

// POST|PUT|DELETE|GET /articles/2013/05/01
handler.Map("/articles/{year}/{month}/{day}", func(c context.Context) error {

  day := c.PathParams().Get("day")
  month := c.PathParams().Get("month")
  year := c.PathParams().Get("year")

  // show the articles for the specified day

  // no errors
  return nil

})

// All requests
handler.Map(func(c context.Context) error {

  // everything else is a 404
  goweb.Respond.WithStatus(c, http.StatusNotFound)

  // no errors
  return nil

})

For a full overview of valid paths, see the "Mapping paths" section above.

func MapAfter

func MapAfter(options ...interface{}) (handlers.Handler, error)

MapAfter adds a new mapping to the DefaultHttpHandler that will be executed after other handlers.

The usage is the same as the goweb.Map function.

After handlers are called after the normal processing handlers are finished, and usually after the response has been written. Setting headers or writing additional bytes will have no effect in after handlers.

func MapBefore

func MapBefore(options ...interface{}) (handlers.Handler, error)

MapBefore adds a new mapping to the DefaultHttpHandler that will be executed before other handlers.

The usage is the same as the goweb.Map function.

Before handlers are called before any of the normal handlers, and before any processing has begun. Setting headers is appropriate for before handlers, but be careful not to actually write anything or Goweb will likely end up trying to write the headers twice and headers set in the processing handlers will have no effect.

func MapController

func MapController(options ...interface{}) error

MapController maps a controller in the handler.

A controller is any object that implements one or more of the controllers.Restful* interfaces.

They include:

RestfulController.Path(context.Context) string
RestfulCreator.Create(context.Context) error
RestfulReader.Read(context.Context) error
RestfulManyReader.ReadMany(context.Context) error
RestfulDeletor.Delete(id string, context.Context) error
RestfulManyDeleter.DeleteMany(context.Context) error
RestfulUpdater.Update(id string, context.Context) error
RestfulReplacer.Replace(id string, context.Context) error
RestfulManyUpdater.UpdateMany(context.Context) error
RestfulOptions.Options(context.Context) error
RestfulHead.Head(context.Context) error

Optionally, you can map Before and After methods too, to allow controller specific code to run at appropriate times:

BeforeHandler.Before(context.Context) error
AfterHandler.After(context.Context) error

To implement any of these methods, you just need to provide a method with the same name and signature. For example, a simple RESTful controller that just provides a simple GET might look like this:

type MyController struct{}

func (c *MyController) ReadMany(ctx context.Context) error {
  // TODO: do something
}

The above code would map only `GET /my`.

Controller Paths

This code will map the controller and use the Path() method on the controller to determine the path prefix (or it will try to guess the URL part based on the name of the struct):

MapController(controller)

This code will map the controller to the specified path prefix regardless of what the Path() method returns:

MapController(path, controller)

Optionally, you can pass matcherFuncs as optional additional arguments. See goweb.Map() for details on the types of arguments allowed.

func MapFunc

func MapFunc(path string, controllerFunc interface{}, matcherFuncs ...interface{}) interface{}

MapFunc is no longer supported in Goweb 2.

Use goweb.Map instead.

func MapRest

func MapRest(pathPrefix string, controller interface{})

MapRest is no longer supported in Goweb 2.

Use goweb.MapController instead.

func MapStatic

func MapStatic(publicPath, systemPath string, matcherFuncs ...handlers.MatcherFunc) (handlers.Handler, error)

MapStatic maps static files from the specified systemPath to the specified publicPath.

goweb.MapStatic("/static", "location/on/system/to/files")

Goweb will automatically expand the above public path pattern from `/static` to `/static/***` to ensure subfolders are automatcially mapped.

Paths

The systemPath is relative to where you will actually run your app from, for example if I am doing `go run main.go` inside the `example_webapp` folder, then `./` would refer to the `example_webapp` folder itself. Therefore, to map to the `static-files` subfolder, you just need to specify the name of the directory:

goweb.MapStatic("/static", "static-files")

In some cases, your systemPath might be different for development and production and this is something to watch out for.

Optionally, you can pass arguments of type MatcherFunc after the second argument. Unlike goweb.Map, these can only be of type MatcherFunc.

func MapStaticFile

func MapStaticFile(publicPath, staticFilePath string, matcherFuncs ...handlers.MatcherFunc) (handlers.Handler, error)

MapStaticFile maps a static file from the specified staticFilePath to the specified publicPath.

goweb.MapStaticFile("favicon.ico", "/location/on/system/to/icons/favicon.ico")

Only paths matching exactly publicPath will cause the single file specified in staticFilePath to be delivered to clients.

Optionally, you can pass arguments of type MatcherFunc after the second argument. Unlike goweb.Map, these can only be of type MatcherFunc.

func Redirect

func Redirect(response http.ResponseWriter, pathOrURLSegments ...interface{})

Redirect writes the Location header and sets the http.StatusFound response.

func RedirectPerm

func RedirectPerm(response http.ResponseWriter, pathOrURLSegments ...interface{})

RedirectPerm writes the Location header and sets the http.StatusMovedPermanently response.

func RedirectTemp

func RedirectTemp(response http.ResponseWriter, pathOrURLSegments ...interface{})

RedirectTemp writes the Location header and sets the http.StatusTemporaryRedirect response.

func RedirectTo

func RedirectTo(response http.ResponseWriter, pathOrURLSegments ...interface{})

RedirectTo writes the Location header.

func RegexPath

func RegexPath(regexpPattern string) handlers.MatcherFunc

RegexPath returns a MatcherFunc that mathces the path based on the specified Regex pattern.

To match a path that contains only numbers, you could do:

goweb.Map(executionFunc, goweb.RegexPath(`^[0-9]+$`))

func SetDefaultHttpHandler

func SetDefaultHttpHandler(handler *handlers.HttpHandler)

SetDefaultHttpHandler sets the HttpHandler that will be used to handle requests.

You do not need to call this, as calling DefaultHttpHandler() will create one if none has been set.

Calling `SetDefaultHttpHandler(nil)` will cause a new HttpHandler to be created next time one is needed.

Writing tests

When writing tests for Goweb, you should:

# Create your own HttpHandler,
# use SetDefaultHttpHandler() to tell goweb to use it,
# call the code being tested (code that presumably calls things like `goweb.Map` etc.)
# make assertions against your own HttpHandler
# call SetDefaultHttpHandler(nil) to clean things up (not necessary)

func Status

func Status(response http.ResponseWriter, status int)

Status writes the header with the specified status.

func Test

func Test(t *testing.T, options ...interface{})

goweb.Test tests some functionality. You will need to include the github.com/stretchr/testify/http package in order to make use of the test functionality.

Argument signatures

The Test function accepts many different signatures, following some simple rules:

  • The first argument is always the testing.T object
  • The second argument must be either a string, or a function that will build the TestRequest (a RequestBuilderFunc).
  • If the second argument is a string, an optional third argument would be either another string or []byte array representing the body.
  • The final argument must always be a func of type func(*testing.T, *testifyhttp.TestResponseWriter)

For example:

import (
  // import testify
  testifyhttp "github.com/MG-RAST/golib/stretchr/testify/http"
)

 // Test(t, string, func(*testing.T, *testifyhttp.TestResponseWriter))
 // Makes a request with the specified method and path, and calls
 // the function to make the appropriate assertions.
 goweb.Test(t, "METHOD path", func(t *testing.T, response *testifyhttp.TestResponseWriter) {

   /* assertions on the response go here */

 })

 // Test(t, RequestBuilderFunc, func(*testing.T, *testifyhttp.TestResponseWriter))
 // Makes a request by calling the RequestBuilderFunc, and calls
 // the function to make the appropriate assertions.
 goweb.Test(t, func() *http.Request {

   /* build and return the http.Request */

 }, func(t *testing.T, response *testifyhttp.TestResponseWriter) {

   /* assertions on the response go here */

 })

func TestOn

func TestOn(t *testing.T, handler *handlers.HttpHandler, options ...interface{})

TestOn is the same as the goweb.Test function, except it allows you to explicitly specify the HttpHandler on which to run the tests.

Types

type RequestBuilderFunc

type RequestBuilderFunc func() *http.Request

RequestBuilderFunc is a function that builds a TestRequest.

Directories

Path Synopsis
The context package contains the Context interface definition.
The context package contains the Context interface definition.
The controllers package provides interfaces that should be utilised when building RESTful controller objects.
The controllers package provides interfaces that should be utilised when building RESTful controller objects.
The example_webapp package contains a real working example of Goweb, showing off most of its features.
The example_webapp package contains a real working example of Goweb, showing off most of its features.
The handlers package contains tools for building pipelines of handlers which requests are run through in order to properly respond to requests.
The handlers package contains tools for building pipelines of handlers which requests are run through in order to properly respond to requests.
The http package contains useful web constants.
The http package contains useful web constants.
The paths package provides capabilities for working with paths, which is a key part of Goweb.
The paths package provides capabilities for working with paths, which is a key part of Goweb.
The responders package provides objects capable of making different kinds of responses to requests.
The responders package provides objects capable of making different kinds of responses to requests.
The webcontext package is Goweb's implementation of the Context object.
The webcontext package is Goweb's implementation of the Context object.
test
Package that enables you to write unit tests that rely on a context.Context object.
Package that enables you to write unit tests that rely on a context.Context object.

Jump to

Keyboard shortcuts

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