使用逻辑编排解决阿里云费用账单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结构的方式,希望能够帮助到您。

相关文章
|
2月前
|
云安全 人工智能 安全
Dify平台集成阿里云AI安全护栏,构建AI Runtime安全防线
阿里云 AI 安全护栏加入Dify平台,打造可信赖的 AI
|
4月前
|
弹性计算 运维 安全
云迁移最佳实践:HyperMotion助中小企业高效上云,阿里云工具集深度集成三方迁移工具
中小企业上云需求强烈,但面临缺乏了解、无合适方案及成本过高等挑战。为解决这些问题,推出“云迁移HyperMotion阿里云集成版”,提供三步上云、自助迁移、自动适配等能力,助力企业高效、低成本完成迁移。
134 0
|
5月前
|
安全 API 数据安全/隐私保护
低代码革命:API无代码集成如何让企业“3天上线一个生态”?
在数字化转型浪潮中,API成为释放数据价值、提升企业效率的核心。本文详解API架构设计、安全实践与跨平台集成,为CTO提供效率提升指南,涵盖微服务、安全认证、协议选择、低代码集成及未来趋势,助力企业构建敏捷、安全、高效的数字生态。
|
5月前
|
JSON API 开发工具
京东 VS 淘宝 API:接口设计、认证机制、数据结构全方位差异化
本文对比京东与淘宝开放平台API设计、认证机制及数据结构差异,涵盖接口规范、安全策略与数据格式,为开发者提供接入参考。
|
5月前
|
消息中间件 安全 数据可视化
降本增效新引擎:API集成如何让电商订单履约快人一步?
本文详解电商系统如何通过API与支付、物流、CRM三大第三方服务高效集成,涵盖技术实现、应用场景与商业价值,助力企业构建数字化竞争力。
|
5月前
|
监控 前端开发 安全
如何集成第三方支付API到电商网站
在电商网站中,集成第三方支付API是确保交易安全、提升用户体验的关键步骤。本文详细介绍了从选择支付提供商到上线监控的全流程,涵盖代码示例与实用建议,助您高效实现支付功能。
280 0
|
5月前
|
监控 测试技术 API
电商API常见错误排查指南:避免集成陷阱
API集成是电商开发的核心,但常因认证、数据、限流等问题引发错误,影响项目进度与用户体验。本文详解常见错误类型、排查步骤与预防策略,结合Python示例指导开发者高效应对。通过日志分析、数据校验、速率监控等手段,帮助您系统化规避集成陷阱,提升开发效率与系统稳定性。
214 0
|
5月前
|
缓存 监控 安全
电商API集成入门:从零开始搭建高效接口
在数字化电商时代,API集成成为企业提升效率、实现系统互联的关键。本文从零开始,逐步讲解如何搭建高效、可靠的电商API接口,适合初学者学习。内容涵盖API基础、认证安全、请求处理、性能优化等核心步骤,并提供Python代码示例与数学公式辅助理解。通过实践,读者可掌握构建优质电商API的技巧,提升用户体验与系统性能。
238 0
|
8月前
|
架构师 安全 物联网
Apipost vs Apifox:高效API协作的差异化功能解析
作为企业级API架构师,深度体验APIPost与Apifox后发现几大亮点功能。目录级参数配置避免全局污染;WebSocket消息分组提升长连接管理效率;Socket.IO支持解决特定协议需求;接口锁定保障团队协作安全。大型团队适合APIPost的细粒度管控,复杂物联网项目需WebSocket分组,维护遗留系统离不开Socket.IO支持,初创团队可按需灵活选择。这些特性显著优化开发协作质量。
|
3月前
|
人工智能 算法 搜索推荐
拼多多:通过用户分组API实施差异化营销策略,提高客单价
拼多多通过用户分组API实现差异化营销,精准提升客单价。基于用户行为数据自动分类,针对不同群体推送专属优惠,如高频用户推高端商品、新用户送礼包、低频用户唤醒激励。结合满减、捆绑销售等策略,有效提高单笔订单金额。该策略提升营销效率,增强用户粘性,助力平台实现数据驱动的可持续增长。
214 0