upgrade
This commit is contained in:
93
docs/docs.go
93
docs/docs.go
@@ -43,10 +43,16 @@ var doc = `{
|
|||||||
"summary": "获取授权信息",
|
"summary": "获取授权信息",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/demo.authResponse"
|
"$ref": "#/definitions/demo.authResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +81,7 @@ var doc = `{
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "用户信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -92,6 +98,18 @@ var doc = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,10 +147,22 @@ var doc = `{
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.CreateResponse"
|
"$ref": "#/definitions/user_model.CreateResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +198,19 @@ var doc = `{
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息"
|
"description": ""
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,10 +246,22 @@ var doc = `{
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.DetailResponse"
|
"$ref": "#/definitions/user_model.DetailResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,16 +299,41 @@ var doc = `{
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.UpdateNickNameByIDResponse"
|
"$ref": "#/definitions/user_model.UpdateNickNameByIDResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"code.Failure": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"description": "业务码",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"description": "描述信息",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"demo.authResponse": {
|
"demo.authResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -302,7 +381,7 @@ var doc = `{
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"mobile": {
|
"mobile": {
|
||||||
"description": "手机号",
|
"description": "手机号(脱敏)",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"nick_name": {
|
"nick_name": {
|
||||||
|
|||||||
@@ -26,10 +26,16 @@
|
|||||||
"summary": "获取授权信息",
|
"summary": "获取授权信息",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/demo.authResponse"
|
"$ref": "#/definitions/demo.authResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +64,7 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "用户信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -75,6 +81,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,10 +130,22 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.CreateResponse"
|
"$ref": "#/definitions/user_model.CreateResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +181,19 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息"
|
"description": ""
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,10 +229,22 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.DetailResponse"
|
"$ref": "#/definitions/user_model.DetailResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,16 +282,41 @@
|
|||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "返回信息",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/user_model.UpdateNickNameByIDResponse"
|
"$ref": "#/definitions/user_model.UpdateNickNameByIDResponse"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"code.Failure": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"description": "业务码",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"description": "描述信息",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"demo.authResponse": {
|
"demo.authResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -285,7 +364,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"mobile": {
|
"mobile": {
|
||||||
"description": "手机号",
|
"description": "手机号(脱敏)",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"nick_name": {
|
"nick_name": {
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
definitions:
|
definitions:
|
||||||
|
code.Failure:
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
description: 业务码
|
||||||
|
type: integer
|
||||||
|
message:
|
||||||
|
description: 描述信息
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
demo.authResponse:
|
demo.authResponse:
|
||||||
properties:
|
properties:
|
||||||
authorization:
|
authorization:
|
||||||
@@ -32,7 +41,7 @@ definitions:
|
|||||||
description: 用户主键ID
|
description: 用户主键ID
|
||||||
type: integer
|
type: integer
|
||||||
mobile:
|
mobile:
|
||||||
description: 手机号
|
description: 手机号(脱敏)
|
||||||
type: string
|
type: string
|
||||||
nick_name:
|
nick_name:
|
||||||
description: 昵称
|
description: 昵称
|
||||||
@@ -74,9 +83,13 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回信息
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/demo.authResponse'
|
$ref: '#/definitions/demo.authResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: 获取授权信息
|
summary: 获取授权信息
|
||||||
tags:
|
tags:
|
||||||
- Demo
|
- Demo
|
||||||
@@ -95,7 +108,7 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 用户信息
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
@@ -107,6 +120,14 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: Trace 示例
|
summary: Trace 示例
|
||||||
tags:
|
tags:
|
||||||
- Demo
|
- Demo
|
||||||
@@ -131,9 +152,17 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回信息
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/user_model.CreateResponse'
|
$ref: '#/definitions/user_model.CreateResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: 创建用户
|
summary: 创建用户
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
@@ -157,7 +186,15 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回信息
|
description: ""
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: 删除用户 - 更新 is_deleted = 1
|
summary: 删除用户 - 更新 is_deleted = 1
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
@@ -181,9 +218,17 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回信息
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/user_model.DetailResponse'
|
$ref: '#/definitions/user_model.DetailResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: 用户详情
|
summary: 用户详情
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
@@ -208,9 +253,17 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回信息
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/user_model.UpdateNickNameByIDResponse'
|
$ref: '#/definitions/user_model.UpdateNickNameByIDResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
summary: 编辑用户 - 通过用户主键ID更新用户昵称
|
summary: 编辑用户 - 通过用户主键ID更新用户昵称
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
|
|||||||
@@ -1,28 +1,41 @@
|
|||||||
package code
|
package code
|
||||||
|
|
||||||
import (
|
// 错误时返回结构
|
||||||
"net/http"
|
type Failure struct {
|
||||||
|
Code int `json:"code"` // 业务码
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
Message string `json:"message"` // 描述信息
|
||||||
)
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// OK
|
|
||||||
OK = errno.NewError(http.StatusOK, 1, "OK")
|
|
||||||
|
|
||||||
|
const (
|
||||||
// 服务级错误码
|
// 服务级错误码
|
||||||
ErrServer = errno.NewError(http.StatusInternalServerError, 10101, http.StatusText(http.StatusInternalServerError))
|
ServerError = 10101
|
||||||
ErrManyRequest = errno.NewError(http.StatusTooManyRequests, 10102, http.StatusText(http.StatusTooManyRequests))
|
TooManyRequests = 10102
|
||||||
ErrParamBind = errno.NewError(http.StatusBadRequest, 10103, "参数信息有误")
|
ParamBindError = 10103
|
||||||
ErrAuthorization = errno.NewError(http.StatusUnauthorized, 10104, "签名信息有误")
|
AuthorizationError = 10104
|
||||||
|
CallHTTPError = 10105
|
||||||
|
|
||||||
// 模块级错误码 - 用户模块
|
// 模块级错误码 - 用户模块
|
||||||
ErrUser = errno.NewError(http.StatusBadRequest, 20101, "非法用户")
|
IllegalUserName = 20101
|
||||||
ErrUserName = errno.NewError(http.StatusBadRequest, 20102, "账号不能为空")
|
UserCreateError = 20102
|
||||||
ErrUserCreate = errno.NewError(http.StatusBadRequest, 20103, "创建用户失败")
|
UserUpdateError = 20103
|
||||||
ErrUserUpdate = errno.NewError(http.StatusBadRequest, 20104, "更新用户失败")
|
UserSearchError = 20104
|
||||||
ErrUserSearch = errno.NewError(http.StatusBadRequest, 20105, "查询用户失败")
|
|
||||||
ErrUserHTTP = errno.NewError(http.StatusBadRequest, 20106, "调用他方接口失败")
|
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var codeText = map[int]string{
|
||||||
|
ServerError: "Internal Server Error",
|
||||||
|
TooManyRequests: "Too Many Requests",
|
||||||
|
ParamBindError: "参数信息有误",
|
||||||
|
AuthorizationError: "签名信息有误",
|
||||||
|
CallHTTPError: "调用第三方 HTTP 接口失败",
|
||||||
|
|
||||||
|
IllegalUserName: "非法用户名",
|
||||||
|
UserCreateError: "创建用户失败",
|
||||||
|
UserUpdateError: "更新用户失败",
|
||||||
|
UserSearchError: "查询用户失败",
|
||||||
|
}
|
||||||
|
|
||||||
|
func Text(code int) string {
|
||||||
|
return codeText[code]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package demo
|
package demo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xinliangnote/go-gin-api/configs"
|
"github.com/xinliangnote/go-gin-api/configs"
|
||||||
@@ -11,6 +12,7 @@ import (
|
|||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
|
||||||
|
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/p"
|
"github.com/xinliangnote/go-gin-api/pkg/p"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||||
@@ -49,19 +51,27 @@ func (d *Demo) Get() core.HandlerFunc {
|
|||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(request)
|
req := new(request)
|
||||||
if err := c.ShouldBindURI(req); err != nil {
|
if err := c.ShouldBindURI(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Name != "Tom" {
|
if req.Name != "Tom" {
|
||||||
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Tom")))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.IllegalUserName,
|
||||||
|
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Tom")),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Payload(code.OK.WithData(&response{
|
c.Payload(&response{
|
||||||
Name: "Tom",
|
Name: "Tom",
|
||||||
Job: "Student",
|
Job: "Student",
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,19 +88,27 @@ func (d *Demo) Post() core.HandlerFunc {
|
|||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(request)
|
req := new(request)
|
||||||
if err := c.ShouldBindPostForm(req); err != nil {
|
if err := c.ShouldBindPostForm(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Name != "Jack" {
|
if req.Name != "Jack" {
|
||||||
c.AbortWithError(code.ErrUser.WithErr(errors.New("req.Name != Jack")))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.IllegalUserName,
|
||||||
|
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Jack")),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Payload(code.OK.WithData(&response{
|
c.Payload(&response{
|
||||||
Name: "Jack",
|
Name: "Jack",
|
||||||
Job: "Teacher",
|
Job: "Teacher",
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,14 +128,19 @@ type traceResponse []struct {
|
|||||||
// @Tags Demo
|
// @Tags Demo
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} authResponse "返回信息"
|
// @Success 200 {object} authResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
// @Router /auth/get [post]
|
// @Router /auth/get [post]
|
||||||
func (d *Demo) Auth() core.HandlerFunc {
|
func (d *Demo) Auth() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
cfg := configs.Get().JWT
|
cfg := configs.Get().JWT
|
||||||
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(code.ErrAuthorization.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.AuthorizationError,
|
||||||
|
code.Text(code.AuthorizationError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +148,7 @@ func (d *Demo) Auth() core.HandlerFunc {
|
|||||||
res.Authorization = tokenString
|
res.Authorization = tokenString
|
||||||
res.ExpireTime = time.Now().Add(time.Hour * cfg.ExpireDuration).Unix()
|
res.ExpireTime = time.Now().Add(time.Hour * cfg.ExpireDuration).Unix()
|
||||||
|
|
||||||
c.Payload(code.OK.WithData(res))
|
c.Payload(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +159,9 @@ func (d *Demo) Auth() core.HandlerFunc {
|
|||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param Authorization header string true "签名"
|
// @Param Authorization header string true "签名"
|
||||||
// @Success 200 {object} traceResponse "用户信息"
|
// @Success 200 {object} traceResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Failure 401 {object} code.Failure
|
||||||
// @Router /demo/trace [get]
|
// @Router /demo/trace [get]
|
||||||
func (d *Demo) Trace() core.HandlerFunc {
|
func (d *Demo) Trace() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
@@ -151,12 +176,16 @@ func (d *Demo) Trace() core.HandlerFunc {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error("get [demo/get] err", zap.Error(err))
|
d.logger.Error("get [demo/get] err", zap.Error(err))
|
||||||
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.CallHTTPError,
|
||||||
|
code.Text(code.CallHTTPError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试信息
|
// 调试信息
|
||||||
p.Println("res1.Data.Name", res1.Data.Name, p.WithTrace(c.Trace()))
|
p.Println("res1.Name", res1.Name, p.WithTrace(c.Trace()))
|
||||||
|
|
||||||
// 三方请求信息
|
// 三方请求信息
|
||||||
res2, err := go_gin_api_repo.DemoPost("Jack",
|
res2, err := go_gin_api_repo.DemoPost("Jack",
|
||||||
@@ -169,13 +198,17 @@ func (d *Demo) Trace() core.HandlerFunc {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.logger.Error("post [demo/post] err", zap.Error(err))
|
d.logger.Error("post [demo/post] err", zap.Error(err))
|
||||||
c.AbortWithError(code.ErrUserHTTP.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.CallHTTPError,
|
||||||
|
code.Text(code.CallHTTPError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试信息
|
// 调试信息
|
||||||
p.Println("res2.Data.Name",
|
p.Println("res2.Name",
|
||||||
res2.Data.Name,
|
res2.Name,
|
||||||
p.WithTrace(c.Trace()),
|
p.WithTrace(c.Trace()),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -193,14 +226,14 @@ func (d *Demo) Trace() core.HandlerFunc {
|
|||||||
|
|
||||||
data := &traceResponse{
|
data := &traceResponse{
|
||||||
{
|
{
|
||||||
Name: res1.Data.Name,
|
Name: res1.Name,
|
||||||
Job: res1.Data.Job,
|
Job: res1.Job,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: res2.Data.Name,
|
Name: res2.Name,
|
||||||
Job: res2.Data.Job,
|
Job: res2.Job,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c.Payload(code.OK.WithData(data))
|
c.Payload(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package user_handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
|
"github.com/xinliangnote/go-gin-api/internal/api/model/user_model"
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/ddm"
|
"github.com/xinliangnote/go-gin-api/pkg/ddm"
|
||||||
|
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
@@ -57,30 +59,45 @@ func (u *userDemo) i() {}
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param RequestInfo body user_model.CreateRequest true "请求信息"
|
// @Param RequestInfo body user_model.CreateRequest true "请求信息"
|
||||||
// @Param Authorization header string true "签名"
|
// @Param Authorization header string true "签名"
|
||||||
// @Success 200 {object} user_model.CreateResponse "返回信息"
|
// @Success 200 {object} user_model.CreateResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Failure 401 {object} code.Failure
|
||||||
// @Router /user/create [post]
|
// @Router /user/create [post]
|
||||||
func (u *userDemo) Create() core.HandlerFunc {
|
func (u *userDemo) Create() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(user_model.CreateRequest)
|
req := new(user_model.CreateRequest)
|
||||||
res := new(user_model.CreateResponse)
|
res := new(user_model.CreateResponse)
|
||||||
if err := c.ShouldBindJSON(req); err != nil {
|
if err := c.ShouldBindJSON(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.UserName == "" {
|
if req.UserName == "" {
|
||||||
c.AbortWithError(code.ErrUserName.WithErr(errors.New("req.UserName = ''")))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.IllegalUserName,
|
||||||
|
code.Text(code.IllegalUserName)).WithErr(errors.New("req.UserName = ''")),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := u.userService.Create(c, req)
|
id, err := u.userService.Create(c, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(code.ErrUserCreate.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UserCreateError,
|
||||||
|
code.Text(code.UserCreateError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Id = id
|
res.Id = id
|
||||||
c.Payload(code.OK.WithData(res))
|
c.Payload(res)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,25 +109,36 @@ func (u *userDemo) Create() core.HandlerFunc {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param RequestInfo body user_model.UpdateNickNameByIDRequest true "请求信息"
|
// @Param RequestInfo body user_model.UpdateNickNameByIDRequest true "请求信息"
|
||||||
// @Param Authorization header string true "签名"
|
// @Param Authorization header string true "签名"
|
||||||
// @Success 200 {object} user_model.UpdateNickNameByIDResponse "返回信息"
|
// @Success 200 {object} user_model.UpdateNickNameByIDResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Failure 401 {object} code.Failure
|
||||||
// @Router /user/update [put]
|
// @Router /user/update [put]
|
||||||
func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
|
func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(user_model.UpdateNickNameByIDRequest)
|
req := new(user_model.UpdateNickNameByIDRequest)
|
||||||
res := new(user_model.UpdateNickNameByIDResponse)
|
res := new(user_model.UpdateNickNameByIDResponse)
|
||||||
if err := c.ShouldBindJSON(req); err != nil {
|
if err := c.ShouldBindJSON(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := u.userService.UpdateNickNameByID(c, req.Id, req.NickName)
|
err := u.userService.UpdateNickNameByID(c, req.Id, req.NickName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UserUpdateError,
|
||||||
|
code.Text(code.UserUpdateError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Id = req.Id
|
res.Id = req.Id
|
||||||
c.Payload(code.OK.WithData(res))
|
|
||||||
|
c.Payload(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,23 +150,33 @@ func (u *userDemo) UpdateNickNameByID() core.HandlerFunc {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "用户ID"
|
// @Param id path int true "用户ID"
|
||||||
// @Param Authorization header string true "签名"
|
// @Param Authorization header string true "签名"
|
||||||
// @Success 200 "返回信息"
|
// @Success 200
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Failure 401 {object} code.Failure
|
||||||
// @Router /user/delete/{id} [patch]
|
// @Router /user/delete/{id} [patch]
|
||||||
func (u *userDemo) Delete() core.HandlerFunc {
|
func (u *userDemo) Delete() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(user_model.DeleteRequest)
|
req := new(user_model.DeleteRequest)
|
||||||
if err := c.ShouldBindURI(req); err != nil {
|
if err := c.ShouldBindURI(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := u.userService.Delete(c, req.Id)
|
err := u.userService.Delete(c, req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(code.ErrUserUpdate.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UserUpdateError,
|
||||||
|
code.Text(code.UserUpdateError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Payload(code.OK.WithData(nil))
|
c.Payload("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,20 +188,30 @@ func (u *userDemo) Delete() core.HandlerFunc {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param username path string true "用户名"
|
// @Param username path string true "用户名"
|
||||||
// @Param Authorization header string true "签名"
|
// @Param Authorization header string true "签名"
|
||||||
// @Success 200 {object} user_model.DetailResponse "返回信息"
|
// @Success 200 {object} user_model.DetailResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Failure 401 {object} code.Failure
|
||||||
// @Router /user/info/{username} [get]
|
// @Router /user/info/{username} [get]
|
||||||
func (u *userDemo) Detail() core.HandlerFunc {
|
func (u *userDemo) Detail() core.HandlerFunc {
|
||||||
return func(c core.Context) {
|
return func(c core.Context) {
|
||||||
req := new(user_model.DetailRequest)
|
req := new(user_model.DetailRequest)
|
||||||
res := new(user_model.DetailResponse)
|
res := new(user_model.DetailResponse)
|
||||||
if err := c.ShouldBindURI(req); err != nil {
|
if err := c.ShouldBindURI(req); err != nil {
|
||||||
c.AbortWithError(code.ErrParamBind.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.ParamBindError,
|
||||||
|
code.Text(code.ParamBindError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := u.userService.GetUserByUserName(c, req.UserName)
|
user, err := u.userService.GetUserByUserName(c, req.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(code.ErrUserSearch.WithErr(err))
|
c.AbortWithError(errno.NewError(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UserSearchError,
|
||||||
|
code.Text(code.UserSearchError)).WithErr(err),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +219,7 @@ func (u *userDemo) Detail() core.HandlerFunc {
|
|||||||
res.UserName = user.UserName
|
res.UserName = user.UserName
|
||||||
res.NickName = user.NickName
|
res.NickName = user.NickName
|
||||||
res.Mobile = ddm.Mobile(user.Mobile)
|
res.Mobile = ddm.Mobile(user.Mobile)
|
||||||
c.Payload(code.OK.WithData(res))
|
|
||||||
|
c.Payload(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package go_gin_api_repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||||
@@ -11,23 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type demoGetResponse struct {
|
type demoGetResponse struct {
|
||||||
Code int `json:"code"`
|
Name string `json:"name"`
|
||||||
Msg string `json:"msg"`
|
Job string `json:"job"`
|
||||||
Data struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Job string `json:"job"`
|
|
||||||
} `json:"data"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type demoPostResponse struct {
|
type demoPostResponse struct {
|
||||||
Code int `json:"code"`
|
Name string `json:"name"`
|
||||||
Msg string `json:"msg"`
|
Job string `json:"job"`
|
||||||
Data struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Job string `json:"job"`
|
|
||||||
} `json:"data"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err error) {
|
func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err error) {
|
||||||
@@ -43,10 +32,6 @@ func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err
|
|||||||
return nil, errors.Wrap(err, "DemoGet json unmarshal error")
|
return nil, errors.Wrap(err, "DemoGet json unmarshal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Code != 1 {
|
|
||||||
return nil, errors.New(fmt.Sprintf("code err: %d-%s", res.Code, res.Msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,17 +40,7 @@ func DemoGetRetryVerify(body []byte) (shouldRetry bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
return false
|
||||||
Code int `json:"code"`
|
|
||||||
}
|
|
||||||
resp := new(Response)
|
|
||||||
if err := json.Unmarshal(body, resp); err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 例如 无需重试的 code 码,code !=1 需要重试
|
|
||||||
successCode := 1
|
|
||||||
return resp.Code != successCode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, err error) {
|
func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, err error) {
|
||||||
@@ -83,10 +58,6 @@ func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, er
|
|||||||
return nil, errors.Wrap(err, "DemoPost json unmarshal error")
|
return nil, errors.Wrap(err, "DemoPost json unmarshal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Code != 1 {
|
|
||||||
return nil, errors.New(fmt.Sprintf("code err: %d-%s", res.Code, res.Msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,15 +66,5 @@ func DemoPostRetryVerify(body []byte) (shouldRetry bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
return false
|
||||||
Code int `json:"code"`
|
|
||||||
}
|
|
||||||
resp := new(Response)
|
|
||||||
if err := json.Unmarshal(body, resp); err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 例如 无需重试的 code 码,code !=1 需要重试
|
|
||||||
successCode := 1
|
|
||||||
return resp.Code != successCode
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import "encoding/json"
|
|||||||
|
|
||||||
func MockDemoGet() (body []byte) {
|
func MockDemoGet() (body []byte) {
|
||||||
res := new(demoGetResponse)
|
res := new(demoGetResponse)
|
||||||
res.Code = 1
|
res.Name = "AA"
|
||||||
res.Msg = "ok"
|
res.Job = "AA_JOB"
|
||||||
res.Data.Name = "AA"
|
|
||||||
res.Data.Job = "AA_JOB"
|
|
||||||
|
|
||||||
body, _ = json.Marshal(res)
|
body, _ = json.Marshal(res)
|
||||||
return body
|
return body
|
||||||
@@ -15,10 +13,8 @@ func MockDemoGet() (body []byte) {
|
|||||||
|
|
||||||
func MockDemoPost() (body []byte) {
|
func MockDemoPost() (body []byte) {
|
||||||
res := new(demoPostResponse)
|
res := new(demoPostResponse)
|
||||||
res.Code = 1
|
res.Name = "BB"
|
||||||
res.Msg = "ok"
|
res.Job = "BB_JOB"
|
||||||
res.Data.Name = "BB"
|
|
||||||
res.Data.Job = "BB_JOB"
|
|
||||||
|
|
||||||
body, _ = json.Marshal(res)
|
body, _ = json.Marshal(res)
|
||||||
return body
|
return body
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var authorization = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEwLCJVc2VyTmFtZSI6IjEyMyIsImV4cCI6MTYxMDcxODA3NCwiaWF0IjoxNjEwNjMxNjc0LCJpc3MiOiJnby1naW4tYXBpIiwibmJmIjoxNjEwNjMxNjc0fQ.S3T4MaIaz3XjkbJ-xkMDkwzuZ_jfZ8ZRf4cPMz0oXBE"
|
var authorization = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEsIlVzZXJOYW1lIjoieGlubGlhbmdub3RlIiwiZXhwIjoxNjEzODI3MTEzLCJpYXQiOjE2MTM3NDA3MTMsIm5iZiI6MTYxMzc0MDcxM30.SnooP1ikO33ryGPdohsmOKqISa-bWzMkMvUNb5f2zc0"
|
||||||
|
|
||||||
func TestDemoGet(t *testing.T) {
|
func TestDemoGet(t *testing.T) {
|
||||||
res, err := DemoGet("Tom",
|
res, err := DemoGet("Tom",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/xinliangnote/go-gin-api/configs"
|
"github.com/xinliangnote/go-gin-api/configs"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||||
@@ -13,20 +15,32 @@ import (
|
|||||||
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||||
auth := ctx.GetHeader("Authorization")
|
auth := ctx.GetHeader("Authorization")
|
||||||
if auth == "" {
|
if auth == "" {
|
||||||
err = code.ErrAuthorization.WithErr(errors.New("Header 中缺少 Authorization 参数"))
|
err = errno.NewError(
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
code.AuthorizationError,
|
||||||
|
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Authorization 参数"))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := configs.Get().JWT
|
cfg := configs.Get().JWT
|
||||||
claims, errParse := token.New(cfg.Secret).Parse(auth)
|
claims, errParse := token.New(cfg.Secret).Parse(auth)
|
||||||
if errParse != nil {
|
if errParse != nil {
|
||||||
err = code.ErrAuthorization.WithErr(errParse)
|
err = errno.NewError(
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
code.AuthorizationError,
|
||||||
|
code.Text(code.AuthorizationError)).WithErr(errParse)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userId = claims.UserID
|
userId = claims.UserID
|
||||||
if userId <= 0 {
|
if userId <= 0 {
|
||||||
err = code.ErrAuthorization.WithErr(errors.New("claims.UserID <= 0 "))
|
err = errno.NewError(
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
code.AuthorizationError,
|
||||||
|
code.Text(code.AuthorizationError)).WithErr(errors.New("claims.UserID <= 0 "))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userName = claims.UserName
|
userName = claims.UserName
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ type Context interface {
|
|||||||
setLogger(logger *zap.Logger)
|
setLogger(logger *zap.Logger)
|
||||||
|
|
||||||
// Payload 正确返回
|
// Payload 正确返回
|
||||||
Payload(payload errno.Error)
|
Payload(payload interface{})
|
||||||
getPayload() errno.Error
|
getPayload() interface{}
|
||||||
|
|
||||||
// GraphPayload GraphQL返回值 与 api 返回结构不同
|
// GraphPayload GraphQL返回值 与 api 返回结构不同
|
||||||
GraphPayload(payload interface{})
|
GraphPayload(payload interface{})
|
||||||
@@ -225,14 +225,14 @@ func (c *context) setLogger(logger *zap.Logger) {
|
|||||||
c.ctx.Set(_LoggerName, logger)
|
c.ctx.Set(_LoggerName, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) getPayload() errno.Error {
|
func (c *context) getPayload() interface{} {
|
||||||
if payload, ok := c.ctx.Get(_PayloadName); ok != false {
|
if payload, ok := c.ctx.Get(_PayloadName); ok != false {
|
||||||
return payload.(errno.Error)
|
return payload
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Payload(payload errno.Error) {
|
func (c *context) Payload(payload interface{}) {
|
||||||
c.ctx.Set(_PayloadName, payload)
|
c.ctx.Set(_PayloadName, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -336,7 +336,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
|||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
stackInfo := string(debug.Stack())
|
stackInfo := string(debug.Stack())
|
||||||
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||||
context.AbortWithError(code.ErrServer)
|
context.AbortWithError(errno.NewError(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
code.ServerError,
|
||||||
|
code.Text(code.ServerError)),
|
||||||
|
)
|
||||||
|
|
||||||
if notify := opt.panicNotify; notify != nil {
|
if notify := opt.panicNotify; notify != nil {
|
||||||
notify(context, err, stackInfo)
|
notify(context, err, stackInfo)
|
||||||
@@ -348,7 +352,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
response errno.Error
|
response interface{}
|
||||||
businessCode int
|
businessCode int
|
||||||
businessCodeMsg string
|
businessCodeMsg string
|
||||||
abortErr error
|
abortErr error
|
||||||
@@ -364,23 +368,27 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
|||||||
if err := context.abortError(); err != nil { // customer err
|
if err := context.abortError(); err != nil { // customer err
|
||||||
multierr.AppendInto(&abortErr, err.GetErr())
|
multierr.AppendInto(&abortErr, err.GetErr())
|
||||||
response = err
|
response = err
|
||||||
|
businessCode = err.GetBusinessCode()
|
||||||
|
businessCodeMsg = err.GetMsg()
|
||||||
|
|
||||||
|
reply := &code.Failure{
|
||||||
|
Code: businessCode,
|
||||||
|
Message: businessCodeMsg,
|
||||||
|
}
|
||||||
|
ctx.JSON(err.GetHttpCode(), reply)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
response = context.getPayload()
|
response = context.getPayload()
|
||||||
|
if response != nil {
|
||||||
|
ctx.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if response != nil {
|
if response != nil {
|
||||||
if x := context.Trace(); x != nil {
|
if x := context.Trace(); x != nil {
|
||||||
context.SetHeader(trace.Header, x.ID())
|
context.SetHeader(trace.Header, x.ID())
|
||||||
response.WithID(x.ID())
|
|
||||||
traceId = x.ID()
|
traceId = x.ID()
|
||||||
} else {
|
|
||||||
response.WithID("")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
businessCode = response.GetBusinessCode()
|
|
||||||
businessCodeMsg = response.GetMsg()
|
|
||||||
ctx.JSON(response.GetHttpCode(), response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
graphResponse = context.getGraphPayload()
|
graphResponse = context.getGraphPayload()
|
||||||
@@ -464,7 +472,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
|||||||
defer releaseContext(context)
|
defer releaseContext(context)
|
||||||
|
|
||||||
if !limiter.Allow() {
|
if !limiter.Allow() {
|
||||||
context.AbortWithError(code.ErrManyRequest)
|
context.AbortWithError(errno.NewError(
|
||||||
|
http.StatusTooManyRequests,
|
||||||
|
code.TooManyRequests,
|
||||||
|
code.Text(code.TooManyRequests)),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +501,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
|||||||
Host: ctx.Host(),
|
Host: ctx.Host(),
|
||||||
Status: "ok",
|
Status: "ok",
|
||||||
}
|
}
|
||||||
ctx.Payload(code.OK.WithData(resp))
|
ctx.Payload(resp)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package grpc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||||
|
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/p"
|
"github.com/xinliangnote/go-gin-api/pkg/p"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||||
@@ -53,7 +55,11 @@ func (c *ClientInterceptor) UnaryInterceptor(ctx context.Context, method string,
|
|||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
stackInfo := string(debug.Stack())
|
stackInfo := string(debug.Stack())
|
||||||
coreContext.Logger().Error("UnaryInterceptor got double panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
coreContext.Logger().Error("UnaryInterceptor got double panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||||
coreContext.AbortWithError(code.ErrServer)
|
coreContext.AbortWithError(errno.NewError(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
code.ServerError,
|
||||||
|
code.Text(code.ServerError)),
|
||||||
|
)
|
||||||
notify.OnPanicNotify(coreContext, err, stackInfo)
|
notify.OnPanicNotify(coreContext, err, stackInfo)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -62,7 +68,11 @@ func (c *ClientInterceptor) UnaryInterceptor(ctx context.Context, method string,
|
|||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
stackInfo := string(debug.Stack())
|
stackInfo := string(debug.Stack())
|
||||||
coreContext.Logger().Error("UnaryInterceptor got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
coreContext.Logger().Error("UnaryInterceptor got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||||
coreContext.AbortWithError(code.ErrServer)
|
coreContext.AbortWithError(errno.NewError(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
code.ServerError,
|
||||||
|
code.Text(code.ServerError)),
|
||||||
|
)
|
||||||
notify.OnPanicNotify(coreContext, err, stackInfo)
|
notify.OnPanicNotify(coreContext, err, stackInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
main.go
14
main.go
@@ -117,12 +117,12 @@ func main() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 关闭 gRPC client
|
// 关闭 gRPC client
|
||||||
func() {
|
//func() {
|
||||||
if err := gRPCRepo.Conn().Close(); err != nil {
|
// if err := gRPCRepo.Conn().Close(); err != nil {
|
||||||
loggers.Error("gRPC client close err", zap.Error(err))
|
// loggers.Error("gRPC client close err", zap.Error(err))
|
||||||
} else {
|
// } else {
|
||||||
loggers.Info("gRPC client close success")
|
// loggers.Info("gRPC client close success")
|
||||||
}
|
// }
|
||||||
},
|
//},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ var _ Error = (*err)(nil)
|
|||||||
type Error interface {
|
type Error interface {
|
||||||
// i 为了避免被其他包实现
|
// i 为了避免被其他包实现
|
||||||
i()
|
i()
|
||||||
// WithData 设置成功时返回的数据
|
|
||||||
WithData(data interface{}) Error
|
|
||||||
// WithID 设置当前请求的唯一ID
|
|
||||||
WithID(id string) Error
|
|
||||||
// WithErr 设置错误信息
|
// WithErr 设置错误信息
|
||||||
WithErr(err error) Error
|
WithErr(err error) Error
|
||||||
// GetBusinessCode 获取 Business Code
|
// GetBusinessCode 获取 Business Code
|
||||||
@@ -30,36 +26,22 @@ type Error interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type err struct {
|
type err struct {
|
||||||
HttpCode int `json:"-"` // HTTP Code
|
HttpCode int // HTTP Code
|
||||||
BusinessCode int `json:"code"` // Business Code
|
BusinessCode int // Business Code
|
||||||
Msg string `json:"msg"` // 描述信息
|
Message string // 描述信息
|
||||||
Data interface{} `json:"data"` // 接口数据
|
Err error // 错误信息
|
||||||
Err error `json:"-"` // 错误信息
|
|
||||||
ID string `json:"id,omitempty"` // 当前请求的唯一ID,便于问题定位,忽略也可以
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewError(httpCode, businessCode int, msg string) Error {
|
func NewError(httpCode, businessCode int, msg string) Error {
|
||||||
return &err{
|
return &err{
|
||||||
HttpCode: httpCode,
|
HttpCode: httpCode,
|
||||||
BusinessCode: businessCode,
|
BusinessCode: businessCode,
|
||||||
Msg: msg,
|
Message: msg,
|
||||||
Data: nil,
|
|
||||||
Err: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *err) i() {}
|
func (e *err) i() {}
|
||||||
|
|
||||||
func (e *err) WithData(data interface{}) Error {
|
|
||||||
e.Data = data
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *err) WithID(id string) Error {
|
|
||||||
e.ID = id
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *err) WithErr(err error) Error {
|
func (e *err) WithErr(err error) Error {
|
||||||
e.Err = errors.WithStack(err)
|
e.Err = errors.WithStack(err)
|
||||||
return e
|
return e
|
||||||
@@ -74,7 +56,7 @@ func (e *err) GetBusinessCode() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *err) GetMsg() string {
|
func (e *err) GetMsg() string {
|
||||||
return e.Msg
|
return e.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *err) GetErr() error {
|
func (e *err) GetErr() error {
|
||||||
@@ -84,17 +66,13 @@ func (e *err) GetErr() error {
|
|||||||
// ToString 返回 JSON 格式的错误详情
|
// ToString 返回 JSON 格式的错误详情
|
||||||
func (e *err) ToString() string {
|
func (e *err) ToString() string {
|
||||||
err := &struct {
|
err := &struct {
|
||||||
HttpCode int `json:"http_code"`
|
HttpCode int `json:"http_code"`
|
||||||
BusinessCode int `json:"business_code"`
|
BusinessCode int `json:"business_code"`
|
||||||
Msg string `json:"msg"`
|
Message string `json:"message"`
|
||||||
Data interface{} `json:"data"`
|
|
||||||
ID string `json:"id,omitempty"`
|
|
||||||
}{
|
}{
|
||||||
HttpCode: e.HttpCode,
|
HttpCode: e.HttpCode,
|
||||||
BusinessCode: e.BusinessCode,
|
BusinessCode: e.BusinessCode,
|
||||||
Msg: e.Msg,
|
Message: e.Message,
|
||||||
Data: e.Data,
|
|
||||||
ID: e.ID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raw, _ := json.Marshal(err)
|
raw, _ := json.Marshal(err)
|
||||||
|
|||||||
46
pkg/httpclient/error.go
Normal file
46
pkg/httpclient/error.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package httpclient
|
||||||
|
|
||||||
|
var _ ReplyErr = (*replyErr)(nil)
|
||||||
|
|
||||||
|
// ReplyErr 错误响应,当 resp.StatusCode != http.StatusOK 时用来包装返回的 httpcode 和 body 。
|
||||||
|
type ReplyErr interface {
|
||||||
|
error
|
||||||
|
StatusCode() int
|
||||||
|
Body() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type replyErr struct {
|
||||||
|
err error
|
||||||
|
statusCode int
|
||||||
|
body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *replyErr) Error() string {
|
||||||
|
return r.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *replyErr) StatusCode() int {
|
||||||
|
return r.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *replyErr) Body() []byte {
|
||||||
|
return r.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func newReplyErr(statusCode int, body []byte, err error) ReplyErr {
|
||||||
|
return &replyErr{
|
||||||
|
statusCode: statusCode,
|
||||||
|
body: body,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToReplyErr 尝试将 err 转换为 ReplyErr
|
||||||
|
func ToReplyErr(err error) (ReplyErr, bool) {
|
||||||
|
if err == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
e, ok := err.(ReplyErr)
|
||||||
|
return e, ok
|
||||||
|
}
|
||||||
@@ -105,7 +105,11 @@ func doHTTP(ctx context.Context, method, url string, payload []byte, opt *option
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return body, resp.StatusCode, errors.Errorf("do [%s %s] return code: %d message: %s", method, url, resp.StatusCode, string(body))
|
return nil, resp.StatusCode, newReplyErr(
|
||||||
|
resp.StatusCode,
|
||||||
|
body,
|
||||||
|
errors.Errorf("do [%s %s] return code: %d message: %s", method, url, resp.StatusCode, string(body)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return body, http.StatusOK, nil
|
return body, http.StatusOK, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user