- weimob api

This commit is contained in:
gazebo
2019-01-15 15:47:58 +08:00
parent f212fa3046
commit 0d4bd09589
4 changed files with 300 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
package weimobapi
import (
"git.rosy.net.cn/baseapi/utils"
)
func (a *API) QueryGoodsList(pageNum, pageSize int) (retVal []map[string]interface{}, totalCount int, err error) {
result, err := a.AccessAPI("goods/queryGoodsList", map[string]interface{}{
"pageNum": pageNum,
"pageSize": pageSize,
})
if err == nil {
if pageList, ok := result["pageList"].([]interface{}); ok {
retVal = utils.Slice2MapSlice(pageList)
}
totalCount = int(utils.MustInterface2Int64(result["totalCount"]))
return retVal, totalCount, nil
}
return nil, 0, err
}

View File

@@ -0,0 +1,17 @@
package weimobapi
import (
"testing"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
)
func TestQueryGoodsList(t *testing.T) {
result, totalCount, err := api.QueryGoodsList(1, 20)
if err != nil {
t.Fatal(err)
}
baseapi.SugarLogger.Debug(totalCount)
baseapi.SugarLogger.Debug(utils.Format4Output(result, false))
}

View File

@@ -0,0 +1,209 @@
package weimobapi
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
ResponseCodeSuccess = "0"
ResponseCodeExceedCallFrequency = "8000103"
)
const (
prodURL = "https://dopen.weimob.com/api/1_0/ec"
authURL = "https://dopen.weimob.com/fuwu/b"
accessTokenAPI = "oauth2/token"
)
type TokenInfo struct {
TokenType string `json:"token_type"`
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
RefreshTokenExpiresIn int `json:"refresh_token_expires_in"`
Scope string `json:"scope"`
PublicAccountID string `json:"public_account_id"`
BusinessID string `json:"business_id"`
}
type API struct {
token *TokenInfo
appID string
appSecret string
client *http.Client
config *platformapi.APIConfig
locker sync.RWMutex
}
var (
exceedLimitCodes = map[string]int{
ResponseCodeExceedCallFrequency: 1,
}
canRetryCodes = map[string]int{}
)
func New(token *TokenInfo, appID, appSecret string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
token: token,
appID: appID,
appSecret: appSecret,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) SetToken(newToken *TokenInfo) (retVal bool) {
a.locker.Lock()
defer a.locker.Unlock()
a.token = newToken
retVal = true
return retVal
}
func (a *API) GetToken() *TokenInfo {
a.locker.RLock()
defer a.locker.RUnlock()
return a.token
}
func (a *API) MustGetToken() *TokenInfo {
token := a.GetToken()
if token == nil {
panic("token is nil")
}
return token
}
func (a *API) AccessAPI(apiStr string, apiParams map[string]interface{}) (retVal map[string]interface{}, err error) {
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
var request *http.Request
if apiStr == accessTokenAPI {
fullURL := utils.GenerateGetURL(authURL, apiStr, utils.MergeMaps(apiParams, map[string]interface{}{
"client_id": a.appID,
"client_secret": a.appSecret,
}))
request, _ = http.NewRequest(http.MethodPost, fullURL, nil)
} else {
fullURL := utils.GenerateGetURL(prodURL, apiStr, utils.Params2Map("accesstoken", a.MustGetToken().AccessToken))
var body io.Reader
if apiParams != nil {
apiParamsBytes, err := json.Marshal(apiParams)
if err != nil {
panic(fmt.Sprintf("Error when marshal %v, error:%v", apiParams, err))
}
body = bytes.NewReader(apiParamsBytes)
}
request, _ = http.NewRequest(http.MethodPost, fullURL, body)
request.Header.Set("Content-Type", "application/json; charset=utf-8")
request.Header.Set("Content-Encoding", "gzip, deflate")
request.Header.Set("User-Agent", "weimob-golang-api")
// request.Close = true //todo 为了性能考虑还是不要关闭
}
return request
},
a.config,
func(jsonResult1 map[string]interface{}) (errLevel string, err error) {
// baseapi.SugarLogger.Debug(utils.Format4Output(jsonResult1, false))
code := ResponseCodeSuccess
errMsg := ""
if apiStr == accessTokenAPI {
// token相关出错到不了这里因为当取token发生错误时HTTP CODE不是200
if errCode, ok := jsonResult1["error"]; ok {
code = getStringCode(errCode)
errMsg = jsonResult1["error_description"].(string)
}
if code == ResponseCodeSuccess {
retVal = jsonResult1
return platformapi.ErrLevelSuccess, nil
}
} else {
if errMap, ok := jsonResult1["code"].(map[string]interface{}); ok {
code = getStringCode(errMap["errcode"])
errMsg = errMap["errmsg"].(string)
}
if code == ResponseCodeSuccess {
retVal = jsonResult1["data"].(map[string]interface{})
return platformapi.ErrLevelSuccess, nil
}
}
newErr := utils.NewErrorCode(errMsg, code)
if _, ok := exceedLimitCodes[code]; ok {
return platformapi.ErrLevelExceedLimit, newErr
} else if _, ok := canRetryCodes[code]; ok {
return platformapi.ErrLevelRecoverableErr, newErr
} else {
baseapi.SugarLogger.Debugf("weimob AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
return platformapi.ErrLevelCodeIsNotOK, newErr
}
})
return retVal, err
}
func getStringCode(code interface{}) string {
if codeStr, ok := code.(string); ok {
return codeStr
}
return utils.Int64ToStr(utils.Interface2Int64WithDefault(code, 0))
}
// redirectURL只是作为校验要求转入得到此CODE时给的redirectURL不包括参数部分
func (a *API) RefreshTokenByCode(code, redirectURL string) (retVal *TokenInfo, err error) {
result, err := a.AccessAPI(accessTokenAPI, map[string]interface{}{
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirectURL,
})
if err == nil {
retVal = map2TokenInfo(result)
a.SetToken(retVal)
return retVal, nil
}
return nil, err
}
func (a *API) RefreshTokenByRefreshToken() (retVal *TokenInfo, err error) {
curToken := a.GetToken()
if curToken != nil {
result, err := a.AccessAPI(accessTokenAPI, map[string]interface{}{
"grant_type": "refresh_token",
"refresh_token": curToken.RefreshToken,
})
if err == nil {
retVal = map2TokenInfo(result)
a.SetToken(retVal)
return retVal, nil
}
return nil, err
}
return nil, fmt.Errorf("刷新TOKEN要求已经有TOKEN")
}
func map2TokenInfo(mapData map[string]interface{}) *TokenInfo {
return &TokenInfo{
TokenType: utils.Interface2String(mapData["token_type"]),
AccessToken: utils.Interface2String(mapData["access_token"]),
ExpiresIn: int(utils.MustInterface2Int64(mapData["expires_in"])),
RefreshToken: utils.Interface2String(mapData["refresh_token"]),
RefreshTokenExpiresIn: int(utils.MustInterface2Int64(mapData["refresh_token_expires_in"])),
Scope: utils.Interface2String(mapData["scope"]),
PublicAccountID: utils.Interface2String(mapData["public_account_id"]),
BusinessID: utils.Interface2String(mapData["business_id"]),
}
}

View File

@@ -0,0 +1,54 @@
package weimobapi
import (
"testing"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"go.uber.org/zap"
)
var (
api *API
sugarLogger *zap.SugaredLogger
)
func init() {
logger, _ := zap.NewDevelopment()
sugarLogger = logger.Sugar()
baseapi.Init(sugarLogger)
tokenStr := `
{
"token_type": "bearer",
"access_token": "db2f4a02-2097-4636-8c8a-cc5576f402cf",
"expires_in": 7199,
"refresh_token": "7b961b6b-0dc4-43e1-8c38-a9a10e2e130d",
"refresh_token_expires_in": 604799,
"scope": "default",
"public_account_id": "100000386048",
"business_id": "1224609670"
}`
var token *TokenInfo
if err := utils.UnmarshalUseNumber([]byte(tokenStr), &token); err != nil {
panic(err)
}
// prod
api = New(token, "319F5E7FB6784DFCA3684C9333EB7744", "7267AA7F58261F6965599218F5A1D592")
}
func TestRefreshTokenByCode(t *testing.T) {
result, err := api.RefreshTokenByCode("6Stxtw", "http://callback.test.jxc4.com/weimob/coded")
if err != nil {
t.Fatal(err)
}
baseapi.SugarLogger.Debug(utils.Format4Output(result, false))
}
func TestRefreshTokenByRefreshToken(t *testing.T) {
result, err := api.RefreshTokenByRefreshToken()
if err != nil {
t.Fatal(err)
}
baseapi.SugarLogger.Debug(utils.Format4Output(result, false))
}