使用逻辑编排解决阿里云费用账单API集成数据结构差异的问题

简介: 利用流程编排在集成过程中定制阿里云账单API的结构

集成阿里云的费用账单,是公司运维小伙伴经常要承担的工作。阿里云也开放了按照多个维维度查询费用账单的API供企业客户使用,集成到云管平台,财务系统等等。不过在实际工作中,常常会发现需要集成的云供应商不止一家,每一家提供的API格式都不一样。如果想要接入已经开发好的系统,数据结构不一致就需要做额外的数据Mapping工作,费时费力。小编在阿里云上发现了一款神器,可对阿里云提供的API做快速的定制,输出想要的格式,这就是阿里云的逻辑编排。

什么是逻辑编排?

举个实际的例子,阿里云账单的API QueryInstanceBill可返回按照实例维度或者计费项维度的账单,返回的格式是这样的:
"Data": {

"Items": {
  "Item": [
    {
                "SubscriptionType": "PayAsYouGo",
                "ProductCode": "cdn",
                "RecordID": "2019080352963162",
                "BillingItem": "InlandNetworkOut",
                "ProductDetail": "cdn",
                "DeductedByPrepaidCard": 0,
                "PretaxAmount": 0,
                "DeductedByCoupons": 0,
                "RoundDownDiscount": 0,
                "UsageStartTime": "2019-08-08 12:00:00",
                "UsageEndTime": "2019-08-08 13:00:00",
                "Status": "NoSettle",
                "PaymentTime": "",
                "PaymentAmount": 0,
                "Item": "PayAsYouGoBill",
                "OutstandingAmount": 0,
                "ProductType": "",
                "DeductedByCashCoupons": 0,
                "OwnerID": "",
                "ProductName": "cdn",
                "Currency": "CNY",
                "PretaxGrossAmount": 0,
                "InvoiceDiscount": 0
            }
            ]

},

如果在集成的过程中,仅希望InlandNetworkOut这一个计费项的用量和金额汇总,输出一个特定Json格式的结果,可以按照下面的步骤操作。

第一步 权限设置

逻辑编排过程中需要调用QueryInstanceBill接口,因此需要相关的权限。可以使用AliyunBSSFullAccess权限,但为了保证最小可用原则,创建一个新的权限策略AliyunBSSBillReadOnly,使用以下的Statement
{
"Version": "1",
"Statement": [

   {
       "Action": ["bss:Query*", "bss:Describe*"],
       "Resource": "*",
       "Effect": "Allow"
   }

]
}
1579513892267_a3ab1069_ff7f_44e0_b839_8b0389f87636
同时创建一个拥有此权限Ram角色,并添加以下的信任策略:

  1. 创建RAM Role,选择Alibaba Cloud Service类型
  2. 添加刚刚创建的策略AliyunBSSBillReadOnly
  3. 修改信任策略,让逻辑编排可以访问
    {

    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "composer.aliyuncs.com"
                ]
            }
        }
    ],
    "Version": "1"

    }

1579514503818_9c76a9d5_1f66_448a_b251_07f0ea338919

第二步 编排流程
登录国际站并访问逻辑编排控制台https://lc.console.aliyun.com/,在左侧的菜单选择“我的工作流”,然后创建一个新的流程,输入名称和描述。创建完成后,转到“代码设计”,然后复制本文给出的一个段脚本。
{

"actions": {
    "查询_InstanceBill_第一页数据": {
        "type": "ACS::BSS::QueryInstanceBill",
        "inputs": {
            "method": "POST",
            "host": {
                "product": "BSS",
                "api": "QueryInstanceBill",
                "apiVersion": "2017-12-14"
            },
            "connection": {},
            "queries": {
                "RegionId": "ap-southeast-1",
                "BillingCycle": "@get(triggerOutputs(), 'queries.BillingCycle')",
                "ProductCode": "cdn",
                "PageNum": 1,
                "PageSize": 300,
                "IsBillingItem": true
            }
        },
        "runAfter": {
            "初始化变量存放所有记录": [
                "Succeeded"
            ]
        }
    },
    "初始化变量存放所有记录": {
        "type": "InitializeVariable",
        "inputs": {
            "name": "records",
            "type": "Array",
            "value": []
        },
        "runAfter": {}
    },
    "存入第一页数据": {
        "type": "AppendToArrayVariable",
        "inputs": {
            "name": "records",
            "value": "@body('查询_InstanceBill_第一页数据')['Data']['Items']['Item']"
        },
        "runAfter": {
            "查询_InstanceBill_第一页数据": [
                "Succeeded"
            ]
        }
    },
    "遍历剩余页数": {
        "type": "Until",
        "inputs": {},
        "runAfter": {
            "初始化变量存放当前页数": [
                "Succeeded"
            ]
        },
        "actions": {
            "查询某一页_InstanceBill_数据": {
                "type": "ACS::BSS::QueryInstanceBill",
                "inputs": {
                    "method": "POST",
                    "host": {
                        "product": "BSS",
                        "api": "QueryInstanceBill",
                        "apiVersion": "2017-12-14"
                    },
                    "connection": {},
                    "queries": {
                        "BillingCycle": "@get(triggerOutputs(), 'queries.BillingCycle')",
                        "RegionId": "ap-southeast-1",
                        "ProductCode": "cdn",
                        "PageNum": "@variables('pageNumber')",
                        "PageSize": 300,
                        "IsBillingItem": true
                    }
                },
                "runAfter": {
                    "设置页数": [
                        "Succeeded"
                    ]
                }
            },
            "追加值至数组变量": {
                "type": "AppendToArrayVariable",
                "inputs": {
                    "name": "records",
                    "value": "@body('查询某一页_InstanceBill_数据')['Data']['Items']['Item']"
                },
                "runAfter": {
                    "查询某一页_InstanceBill_数据": [
                        "Succeeded"
                    ]
                }
            },
            "设置页数": {
                "runAfter": {},
                "type": "SetVariable",
                "inputs": {
                    "name": "pageNumber",
                    "value": "@add(variables('pageNumber'), 1)"
                }
            }
        },
        "expression": "@lte(sub(ceil(div(body('查询_InstanceBill_第一页数据').Data.TotalCount, 300)), variables('pageNumber')), 0)"
    },
    "初始化变量存放当前页数": {
        "type": "InitializeVariable",
        "inputs": {
            "name": "pageNumber",
            "type": "Integer",
            "value": 1
        },
        "runAfter": {
            "存入第一页数据": [
                "Succeeded"
            ]
        }
    },
    "计算总数": {
        "type": "JavascriptCode",
        "inputs": {
            "code": "const records = $context.variables('records');\n\nconst allUsage = records.reduce((sum, group) => {\n    if (Array.isArray(group)) {\n        group.forEach((record) => {\n            if (record.BillingItem === 'InlandNetworkOut') {\n                if (record.Usage) {\n                    sum.Usage += parseFloat(record.Usage) || 0;\n                }\n                if (record.PretaxAmount) {\n                    sum.PretaxAmount += parseFloat(record.PretaxAmount) || 0;\n                }\n            }\n            \n        });\n    } else if (group.Usage || group.PretaxAmount) {\n        if (group.BillingItem === 'InlandNetworkOut') {\n            sum.Usage += parseFloat(group.Usage) || 0;\n            sum.PretaxAmount += parseFloat(group.PretaxAmount) || 0;\n        }\n    }\n    \n    return sum;\n}, { Usage: 0, PretaxAmount: 0 });\n\nreturn allUsage;"
        },
        "runAfter": {
            "遍历剩余页数": [
                "Succeeded"
            ]
        }
    },
    "响应": {
        "type": "Response",
        "outputs": {
            "statusCode": 500,
            "body": {                  
                "cost_data": [
                    {                        
                        "usage": "@body('计算总数').Usage",
                        "cost": "@body('计算总数').PretaxAmount"
                    }
                ]
            },
            "headers": {
                "Content-Type": "application/json"
            }
        },
        "runAfter": {
            "计算总数": [
                "Succeeded"
            ]
        }
    }
}

}

返回图形化设置,这时需要对其中调用API的过程进行授权。点击并展开“查询InstanceBill第一页数据”,在下方点击Change Permissions,添加刚刚创建新的RAM Role,注意Authorized Policies是否包括了应该有的权限。再点开“遍历剩余页数”这一步,再展开“查询某一页InstanceBill数据”,进行如上的权限添加步骤。点击右上角的保存按键保存流程。

第三步 调用流程
在流程的第一步中,可以找到服务发起的URL,Copy到浏览器中可进行测试。在上面的例子中,调用时需要添加一个查询账期的参数BillingCycle=YYYY-MM。根据所需,可更改调用方式为POST或者GET。

这就是一个利用流程编改变API结构的方式,希望能够帮助到您。

相关文章
|
1月前
|
架构师 安全 物联网
Apipost vs Apifox:高效API协作的差异化功能解析
作为企业级API架构师,深度体验APIPost与Apifox后发现几大亮点功能。目录级参数配置避免全局污染;WebSocket消息分组提升长连接管理效率;Socket.IO支持解决特定协议需求;接口锁定保障团队协作安全。大型团队适合APIPost的细粒度管控,复杂物联网项目需WebSocket分组,维护遗留系统离不开Socket.IO支持,初创团队可按需灵活选择。这些特性显著优化开发协作质量。
|
24天前
|
人工智能 运维 关系型数据库
云服务API与MCP深度集成,RDS MCP最佳实践
近日,阿里云数据库RDS发布开源RDS MCP Server,将复杂的技术操作转化为自然语言交互,实现"对话即运维"的流畅体验。通过将RDS OpenAPI能力封装为MCP协议工具,用户只需像聊天一样描述需求,即可完成数据库实例创建、性能调优、故障排查等专业操作。本文介绍了RDS MCP(Model Context Protocol)的最佳实践及其应用,0代码,两步即可轻松完成RDS实例选型与创建,快来体验!
云服务API与MCP深度集成,RDS MCP最佳实践
|
4月前
|
人工智能 IDE API
AI驱动的开发者工具:打造沉浸式API集成体验
本文介绍了阿里云在过去十年中为开发者提供的API服务演变。内容分为两大部分:一是从零开始使用API的用户旅程,涵盖API的发现、调试与集成;二是回顾阿里云过去十年为开发者提供的服务及发展历程。文中详细描述了API从最初的手写SDK到自动化生成SDK的变化,以及通过API Explorer、IDE插件和AI助手等工具提升开发者体验的过程。这些工具和服务旨在帮助开发者更高效地使用API,减少配置和调试的复杂性,提供一站式的解决方案。
|
1月前
|
人工智能 API 开发工具
GitHub官方开源MCP服务!GitHub MCP Server:无缝集成GitHub API,实现Git流程完全自动化
GitHub MCP Server是基于Model Context Protocol的服务器工具,提供与GitHub API的无缝集成,支持自动化处理问题、Pull Request和仓库管理等功能。
527 2
GitHub官方开源MCP服务!GitHub MCP Server:无缝集成GitHub API,实现Git流程完全自动化
|
1月前
|
存储 人工智能 API
离线VS强制登录?Apipost与Apifox的API工具理念差异深度解析
在代码开发中,工具是助手还是枷锁?本文通过对比Apipost和Apifox在断网环境下的表现,探讨API工具的选择对开发自由度的影响。Apifox强制登录限制了离线使用,而Apipost支持游客模式与本地存储,尊重开发者数据主权。文章从登录策略、离线能力、协作模式等方面深入分析,揭示工具背后的设计理念与行业趋势,帮助开发者明智选择,掌握数据控制权并提升工作效率。
|
2月前
|
人工智能 自然语言处理 API
如何在 10 分钟内将 DeepSeek API 集成到您的应用程序
在AI时代,DeepSeek API以其先进的模型帮助企业快速集成自然语言处理等功能,无需深厚机器学习背景。通过Apipost工具,开发者可轻松测试、调试API并生成代码,优化工作流。本文介绍从身份验证到错误处理的完整流程,并提供相关资源链接,助您高效实现应用智能化。
|
3月前
|
缓存 运维 监控
Anolis OS深度集成运维利器 阿里云操作系统控制台上线
阿里云在百万服务器运维领域的丰富经验打造。
Anolis OS深度集成运维利器 阿里云操作系统控制台上线
|
3月前
|
人工智能 JSON 自然语言处理
AI 程序员的4个分身 | 代码生成专家+注释精灵+API集成助手+智能调试伙伴
AI 程序员的4个分身 | 代码生成专家+注释精灵+API集成助手+智能调试伙伴
275 35
|
2月前
|
JSON API 开发者
1688 快递费用 API 接口的技术剖析与应用
1688快递费用API接口为企业和开发者提供自动化、高效化的快递费用查询服务,打破人工查询的繁琐局面。通过输入寄件与收件地址、商品重量、体积及选择快递公司等信息,接口精准计算费用并返回结果,支持中通、圆通等主流快递。输出内容包括快递费用、预估时效及附加费说明,助力电商精细化运营。Python示例代码展示了如何使用requests库发起POST请求并解析响应数据,实现费用查询自动化。
137 10
|
2月前
|
安全 持续交付 云计算
课时5:阿里云容器服务:最原生的集成Docker和云服务
阿里云容器服务以服务化形式构建容器基础设施,大幅提升开发效率,简化应用部署流程。通过Docker容器和DevOps工具(如Jenkins),实现自动化部署与迭代,优化企业内部复杂部署问题。该服务支持GPU调度、混合云架构无缝迁移,并与阿里云产品体系无缝集成,提供安全防护、网络负载均衡等多重功能支持。凭借微服务架构,帮助企业突破业务瓶颈,提高资源利用率,轻松应对海量流量。
课时5:阿里云容器服务:最原生的集成Docker和云服务

热门文章

最新文章