1. 程式人生 > >sqler sql 轉rest api 原始碼解析(三) rest協議

sqler sql 轉rest api 原始碼解析(三) rest協議

rest 服務說明

rest 協議主要是將配置檔案中的巨集暴露為rest 介面,使用了labstack/echo web 框架,同時基於context 模型
進行巨集管理物件的共享,同時進行了一些中介軟體的註冊 cors RemoveTrailingSlash gzip Recover

rest 啟動

  • 中介軟體註冊
 
  e.Pre(middleware.RemoveTrailingSlash())
  e.Use(middleware.CORS())
  e.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 9}))
  e.Use(middleware.Recover())
  • 路由配置
    預設配置,以及指定巨集的路由
 
  e.GET("/", routeIndex)
  e.Any("/:macro", routeExecMacro, middlewareAuthorize)
   
  • 巨集執行路由
    包含了一個授權的中介軟體,同時在這個中間價中傳遞共享變數(macro)
 
func middlewareAuthorize(next echo.HandlerFunc) echo.HandlerFunc {
  return func(c echo.Context) error {
    if strings.HasPrefix(c.Param("macro"), "_") {
      return c.JSON(403, map[string]interface{}{
        "success": false,
        "error": "access not allowed",
      })
    }
    macro := macrosManager.Get(c.Param("macro"))
    if macro == nil {
      return c.JSON(404, map[string]interface{}{
        "success": false,
        "error": "resource not found",
      })
    }
    if len(macro.Methods) < 1 {
      macro.Methods = []string{c.Request().Method}
    }
    methodIsAllowed := false
    for _, method := range macro.Methods {
      method = strings.ToUpper(method)
      if c.Request().Method == method {
        methodIsAllowed = true
        break
      }
    }
    if !methodIsAllowed {
      return c.JSON(405, map[string]interface{}{
        "success": false,
        "error": "method not allowed",
      })
    }
    // for _, endpoint := range macro.Authorizers {
    // parts := strings.SplitN(endpoint, " ", 2)
    // if len(parts) < 2 {
    // return c.JSON(500, map[string]interface{}{
    // "success": false,
    // "error": fmt.Sprintf("authorizer: %s is invalid", endpoint),
    // })
    // }
    // resp, err := resty.R().SetHeaders(map[string]string{
    // "Authorization": c.Request().Header.Get("Authorization"),
    // }).Execute(parts[0], parts[1])
    // if err != nil {
    // return c.JSON(500, map[string]interface{}{
    // "success": false,
    // "error": err.Error(),
    // })
    // }
    // if resp.StatusCode() >= 400 {
    // return c.JSON(resp.StatusCode(), map[string]interface{}{
    // "success": false,
    // "error": resp.Status(),
    // })
    // }
    // }
   // 路由共享變數
    c.Set("macro", macro)
    return next(c)
  }
}
   
  • routeExecMacro
    routes.go 解析請求引數,解析巨集,返回json 格式資料
 
// routeExecMacro - execute the requested macro
func routeExecMacro(c echo.Context) error {
// 獲取請求引數,轉換為支援巨集繫結的map 物件
  macro := c.Get("macro").(*Macro)
  input := make(map[string]interface{})
  body := make(map[string]interface{})
  c.Bind(&body)
  for k := range c.QueryParams() {
    input[k] = c.QueryParam(k)
  }
  for k, v := range body {
    input[k] = v
  }
  headers := c.Request().Header
  for k, v := range headers {
    input["http_"+strings.Replace(strings.ToLower(k), "-", "_", -1)] = v[0]
  }
  out, err := macro.Call(input)
  if err != nil {
    code := errStatusCodeMap[err]
    if code < 1 {
      code = 500
    }
    return c.JSON(code, map[string]interface{}{
      "success": false,
      "error": err.Error(),
      "data": out,
    })
  }
  return c.JSON(200, map[string]interface{}{
    "success": true,
    "data": out,
  })
}
 
 

參考資料

https://github.com/labstack/echo
https://github.com/alash3al/sqler/blob/master/server_rest.go
https://github.com/alash3al/sqler/blob/master/routes.go