gogo

package module
v0.0.0-...-0e3adaf Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2016 License: MIT Imports: 30 Imported by: 0

README

gogo

Build Status

RESTful api framework of golang.

It's heavily inspired from neko which created by RocWong.

Installation

$ go get github.com/dolab/gogo
  • Create application using scaffold tools
$ go get github.com/dolab/gogo/gogo

# show gogo helps
$ gogo -h

# create a new application
$ gogo new myapp

# fix application import path
$ cd myapp
$ source env.sh

# run development server
$ make godev

# run test
$ make
  • Create application from skeleton

DEPRECATED!!! Please using scaffold way.

$ cp -r $GOPATH/src/github.com/dolab/gogo/skeleton myapp

# fix application import path
$ cd myapp
$ source fix.sh
$ source env.sh

# run development server
$ make godev

Getting Started

  • Normal
package main

import (
    "github.com/dolab/gogo"
)

func main() {
    app := gogo.New("development", "/path/to/your/config")

    // GET /
    app.GET("/", func(ctx *gogo.Context) {
        ctx.Text("Hello, gogo!")
    })

    app.Run()
}
  • Using middlewares
package main

import (
    "github.com/dolab/gogo"
)

func main() {
    app := gogo.New("development", "/path/to/your/config")

    app.Use(func(ctx *gogo.Context) {
        if panicErr := recover(); panicErr != nil {
            ctx.Abort()

            ctx.Logger.Errorf("[PANICED] %v", panicErr)
            return
        }

        ctx.Next()
    })

    // GET /
    app.GET("/", func(ctx *gogo.Context) {
        panic("Oops ~ ~ ~")
    })

    app.Run()
}
  • Using group
package main

import (
    "encoding/base64"
    "net/http"
    "strings"

    "github.com/dolab/gogo"
)

func main() {
    app := gogo.New("development", "/path/to/your/config")

    app.Use(func(ctx *gogo.Context) {
        if panicErr := recover(); panicErr != nil {
            ctx.Abort()

            ctx.Logger.Errorf("[PANICED] %v", panicErr)
        }

        ctx.Next()
    })

    // GET /
    app.GET("/", func(ctx *gogo.Context) {
        panic("Oops ~ ~ ~")
    })

    // prefix resources with /v1 and apply basic auth middleware for all sub-resources
    v1 := app.Group("/v1", func(ctx *gogo.Context) {
        auth := ctx.Header("Authorization")
        if !strings.HasPrefix(auth, "Basic ") {
            ctx.Abort()

            ctx.WriteHeader(http.StatusForbidden)
            ctx.Return()
            return
        }

        b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
        if err != nil {
            ctx.Logger.Errorf("Base64 decode error: %v", err)
            ctx.Abort()

            ctx.WriteHeader(http.StatusForbidden)
            ctx.Return()
            return
        }

        tmp := strings.SplitN(string(b), ":", 2)
        if len(tmp) != 2 || tmp[0] != "gogo" || tmp[1] != "ogog" {
            ctx.Abort()

            ctx.WriteHeader(http.StatusForbidden)
            ctx.Return()
            return
        }

        // settings which can used by following middlewares and handler
        ctx.Set("username", tmp[0])

        ctx.Next()
    })

    // GET /v1
    v1.GET("/", func(ctx *gogo.Context) {
        username := ctx.MustGet("username").(string)

        ctx.Text("Hello, " + username + "!")
    })

    app.Run()
}

TODOs

  • server config context
  • scoffold && generator
  • mountable third-part app

Thanks

Author

Spring MC

LICENSE

The MIT License (MIT)

Copyright (c) 2016

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

Index

Constants

View Source
const (
	Development RunMode = "development"
	Test        RunMode = "test"
	Production  RunMode = "production"

	DefaultMaxMultiformBytes = 32 << 20 // 32M
	DefaultMaxHeaderBytes    = 64 << 10 // 64k

	DefaultHttpRequestId       = "X-Request-Id"
	DefaultHttpRequestTimeout  = 30 // 30s
	DefaultHttpResponseTimeout = 30 // 30s
)

Variables

View Source
var (
	DefaultServerConfig = &ServerConfig{
		Addr:      "127.0.0.1",
		Port:      9090,
		Ssl:       false,
		RequestId: DefaultHttpRequestId,
	}

	DefaultLoggerConfig = &LoggerConfig{
		Output:    "stderr",
		LevelName: "info",
	}

	DefaultSectionConfig = &SectionConfig{
		Server: DefaultServerConfig,
		Logger: DefaultLoggerConfig,
	}
)
View Source
var (
	ErrHeaderFlushed = errors.New("Response headers have been written!")
	ErrConfigSection = errors.New("Config section does not exist!")
	ErrSettingsKey   = errors.New("Settings key is duplicated!")
	ErrHash          = errors.New("The hash function does not linked into the binary!")
)
View Source
var (
	// FindModeConfigFile returns config file for specified run mode.
	// You could custom your own run mode config file by overwriting.
	FindModeConfigFile = func(runMode, srcPath string) string {

		srcPath = path.Clean(srcPath)

		filename := "application.json"
		switch RunMode(runMode) {
		case Development:

			filename = "application.development.json"

		case Test:

			filename = "application.test.json"

		case Production:

		}

		file := path.Join(srcPath, "config", filename)
		if _, err := os.Stat(file); os.IsNotExist(err) {
			file = path.Join(srcPath, "config", "application.json")
		}

		return file
	}
)

Functions

func IsObjectIdHex

func IsObjectIdHex(s string) bool

IsObjectIdHex returns whether s is a valid hex representation of an ObjectId. See the ObjectIdHex function.

Types

type AppConfig

type AppConfig struct {
	Mode RunMode `json:"mode"`
	Name string  `json:"name"`

	Sections map[RunMode]*json.RawMessage `json:"sections"`
}

func NewAppConfig

func NewAppConfig(filename string) (*AppConfig, error)

NewAppConfig returns app config by parsing application.json

func NewStringAppConfig

func NewStringAppConfig(s string) (*AppConfig, error)

NewStringAppConfig returns app config by parsing json string

func (*AppConfig) Section

func (config *AppConfig) Section() *SectionConfig

Section is shortcut of retreving app server and logger configurations at one time It returns SectionConfig if exists, otherwise returns DefaultSectionConfig instead

func (*AppConfig) SetMode

func (config *AppConfig) SetMode(mode RunMode)

SetMode changes config mode

func (*AppConfig) UnmarshalJSON

func (config *AppConfig) UnmarshalJSON(v interface{}) error

UnmarshalJSON parses JSON-encoded data of section and stores the result in the value pointed to by v. It returns ErrConfigSection error if section of the current mode does not exist.

type AppLogger

type AppLogger struct {
	*logger.Logger
	// contains filtered or unexported fields
}

AppLogger implements Logger interface

func NewAppLogger

func NewAppLogger(output, filename string) *AppLogger

func (*AppLogger) New

func (l *AppLogger) New(requestId string) Logger

New returns a new Logger with provided requestId which shared writer with current logger

func (*AppLogger) RequestId

func (l *AppLogger) RequestId() string

type AppParams

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

func NewAppParams

func NewAppParams(r *http.Request, params httprouter.Params) *AppParams

func (*AppParams) Bson

func (p *AppParams) Bson(v interface{}) error

Bson unmarshals request body with bson codec

func (*AppParams) File

File retrieves multipart uploaded file of HTTP POST request

func (*AppParams) Get

func (p *AppParams) Get(name string) string

Get returns the first value for the named component of the request. NOTE: httprouter.Params takes precedence over URL query string values.

func (*AppParams) Gob

func (p *AppParams) Gob(v interface{}) error

Gob decode request body with gob codec

func (*AppParams) HasForm

func (p *AppParams) HasForm(name string) bool

HasForm returns whether named param is exist for POST/PUT request body.

func (*AppParams) HasQuery

func (p *AppParams) HasQuery(name string) bool

HasQuery returns whether named param is exist for URL query string.

func (*AppParams) Json

func (p *AppParams) Json(v interface{}) error

Json unmarshals request body with json codec

func (*AppParams) Post

func (p *AppParams) Post(name string) string

Post returns the named comonent of the request by calling http.Request.FormValue()

func (*AppParams) Xml

func (p *AppParams) Xml(v interface{}) error

Xml unmarshals request body with xml codec

type AppRoute

type AppRoute struct {
	Handlers []Middleware
	// contains filtered or unexported fields
}

func NewAppRoute

func NewAppRoute(prefix string, server *AppServer) *AppRoute

NewAppRoute creates a new app route with specified prefix and server

func (*AppRoute) Any

func (r *AppRoute) Any(path string, handler Middleware)

Any is a shortcut for all request methods

func (*AppRoute) DELETE

func (r *AppRoute) DELETE(path string, handler Middleware)

DELETE is a shortcut of route.Handle("DELETE", path, handler)

func (*AppRoute) GET

func (r *AppRoute) GET(path string, handler Middleware)

GET is a shortcut of route.Handle("GET", path, handler)

func (*AppRoute) Group

func (r *AppRoute) Group(prefix string, middlewares ...Middleware) *AppRoute

Group returns a new app route group which has the same prefix path and middlewares

func (*AppRoute) HEAD

func (r *AppRoute) HEAD(path string, handler Middleware)

HEAD is a shortcut of route.Handle("HEAD", path, handler)

func (*AppRoute) Handle

func (r *AppRoute) Handle(method string, path string, handler Middleware)

Handle registers a new resource with its handler

func (*AppRoute) MockHandle

func (r *AppRoute) MockHandle(method string, path string, response http.ResponseWriter, handler Middleware)

MockHandle mocks a new resource with specified response and handler, useful for testing

func (*AppRoute) OPTIONS

func (r *AppRoute) OPTIONS(path string, handler Middleware)

OPTIONS is a shortcut of route.Handle("OPTIONS", path, handler)

func (*AppRoute) PATCH

func (r *AppRoute) PATCH(path string, handler Middleware)

PATCH is a shortcut of route.Handle("PATCH", path, handler)

func (*AppRoute) POST

func (r *AppRoute) POST(path string, handler Middleware)

POST is a shortcut of route.Handle("POST", path, handler)

func (*AppRoute) PUT

func (r *AppRoute) PUT(path string, handler Middleware)

PUT is a shortcut of route.Handle("PUT", path, handler)

func (*AppRoute) Static

func (r *AppRoute) Static(path, root string)

Static serves files from the given dir

func (*AppRoute) Use

func (r *AppRoute) Use(middlewares ...Middleware)

Use registers new middlewares to the route TODO: ignore duplicated middlewares?

type AppServer

type AppServer struct {
	*AppRoute
	// contains filtered or unexported fields
}

func New

func New(runMode, srcPath string) *AppServer

New creates application server with config resolved of run mode.

func NewAppServer

func NewAppServer(mode RunMode, config *AppConfig, logger Logger) *AppServer

func NewWithLogger

func NewWithLogger(runMode, srcPath string, logger Logger) *AppServer

NewWithLogger creates application server with provided Logger

func (*AppServer) Clean

func (s *AppServer) Clean()

Clean removes all registered middlewares, it useful in testing cases.

func (*AppServer) Config

func (s *AppServer) Config() *AppConfig

Config returns app config of the app server

func (*AppServer) Mode

func (s *AppServer) Mode() string

Mode returns run mode of the app server

func (*AppServer) Run

func (s *AppServer) Run()

Run runs the http server

func (*AppServer) ServeHTTP

func (s *AppServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface

func (*AppServer) Use

func (s *AppServer) Use(middlewares ...Middleware)

Use applies middlewares to app route NOTE: It dispatch to Route.Use by overwrite

type Context

type Context struct {
	Response Responser
	Request  *http.Request
	Params   *AppParams

	Server *AppServer
	Config *AppConfig
	Logger Logger
	// contains filtered or unexported fields
}

func NewContext

func NewContext(server *AppServer) *Context

func (*Context) Abort

func (c *Context) Abort()

Abort forces to stop call chain.

func (*Context) AddHeader

func (c *Context) AddHeader(key, value string)

AddHeader adds response header with key/value pair

func (*Context) Get

func (c *Context) Get(key string) (interface{}, bool)

Get returns a value of the key

func (*Context) GetFinal

func (c *Context) GetFinal(key string) (interface{}, bool)

GetFinal returns a frozen value of the key

func (*Context) HasHeader

func (c *Context) HasHeader(key string) bool

HasHeader returns true if request sets its header for canonicaled specified key

func (*Context) HasRawHeader

func (c *Context) HasRawHeader(key string) bool

HasRawHeader returns true if request sets its header with specified key

func (*Context) HashedReturn

func (c *Context) HashedReturn(hasher crypto.Hash, body ...interface{}) error

HashedReturn returns response with ETag header calculated hash of response.Body dynamically

func (*Context) Header

func (c *Context) Header(key string) string

Header returns request header value of canonicaled specified key

func (*Context) Json

func (c *Context) Json(data interface{}) error

Json returns response with json codec and Content-Type: application/json header

func (*Context) JsonP

func (c *Context) JsonP(callback string, data interface{}) error

JsonP returns response with json codec and Content-Type: application/javascript header

func (*Context) MustGet

func (c *Context) MustGet(key string) interface{}

MustGet returns a value of key or panic when key doesn't exist

func (*Context) MustGetFinal

func (c *Context) MustGetFinal(key string) interface{}

MustGetFinal returns a frozen value of key or panic when key doesn't exist

func (*Context) MustSetFinal

func (c *Context) MustSetFinal(key string, value interface{})

MustSetFinal associates a value with key for the context and freezes following update, it panics if key is duplicated.

func (*Context) Next

func (c *Context) Next()

Next executes the remain handlers in the chain. NOTE: It ONLY used in the middlewares!

func (*Context) RawHeader

func (c *Context) RawHeader(key string) string

RawHeader returns request header value of specified key

func (*Context) Redirect

func (c *Context) Redirect(location string)

Redirect returns a HTTP redirect to the specific location.

func (*Context) Render

func (c *Context) Render(w Render, data interface{}) error

func (*Context) RequestID

func (c *Context) RequestID() string

RequestID returns x-request-id value

func (*Context) RequestURI

func (c *Context) RequestURI() string

RequestURI returns request raw uri

func (*Context) Return

func (c *Context) Return(body ...interface{}) error

Return returns response following default Content-Type header

func (*Context) Set

func (c *Context) Set(key string, value interface{})

Set associates a new value with key for the context

func (*Context) SetFinal

func (c *Context) SetFinal(key string, value interface{}) error

SetFinal associates a value with key for the context and freezes following update

func (*Context) SetHeader

func (c *Context) SetHeader(key, value string)

SetHeaders sets response header with key/value pair

func (*Context) SetStatus

func (c *Context) SetStatus(code int)

SetStatus sets response status code

func (*Context) Text

func (c *Context) Text(data interface{}) error

Text returns response with Content-Type: text/plain header

func (*Context) Xml

func (c *Context) Xml(data interface{}) error

Xml returns response with xml codec and Content-Type: text/xml header

type DefaultRender

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

DefaultRender responses with default Content-Type header

func (*DefaultRender) ContentType

func (render *DefaultRender) ContentType() string

func (*DefaultRender) Render

func (render *DefaultRender) Render(v interface{}) error

type HashRender

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

HashRender responses with Etag header calculated from render data dynamically. NOTE: This always write response by copy if the render data is an io.Reader!!!

func (*HashRender) ContentType

func (render *HashRender) ContentType() string

func (*HashRender) Render

func (render *HashRender) Render(v interface{}) error

type JsonRender

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

JsonRender responses with Content-Type: application/json header It transform response data by json.Marshal.

func (*JsonRender) ContentType

func (render *JsonRender) ContentType() string

func (*JsonRender) Render

func (render *JsonRender) Render(v interface{}) error

type JsonpRender

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

JsonpRender responses with Content-Type: application/javascript header It transform response data by json.Marshal.

func (*JsonpRender) ContentType

func (render *JsonpRender) ContentType() string

func (*JsonpRender) Render

func (render *JsonpRender) Render(v interface{}) error

type Logger

type Logger interface {
	New(requestId string) Logger
	RequestId() string
	SetLevelByName(level string) error
	SetColor(color bool)

	Print(v ...interface{})
	Printf(format string, v ...interface{})
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})
	Info(v ...interface{})
	Infof(format string, v ...interface{})
	Warn(v ...interface{})
	Warnf(format string, v ...interface{})
	Error(v ...interface{})
	Errorf(format string, v ...interface{})
	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})
	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
}

Logger defines interface of application log apis.

type LoggerConfig

type LoggerConfig struct {
	Output    string `json:"output"` // valid values [stdout|stderr|null|path/to/file]
	LevelName string `json:"level"`  // valid values [debug|info|warn|error]

	FilterParams []string `json:"filter_params"`
}

logger config spec

func (*LoggerConfig) Level

func (l *LoggerConfig) Level() logger.Level

type Middleware

type Middleware func(ctx *Context)

Middleware represents request filters and resource handler NOTE: It is the filter's responsibility to invoke ctx.Next() for chainning.

type ObjectId

type ObjectId string

ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes long. MongoDB objects by default have such a property set in their "_id" property.

http://www.mongodb.org/display/DOCS/Object+IDs

func NewObjectId

func NewObjectId() ObjectId

NewObjectId returns a new unique ObjectId.

func NewObjectIdWithTime

func NewObjectIdWithTime(t time.Time) ObjectId

NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled with the provided number of seconds from epoch UTC, and all other parts filled with zeroes. It's not safe to insert a document with an id generated by this method, it is useful only for queries to find documents with ids generated before or after the specified timestamp.

func ObjectIdHex

func ObjectIdHex(s string) ObjectId

ObjectIdHex returns an ObjectId from the provided hex representation. Calling this function with an invalid hex representation will cause a runtime panic. See the IsObjectIdHex function.

func (ObjectId) Counter

func (id ObjectId) Counter() int32

Counter returns the incrementing value part of the id. It's a runtime error to call this method with an invalid id.

func (ObjectId) Hex

func (id ObjectId) Hex() string

Hex returns a hex representation of the ObjectId.

func (ObjectId) Machine

func (id ObjectId) Machine() []byte

Machine returns the 3-byte machine id part of the id. It's a runtime error to call this method with an invalid id.

func (ObjectId) Pid

func (id ObjectId) Pid() uint16

Pid returns the process id part of the id. It's a runtime error to call this method with an invalid id.

func (ObjectId) String

func (id ObjectId) String() string

String returns a hex string representation of the id. Example: ObjectIdHex("4d88e15b60f486e428412dc9").

func (ObjectId) Time

func (id ObjectId) Time() time.Time

Time returns the timestamp part of the id. It's a runtime error to call this method with an invalid id.

func (ObjectId) Valid

func (id ObjectId) Valid() bool

Valid returns true if id is valid. A valid id must contain exactly 12 bytes.

type Render

type Render interface {
	ContentType() string
	Render(v interface{}) error
}

Render represents HTTP response render

func NewDefaultRender

func NewDefaultRender(w Responser) Render

func NewHashRender

func NewHashRender(w Responser, hasher crypto.Hash) Render

func NewJsonRender

func NewJsonRender(w Responser) Render

func NewJsonpRender

func NewJsonpRender(w Responser, callback string) Render

func NewTextRender

func NewTextRender(w Responser) Render

func NewXmlRender

func NewXmlRender(w Responser) Render

type Response

type Response struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

func (*Response) Before

func (r *Response) Before(filter func(w Responser))

Before registers filters which invoked before response has written

func (*Response) Flush

func (r *Response) Flush()

func (*Response) FlushHeader

func (r *Response) FlushHeader()

FlushHeader writes response headers with status and reset size, it also invoke before filters

func (*Response) HeaderFlushed

func (r *Response) HeaderFlushed() bool

HeaderFlushed returns whether response headers has written

func (*Response) Size

func (r *Response) Size() int

func (*Response) Status

func (r *Response) Status() int

func (*Response) Write

func (r *Response) Write(data []byte) (size int, err error)

func (*Response) WriteHeader

func (r *Response) WriteHeader(code int)

WriteHeader sets response status code only by overwrites underline

type ResponseFilter

type ResponseFilter func(Responser)

type Responser

type Responser interface {
	http.ResponseWriter
	http.Flusher

	Before(filter func(w Responser)) // register before filter
	Size() int                       // return the size of response body
	Status() int                     // response status code
	HeaderFlushed() bool             // whether response header has been sent?
	FlushHeader()                    // send response header
}

Responser represents HTTP response interface

func NewResponse

func NewResponse(w http.ResponseWriter) Responser

type RunMode

type RunMode string

func (RunMode) IsDevelopment

func (mode RunMode) IsDevelopment() bool

func (RunMode) IsProduction

func (mode RunMode) IsProduction() bool

func (RunMode) IsTest

func (mode RunMode) IsTest() bool

func (RunMode) IsValid

func (mode RunMode) IsValid() bool

type SectionConfig

type SectionConfig struct {
	Server *ServerConfig `json:"server"`
	Logger *LoggerConfig `json:"logger"`
}

app server and logger config

type ServerConfig

type ServerConfig struct {
	Addr           string `json:"addr"`
	Port           int    `json:"port"`
	RTimeout       int    `json:"request_timeout"`  // time in s
	WTimeout       int    `json:"response_timeout"` // time in s
	MaxHeaderBytes int    `json:"max_header_bytes"`

	Ssl     bool   `json:"ssl"`
	SslCert string `json:"ssl_cert"`
	SslKey  string `json:"ssl_key"`

	Throttle   int    `json:"throttle"`    // in time.Second/throttle ms
	SlowdownMs int    `json:"slowdown_ms"` // in ms
	RequestId  string `json:"request_id"`
}

server config spec

type StatusCoder

type StatusCoder interface {
	StatusCode() int
}

StatusCoder represents HTTP response status code

type TextRender

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

TextRender responses with Content-Type: text/plain header It transform response data by stringify.

func (*TextRender) ContentType

func (render *TextRender) ContentType() string

func (*TextRender) Render

func (render *TextRender) Render(v interface{}) error

type XmlRender

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

XmlRender responses with Content-Type: text/xml header It transform response data by xml.Marshal.

func (*XmlRender) ContentType

func (render *XmlRender) ContentType() string

func (*XmlRender) Render

func (render *XmlRender) Render(v interface{}) error

Directories

Path Synopsis
skeleton

Jump to

Keyboard shortcuts

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