apihttpwrapper

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

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

Go to latest
Published: Oct 2, 2021 License: MIT Imports: 15 Imported by: 0

README

ApiHttpWrapper

TL;DR

apihttpwrapper是一个golang的HTTP JSON API框架. 简而言之, 它可以很容易地把一个golang的函数或者对象方法转换成HTTP JSON API, 使用者只需要 考虑该函数或方法应当对应哪个URL路径, 而不用关心json编解码/url query string解析/url pattern解析等各种琐事.

Example

它用起来就像这样:

package main

import "os"
import "net/http"
import "github.com/abadcafe/apihttpwrapper"

type userInfo struct {
    Age int
    Address string
}

type userName struct {
    Name string
}

type user struct {
    userName
    userInfo
}

func addUser(ctx *apihttpwrapper.ServiceMethodContext, user *user) error {
    // do add user or return error
    return nil
}

func getUser(ctx *apihttpwrapper.ServiceMethodContext, name *userName) (*userInfo, error) {
    // return userInfo or error
    return &userInfo{}, nil
}

func main() {
    accessLogFile, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err)
    }

    routes := []*apihttpwrapper.Route{
        {Method: "POST", Path: "/user/:Name", Function: addUser},
        {Method: "POST", Path: "/user/", Function: addUser},
        {Method: "GET", Path: "/user/:Name", Function: getUser, BypassRequestBody: true},
    }
    loggingServiceRouter, err := apihttpwrapper.NewLoggingHTTPRouter(routes, nil, accessLogFile)
    if err != nil {
        panic(err)
    }

    http.Handle("/", loggingServiceRouter)
    _ = http.ListenAndServe(":8080", nil)
}

就这么几行, 就得到了一个带access log功能的HTTP JSON API服务器.

可以用curl与之交互:

# 添加用户, name这个字段放在url pattern里, 优先级最高
curl -H "Content-Type: application/json" -d '{"Age": 18, "Address": "beijing"}' http://127.0.0.1:8080/user/test
# 或者把name字段直接放在json body里, 优先级次高
curl -H "Content-Type: application/json" -d '{"Name": "test", "Age": 18, "Address": "beijing"}' http://127.0.0.1:8080/user/
# 或者把name字段放在query string里, 优先级最低
curl -H "Content-Type: application/json" -d '{"Age": 18, "Address": "beijing"}' http://127.0.0.1:8080/user/?name=test

# 获取用户信息
curl -G http://127.0.0.1:8080/user/test

如果函数返回error或者panic了, 该框架会自动封装成HTTP的500错误.

FAQ

对函数原型是否有要求?

是的, 只支持2种函数原型:

  1. func(*ServiceMethodContext, *struct) (any_struct_pointer, error) 框架会把url pattern/json/query string解析成第二个参数struct, 并把第一个返回值给json encode之后放在response body里输出.

  2. func(*ServiceMethodContext, *struct) error 框架不处理返回值, 用户可以自己通过ServiceMethodContext.ResponseWriter输出任意body.

如果返回了error或函数panic了, 则按以下格式输出:

{
  "code": 500,
  "msg": "service method error", 
  "data": "returned error string"
}
我想返回自定义的错误码怎么办?

你可以使用ServiceMethodContext.ResponseStatusSetter()方法.

我的函数并不关心输入的参数怎么办?

直接这样定义函数就好了:

func getSomething(_ *apihttpwrapper.ServiceMethodContext, _ *struct{}) (anything, error) {
    return anything, nil
}
apihttpwrapper.ServiceMethodContext是干吗用的?

这个结构体包含以下字段:

type ServiceMethodContext struct {
	Context              context.Context // 该HTTP请求的context
	RemoteAddr           string // 发起请求的远端地址, 有可能是反向代理服务器的IP地址.
	RequestHeader        http.Header // 请求头, http.Header类型, 各字段都可以读.
	RequestBodyReader    io.ReadCloser // request body
	ResponseStatusSetter func(status int) // 响应头, 用来设置response status code.
	ResponseHeader       http.Header // 响应头, http.Header类型, 可以往里添各种http头的字段.
	ResponseBodyWriter   io.Writer // response body
}

这些字段都可以随便使用.

但需要注意的是, 如果你想自己处理request body, 那么你就应当把Route.BypassRequestBody设为true, 这样框架就会忽略request body, 留给你自 己的函数来解析.

access log是否支持自动切分?

日志切分这个事情并不应当由HTTP JSON API框架来完成, 你可以用autosplitfile来替代普通的 os.File传进apihttpwrapper.NewLoggingHTTPRouter()方法里, 这样你的access log就是自动切分的了.

Documentation

Index

Constants

View Source
const ServiceHandlerAccessLogRowFillerContextKey = "apihttpwrapper.ServiceHandlerAccessLogRowFiller"

Variables

This section is empty.

Functions

func NewHTTPRouter

func NewHTTPRouter(routes []*Route) (*httprouter.Router, error)

func NewLoggingHTTPRouter

func NewLoggingHTTPRouter(routes []*Route, loggingHeaders []string, logWriter io.Writer) (http.Handler, error)

func RegisterRoutes

func RegisterRoutes(r *httprouter.Router, loggerContextKey interface{}, routes []*Route) error

Types

type AccessLogDecorator

type AccessLogDecorator struct {
	http.Handler
	// contains filtered or unexported fields
}

func NewAccessLogDecorator

func NewAccessLogDecorator(handler http.Handler, logWriter io.Writer, loggingHeaders []string,
	rowFillerContextKey interface{}, rowFillerFactory AccessLogRowFillerFactory) *AccessLogDecorator

func (*AccessLogDecorator) ServeHTTP

func (d *AccessLogDecorator) ServeHTTP(w http.ResponseWriter, r *http.Request)

type AccessLogRow

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

func (*AccessLogRow) SetRowField

func (row *AccessLogRow) SetRowField(field string, value string)

type AccessLogRowFiller

type AccessLogRowFiller interface{}

func ServiceHandlerAccessLogRowFillerFactory

func ServiceHandlerAccessLogRowFillerFactory(row *AccessLogRow) AccessLogRowFiller

type AccessLogRowFillerFactory

type AccessLogRowFillerFactory func(*AccessLogRow) AccessLogRowFiller

type FormattedResponse

type FormattedResponse struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type MethodLogger

type MethodLogger interface {
	Record(field string, value string)
}

type Route

type Route struct {
	Method            string
	Path              string
	Function          interface{}
	BypassRequestBody bool
}

type ServiceHandler

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

func NewServiceHandler

func NewServiceHandler(method interface{}, loggerContextKey interface{},
	bypassRequestBody bool) (h *ServiceHandler, err error)

func (*ServiceHandler) ServeHTTP

func (h *ServiceHandler) ServeHTTP(respWriter http.ResponseWriter, req *http.Request)

func (*ServiceHandler) ServeHTTPWithParams

func (h *ServiceHandler) ServeHTTPWithParams(rw http.ResponseWriter, r *http.Request, params httprouter.Params)

type ServiceMethodContext

type ServiceMethodContext struct {
	Context              context.Context
	RemoteAddr           string
	RequestHeader        http.Header
	RequestBodyReader    io.ReadCloser
	ResponseStatusSetter func(status int)
	ResponseHeader       http.Header
	ResponseBodyWriter   io.Writer
}

Jump to

Keyboard shortcuts

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