程序员社区

go RestAPI编写技巧

//随着API接口增加,项目中会出现很多重复的代码,一种可扩展的方法就是将重复代码抽象出来
//对于以JSON作为序列化方式的接口,我们可以增加如下方法:

//方法一,从请求当中解析出,请求数据
func decodeBody(r *http.Request, v interface{}) error {
    defer r.Body.Close()
    return json.NewDecoder(r.Body).Decode(v)
}

//方法二,将相应数据序列化并写入http.ResponseWriter中
func encodeBody(w http.ResponseWriter, r *http.Request, v interface{}) error {
    return json.NewEncoder(w).Encode(v)
}

//方法3,该方法使用方法2更简化了,需要API应答的处理过程,只需要将应答状态码和应答的数据传入即可
func respond(w http.ResponseWriter, r *http.Request, status int, data interface{}) {
    w.WriteHeader(status)
    if data != nil {
        encodeBody(w, r, data)
    }
}

//方法4,restAPI方法中,错误处理是经常碰到的,构造一个方便的错误处理会增加开发效率
func respondErr(w http.ResponseWriter, r *http.Request, status int, args ...interface{}) {
    respond(w, r, status, map[string]interface{}{
        "error": map[string]interface{}{
            "message": fmt.Sprint(args...),
        },
    })
}

//方法5,将方法4封装成http错误处理
func respondHTTPErr(w http.ResponseWriter, r *http.Request, status int) {
    respondErr(w, r, status, http.StatusText(status))
}

//API handlers之间共享数据方法:
type contextKey struct {
    name string
}

var contextKeyAPIKey = &contextKey{"api-key"}

func APIKey(ctx context.Context) (string, bool) {
    key, ok := ctx.Value(contextKeyAPIKey).(string)
    return key, ok
}

//API处理函数封装,函数1
func withAPIKey(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        key := r.URL.Query().Get("key")
        if !isValidAPIKey(key) {
            respondErr(w, r, http.StatusUnauthorized, "invalid API key")
            return
        }
        ctx := context.WithValue(r.Context(), contextKeyAPIKey, key)
        fn(w, r.WithContext(ctx))
    }
}

func isValidAPIKey(key string) bool {
    return key == "abc123"
}

//方法2,处理跨域问题
func withCORS(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Expose-Headers", "Location")
        fn(w, r)
    }
}

type server struct{}

//API对资源的处理方式:
func (s *server) HandlResource(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        s.HandleResourceGet(w, r)
        return
    case "POST":
        s.handleRresourcePost(w, r)
        return
    case "DELETE":
        s.handleResourceDelete(w, r)
        return
    default:
        respondHTTPErr(w, r, http.StatusNotFound)
    }
}
赞(0) 打赏
未经允许不得转载:IDEA激活码 » go RestAPI编写技巧

一个分享Java & Python知识的社区