mirror of
https://github.com/larksuite/cli.git
synced 2026-07-04 14:38:53 +08:00
129 lines
3.3 KiB
Go
129 lines
3.3 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package base
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/larksuite/cli/internal/output"
|
|
"github.com/larksuite/cli/internal/util"
|
|
)
|
|
|
|
func handleBaseAPIResult(result interface{}, err error, action string) (map[string]interface{}, error) {
|
|
data, err := handleBaseAPIResultAny(result, err, action)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dataMap, _ := data.(map[string]interface{})
|
|
return dataMap, nil
|
|
}
|
|
|
|
// handleBaseAPIResultAny normalizes the Base v3 {code,msg,data} envelope used
|
|
// by shortcut APIs. Success returns data as-is; API failures become the CLI's
|
|
// structured ErrAPI, with server-provided message/hint promoted to the top level.
|
|
func handleBaseAPIResultAny(result interface{}, err error, action string) (interface{}, error) {
|
|
if err != nil {
|
|
return nil, output.Errorf(output.ExitAPI, "api_error", "%s: %s", action, err)
|
|
}
|
|
|
|
resultMap, _ := result.(map[string]interface{})
|
|
code, _ := util.ToFloat64(resultMap["code"])
|
|
if code == 0 {
|
|
return resultMap["data"], nil
|
|
}
|
|
|
|
larkCode := int(code)
|
|
msg := extractDataErrorMessage(resultMap)
|
|
if strings.TrimSpace(msg) == "" {
|
|
msg, _ = resultMap["msg"].(string)
|
|
}
|
|
|
|
detail := extractErrorDetail(resultMap)
|
|
apiErr := output.ErrAPI(larkCode, msg, detail)
|
|
hint := extractErrorHint(resultMap)
|
|
if apiErr.Detail != nil && apiErr.Detail.Hint == "" && hint != "" {
|
|
apiErr.Detail.Hint = hint
|
|
}
|
|
if apiErr.Detail != nil {
|
|
apiErr.Detail.Detail = cleanEmptyBaseErrorDetail(detail)
|
|
}
|
|
return nil, apiErr
|
|
}
|
|
|
|
func cleanEmptyBaseErrorDetail(detail interface{}) interface{} {
|
|
detailMap, ok := detail.(map[string]interface{})
|
|
if !ok {
|
|
return nil
|
|
}
|
|
for key, value := range detailMap {
|
|
if value == nil {
|
|
delete(detailMap, key)
|
|
}
|
|
}
|
|
if len(detailMap) == 0 {
|
|
return nil
|
|
}
|
|
return detailMap
|
|
}
|
|
|
|
func extractErrorDetail(resultMap map[string]interface{}) interface{} {
|
|
if detail, ok := nonNilMapValue(resultMap, "error"); ok {
|
|
return detail
|
|
}
|
|
data, _ := resultMap["data"].(map[string]interface{})
|
|
if detail, ok := nonNilMapValue(data, "error"); ok {
|
|
return detail
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func nonNilMapValue(src map[string]interface{}, key string) (interface{}, bool) {
|
|
if src == nil {
|
|
return nil, false
|
|
}
|
|
value, ok := src[key]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
switch value.(type) {
|
|
case nil:
|
|
return nil, false
|
|
default:
|
|
return value, true
|
|
}
|
|
}
|
|
|
|
func extractErrorHint(resultMap map[string]interface{}) string {
|
|
if detail, ok := resultMap["error"].(map[string]interface{}); ok {
|
|
if hint := consumeStringField(detail, "hint"); hint != "" {
|
|
return hint
|
|
}
|
|
}
|
|
data, _ := resultMap["data"].(map[string]interface{})
|
|
if detail, ok := data["error"].(map[string]interface{}); ok {
|
|
if hint := consumeStringField(detail, "hint"); hint != "" {
|
|
return hint
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func extractDataErrorMessage(resultMap map[string]interface{}) string {
|
|
data, _ := resultMap["data"].(map[string]interface{})
|
|
if detail, ok := data["error"].(map[string]interface{}); ok {
|
|
if message := consumeStringField(detail, "message"); message != "" {
|
|
return message
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func consumeStringField(src map[string]interface{}, key string) string {
|
|
value, _ := src[key].(string)
|
|
if _, exists := src[key]; exists {
|
|
delete(src, key)
|
|
}
|
|
return strings.TrimSpace(value)
|
|
}
|