X

清林云BaaS的API格式

清林云 BaaS (Backend as a Service) 有固定的 API 格式,我们称为 TypeAPI

基本结构

API 的基本 HTTP 结构如下:

API 示例

以浏览器的 fetch 请求为例:

fetch("https://环境地域.baasapi.com/", {  "headers": {    "content-type": "application/json",    "envid": "你的环境ID",    "keyid": "你的环境密匙ID",    "Authorization": "(可选)如果API需要token则携带用户token"  },  "method": "POST",  "body": JSON.stringify({    appId: "qinglin-simple-blog",    api: "getManyPost",    version: "v1",    args: {}  })}).then(res=>res.json()).then(data=>console.log(data)).catch(e=>console.log(e))

这是清林云的 API 约束,我们称之为 TypeAPI 风格,在很多场景下描述能力优于 RESTful 风格,开发者更容易理解。

请求地址 url

https://[环境地域].baasapi.com/

其中[环境地域] 为你使用环境的地域代码,例如:https://cn-east-1.baasapi.com/

地域代码可在控制台概览页面的环境上方看到。

以下为所有地域代码:

  • 中国东部:cn-east-1
  • 中国北部:cn-north-1
  • 中国南部:cn-south-1
  • 中国西部:cn-west-1
  • 中国香港:cn-hk-1
  • 美国西部:us-west-1
  • 美国东部:us-east-1
  • 英国:uk-1
  • 新加坡:sg-1
  • 澳大利亚:au-1
  • 印度:in-1

另外专有云和私有云地域代码根据客户定制。

请求方法 method

统一为POST

清林云 API 设计吸收借鉴GraphQL模式,不用每次封装请求库不同方法,使用更为人类友好的声明式 API,代码更易阅读。

请求头 headers{  "headers": {    "Content-Type": "application/json",    "envid": "你的环境ID",    "keyid": "你的环境密匙Id",    "Authorization": "Bearer 用户jwtToken"  }}

请求内容类型统一为 application/json

携带你的环境 ID 和密匙 ID。

注意此处Authorization,代表用户 jwt token。当请求不需要 token 的 API 时,此处可忽略,当请求需要用户登录后才能访问的 API 时,则要携带,是否需要 token 在应用的 API 文档中会注明。

示例:"Authorization": "Bearer eyJhbGVCJ9.eyJMzEwMjF9.mXM2b6yg"(此处为删减 token,实际 token 要更长一些)

token 来自于拥有登录步骤的应用或自定义的 jwt 步骤加密。加密方式为userId或你自定义的字段与环境密匙的密码加密签名。也就是说,你的环境密匙密码可以用来鉴权用户 token,也就是说你同样可以用使用清林云应用颁发给用户的 token 去请求你自己的服务器,自行使用密码来鉴权,所以千万不要泄露,以防安全风险。

请求内容 body{  "appId": "qinglin-simple-blog",  "api": "createPost",  "version": "v1",  "args": {    "title": "第一篇文章",    "content": "这是第一篇文章的内容"  }}

appId为你要请求的应用 ID,在应用详情可以看到,如下图所示:

api为你要请求的应用 API,上图的getManyPost和右侧的列表都是。

version是该 API 的版本号,文档中有标识,如下图的版本。你可以在文档中选择不同版本查看,不同版本要求的 API 参数可能不一样。

版本设计是为了避免应用开发者在更新 API 功能时造成老版本用户和线上用户请求错误,所以当开发者为 API 添加新功能时,如果原有的请求参数不能实现新功能,则要创建新版本再更新功能。

这样正在使用该 API 的客户依然根据版本请求旧 API,收到版本更新通知后更新前端业务代码能够正常使用新版本后再进行版本切换。

args为请求该 API 的参数。如上图所示,如需请求createPost这个 API 则要求请求中携带三个参数,参数args中的字段,用途有参数名称说明,数据类型为参数字段格式,要求必须的则要将相关数据加入args才可请求。

args中有一些特殊字段在步骤 ID 项的 Object 中:

  • getColumns: 查询需要的列

比如,getManyPost这个 API 中的一个步骤 ID 为posts,并且该 API 中的查询文章步骤的返回数据列选项包含由请求控制项,那么我们希望该步骤返回的数据列只包含title,则可以如下请求:

{  "appId": "qinglin-simple-blog",  "api": "getManyPost",  "version": "v1",  "args": {    "posts": {      "getColumns": ["title"]    }  }}

以下是 S 系列引擎专属字段,同样在步骤 ID 的对象内:

  • skip: 查询翻页,跳过的条数
  • getTotalCount: 是否返回总行数
  • sorters: 查询排序
  • nextToken: 查询翻页,下一页的 token
  • minMatch: 匹配查询最少匹配
  • operator: 匹配查询匹配逻辑
  • rangeFrom: 范围查询 From
  • rangeTo: 范围查询 To
  • factor: 得分查询数值字段
  • searchKey: 嵌套查询的 Key
  • searchValue: 嵌套查询的 Value
  • topLeft: GEO 盒子查询的范围
  • bottomRight: GEO 盒子查询的范围
  • centerPoint: GEO 距离查询的中心点
  • distance: GEO 距离查询的距离
  • points: GEO 多边形查询的点数组

当需要特殊参数时,应用开发者一般会在文档中说明。

返回内容

返回内容都是 JSON 格式,分别有成功和失败两种状态:

成功

以下为各步骤类型的返回示例:

{  // 云数据库步骤类型分别有 getMany get create update delete +parallel  // 各类型后加 Data 如 getData 为演示,实际为 步骤ID。  // id 为数据id,field 为数据字段  "getManyData": {    // 范围查询的步骤返回包括data和nextId,data为数组即多条数据    "data": [      {        "id": "xxx",        "field": "xxx"      }    ],    "nextId": {      // 当范围查询步骤数据条数超出limit限制时则会有nextId,用于分页查询      "postId": 1622474714667000 // 下一条数据的id    }  },  "getData": {    "id": "xxx",    "field": "xxx"  },  "createData": {    "id": "xxx"  },  "updateData": {    "id": "xxx"  },  "deleteData": {    "success": true  },  "parallelData": [    //还有一个特殊情况,并行执行云数据库指令,会返回数组    {      "parallerItem": {        "id": "xxx",        "field": "xxx"      }    },    {      "parallerItem": {        "id": "xxx",        "field": "xxx"      }    }  ],  // 条件判断  "步骤ID": true, // or false  // JS脚本  "步骤ID": "脚本返回数据", //格式取决于你的脚本  // 其他API  "步骤ID": {}, // 其他API 的返回格式  // HTTP 请求  "步骤ID": {}, // HTTP请求的返回数据  // Json 选择  "步骤ID": "value", // 选择的Json 项  // 自定义函数  "步骤ID": "函数返回数据", //格式取决于你的函数  // 获取配置  "步骤ID": "value", // 配置数据  // 简单计算  "步骤ID": "value", // 计算结果  // Json转换  "步骤ID": "value", // 转换结果  // 数组操作  "步骤ID": "value", // 操作结果  // JWT  "步骤ID": "jwt token" // jwt 签名token}失败

失败返回遵循最新的通用 HTTP 异常返回标准草案,但是更改了状态码 400 为 200,加入了errCode项进行判断,因为在某些请求客户端下,400 状态会导致一些程序异常。

{  "errCode": "错误码", // 通常为 1,第三方服务则是第三方错误码,验证请求是否出错一般判断是否有errCode即可,如 if(res.errCode){错误处理} else {正常处理}  "type": "错误的API",  "title": "错误原因",  "detail": "详细数据",  "instance": "请求ID和客户端数据"}

其中,detail是如下字段的 Json 字符串:

{  "args": "参数",  "appId": "应用ID",  "api": "应用API",  "envId": "环境ID",  "version": "API版本"}

instance是如下字段的 Json 字符串:

{  "requestId": "请求ID", // 如果出现莫名错误,向客服提交该项用于追踪bug  "clientIP": "请求端IP地址", // 请求端IP地址  "referer": "请求来源", // 请求来源  "userAgent": "请求客户端", // 请求客户端  "date": "时间戳" // 时间戳}自定义


另外,还有一个步骤类型为 自定义返回数据,可以自定义返回数据的格式,用于第三方特定的服务或其他个性化需求,详情请查看步骤章节。

安全措施

主要有三种方式保护你的环境信息被盗用。

第一种是:大部分应用 API 都是需要 token 的,位于请求headers中的Authorization。token 来自于一些提供登录功能的应用以及 jwt 步骤,它们将用户字段和环境密匙的密码签名,前端在登录后将 token 保存在用户端本地,每次请求携带即可保障用户数据的安全,清林云 BaaS 将会对需要 token 的 API 收到请求时进行鉴权。

Authorization的格式为:Bearer token

第二种是:检查headers中的origin字段,虽然这在请求工具中可以设置,但是在用户浏览器中无法被篡改。当你上线产品前,请前往环境设置中,填写 URL 白名单,将你的域名 origin 加入。这样只有来自该域名的请求才会被处理。

如果headers中没有携带origin则会检查referer

在添加 URL 白名单时需要注意,当白名单中有*时,来源于所有地址的请求都会被接受,包括localhost。而其他的 URL 必须是 origin 格式,例如:https://www.baasapi.com ,包含协议https,没有末位的/符号。httphttps不兼容,如果你的网站两种协议都有,则要分别添加两个 URL。

前两种方法的结合可以拒绝大部分恶意攻击。

第三种是:利用非对称加密请求内容,在环境密匙中配置加密证书私钥和加密方式,清林云在接受到请求后会用私钥解密该证书公钥加密的内容,这样可以有效保护请求安全,适用于对安全性较高的产品。

该方法暂时还未全量开放,如您有需求可以联系客服。

另外清林云 BaaS 也会提供默认的安全措施如防火墙、防 DDoS、请求流控、同 IP 限制、恶意攻击识别等。

清林云和政府相关部门也有一定合作,对于恶意网络攻击行为也会进行追踪和报警处理。如果您的环境资源被攻击,请及时联系客服,我们将会配合您和相关部门进行处理。

Webhook

有一些第三方业务需要发送 webhook 信息到你的服务器,那么作为 BaaS,我们也为你解决了这方面的问题。

在第三方设置回调地址为:https://环境地域.baasapi.com/webhook/环境ID/密匙ID/应用ID/应用API/API版本/即可将请求以转发至该应用的 API。

转发给该 API 的参数为 headers path data 对应调用该 webhook 地址的 headers path body

具体示例可以查看电商系统中的订单部分和支付部分。

多语言示例HTTPPOST / HTTP/1.1Content-Type: application/jsonEnvid: yorhcDIFv2VLKyKE5YRa-Keyid: frDo9pCfewCfBQ93otisAAuthorization: Bearer tokenHost: cn-east-1.baasapi.comContent-Length: 88{ "appId": "hello", "api": "hi", "version": "v1", "args": {  "apiParam": "any" }}JavaScript

fetch:

fetch('https://cn-east-1.baasapi.com/', {  method: 'POST',  headers: {    'Content-Type': 'application/json',    envid: 'yorhcDIFv2VLKyKE5YRa-',    keyid: 'frDo9pCfewCfBQ93otisA',  },  body: '{"appId":"hello","api":"hi","version":"v1","args":{"apiParam":"any"}}',})  .then((response) => {    console.log(response);  })  .catch((err) => {    console.error(err);  });

jQuery:

const settings = {  async: true,  crossDomain: true,  url: 'https://cn-east-1.baasapi.com/',  method: 'POST',  headers: {    'Content-Type': 'application/json',    envid: 'yorhcDIFv2VLKyKE5YRa-',    keyid: 'frDo9pCfewCfBQ93otisA',  },  processData: false,  data: '{\n\t"appId": "hello",\n\t"api": "hi",\n\t"version": "v1",\n\t"args": {\n\t\t"apiParam": "any"\n\t}\n}',};$.ajax(settings).done(function (response) {  console.log(response);});

xhr:

const data = JSON.stringify({  appId: 'hello',  api: 'hi',  version: 'v1',  args: {    apiParam: 'any',  },});const xhr = new XMLHttpRequest();xhr.withCredentials = true;xhr.addEventListener('readystatechange', function () {  if (this.readyState === this.DONE) {    console.log(this.responseText);  }});xhr.open('POST', 'https://cn-east-1.baasapi.com/');xhr.setRequestHeader('Content-Type', 'application/json');xhr.setRequestHeader('envid', 'yorhcDIFv2VLKyKE5YRa-');xhr.setRequestHeader('keyid', 'frDo9pCfewCfBQ93otisA');xhr.send(data);

axios:

import axios from 'axios';const options = {  method: 'POST',  url: 'https://cn-east-1.baasapi.com/',  headers: {    'Content-Type': 'application/json',    envid: 'yorhcDIFv2VLKyKE5YRa-',    keyid: 'frDo9pCfewCfBQ93otisA',  },  data: {    appId: 'hello',    api: 'hi',    version: 'v1',    args: { apiParam: 'any' },  },};axios  .request(options)  .then(function (response) {    console.log(response.data);  })  .catch(function (error) {    console.error(error);  });Dartimport 'package:http/http.dart' as http;Future<http.Response> createData() {  return http.post(    Uri.parse('https://cn-east-1.baasapi.com/'),    headers: <String, String>{      'Content-Type': 'application/json',      'envid': 'yorhcDIFv2VLKyKE5YRa',      'keyid': 'frDo9pCfewCfBQ93otisA',    },    body: jsonEncode(<String, String>{      'appId': 'hello',      'api': 'hi',      'version': 'v1',      'args': '{\n\t"appId": "hello",\n\t"api": "hi",\n\t"version": "v1",\n\t"args": {\n\t\t"apiParam": "any"\n\t}\n}',    }),  );}Java

OkHttp:

OkHttpClient client = new OkHttpClient();MediaType mediaType = MediaType.parse("application/json");RequestBody body = RequestBody.create(mediaType, "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}");Request request = new Request.Builder()  .url("https://cn-east-1.baasapi.com/")  .post(body)  .addHeader("Content-Type", "application/json")  .addHeader("envid", "yorhcDIFv2VLKyKE5YRa-")  .addHeader("keyid", "frDo9pCfewCfBQ93otisA")  .build();Response response = client.newCall(request).execute();

Unirest:

HttpResponse<String> response = Unirest.post("https://cn-east-1.baasapi.com/")  .header("Content-Type", "application/json")  .header("envid", "yorhcDIFv2VLKyKE5YRa-")  .header("keyid", "frDo9pCfewCfBQ93otisA")  .body("{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}")  .asString();

AsyncHttp:

AsyncHttpClient client = new DefaultAsyncHttpClient();client.prepare("POST", "https://cn-east-1.baasapi.com/")  .setHeader("Content-Type", "application/json")  .setHeader("envid", "yorhcDIFv2VLKyKE5YRa-")  .setHeader("keyid", "frDo9pCfewCfBQ93otisA")  .setBody("{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}")  .execute()  .toCompletableFuture()  .thenAccept(System.out::println)  .join();client.close();

java.net.http:

HttpRequest request = HttpRequest.newBuilder()    .uri(URI.create("https://cn-east-1.baasapi.com/"))    .header("Content-Type", "application/json")    .header("envid", "yorhcDIFv2VLKyKE5YRa-")    .header("keyid", "frDo9pCfewCfBQ93otisA")    .method("POST", HttpRequest.BodyPublishers.ofString("{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}"))    .build();HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());Kotlin

OkHttp:

val client = OkHttpClient()val mediaType = MediaType.parse("application/json")val body = RequestBody.create(mediaType, "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}")val request = Request.Builder()  .url("https://cn-east-1.baasapi.com/")  .post(body)  .addHeader("Content-Type", "application/json")  .addHeader("envid", "yorhcDIFv2VLKyKE5YRa-")  .addHeader("keyid", "frDo9pCfewCfBQ93otisA")  .build()val response = client.newCall(request).execute()Objective-C

NSURLSession:

#import <Foundation/Foundation.h>NSDictionary *headers = @{ @"Content-Type": @"application/json", @"envid": @"yorhcDIFv2VLKyKE5YRa-", @"keyid": @"frDo9pCfewCfBQ93otisA" };NSDictionary *parameters = @{ @"appId": @"hello", @"api": @"hi", @"version": @"v1", @"args": @{ @"apiParam": @"any" } };NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://cn-east-1.baasapi.com/"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];[request setHTTPMethod:@"POST"];[request setAllHTTPHeaderFields:headers];[request setHTTPBody:postData];NSURLSession *session = [NSURLSession sharedSession];NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { NSLog(@"%@", error); } else { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; NSLog(@"%@", httpResponse); } }];[dataTask resume];Swift

NSURLSession:

import Foundationlet headers = [  "Content-Type": "application/json",  "envid": "yorhcDIFv2VLKyKE5YRa-",  "keyid": "frDo9pCfewCfBQ93otisA"]let parameters = [  "appId": "hello",  "api": "hi",  "version": "v1",  "args": ["apiParam": "any"]] as [String : Any]let postData = JSONSerialization.data(withJSONObject: parameters, options: [])let request = NSMutableURLRequest(url: NSURL(string: "https://cn-east-1.baasapi.com/")! as URL,                                        cachePolicy: .useProtocolCachePolicy,                                    timeoutInterval: 10.0)request.httpMethod = "POST"request.allHTTPHeaderFields = headersrequest.httpBody = postData as Datalet session = URLSession.sharedlet dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in  if (error != nil) {    print(error)  } else {    let httpResponse = response as? HTTPURLResponse    print(httpResponse)  }})dataTask.resume()Go

NewRequest

package mainimport ( "fmt" "strings" "net/http" "io/ioutil")func main() { url := "https://cn-east-1.baasapi.com/" payload := strings.NewReader("{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Content-Type", "application/json") req.Header.Add("envid", "yorhcDIFv2VLKyKE5YRa-") req.Header.Add("keyid", "frDo9pCfewCfBQ93otisA") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body))}Rust

reqwest:

let mut headers = HeaderMap::new();headers.insert("envid", "yorhcDIFv2VLKyKE5YRa".parse().unwrap());headers.insert("keyid", "frDo9pCfewCfBQ93otisA".parse().unwrap());let mut map = HashMap::new();map.insert("appId", "hello");map.insert("api", "hi");map.insert("version", "v1");map.insert("args", "{}");let client = reqwest::Client::new();let res = client.post("https://cn-east-1.baasapi.com/").headers($headers)    .json(&map)    .send()    .await?;Nodejs

request:

const request = require('request');const options = {  method: 'POST',  url: 'https://cn-east-1.baasapi.com/',  headers: {    'Content-Type': 'application/json',    envid: 'yorhcDIFv2VLKyKE5YRa-',    keyid: 'frDo9pCfewCfBQ93otisA',  },  body: { appId: 'hello', api: 'hi', version: 'v1', args: { apiParam: 'any' } },  json: true,};request(options, function (error, response, body) {  if (error) throw new Error(error);  console.log(body);});PHP

cURL:

<?php$curl = curl_init();curl_setopt_array($curl, [  CURLOPT_URL => "https://cn-east-1.baasapi.com/",  CURLOPT_RETURNTRANSFER => true,  CURLOPT_ENCODING => "",  CURLOPT_MAXREDIRS => 10,  CURLOPT_TIMEOUT => 30,  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,  CURLOPT_CUSTOMREQUEST => "POST",  CURLOPT_POSTFIELDS => "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}",  CURLOPT_HTTPHEADER => [    "Content-Type: application/json",    "envid: yorhcDIFv2VLKyKE5YRa-",    "keyid: frDo9pCfewCfBQ93otisA"  ],]);$response = curl_exec($curl);$err = curl_error($curl);curl_close($curl);if ($err) {  echo "cURL Error #:" . $err;} else {  echo $response;}

HTTP v2:

<?php$client = new http\Client;$request = new http\Client\Request;$body = new http\Message\Body;$body->append('{ "appId": "hello", "api": "hi", "version": "v1", "args": {  "apiParam": "any" }}');$request->setRequestUrl('https://cn-east-1.baasapi.com/');$request->setRequestMethod('POST');$request->setBody($body);$request->setHeaders([  'Content-Type' => 'application/json',  'envid' => 'yorhcDIFv2VLKyKE5YRa-',  'keyid' => 'frDo9pCfewCfBQ93otisA']);$client->enqueue($request)->send();$response = $client->getResponse();echo $response->getBody();Python

http.client:

import http.clientconn = http.client.HTTPSConnection("cn-east-1.baasapi.com")payload = "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}"headers = {    'Content-Type': "application/json",    'envid': "yorhcDIFv2VLKyKE5YRa-",    'keyid': "frDo9pCfewCfBQ93otisA"    }conn.request("POST", "/", payload, headers)res = conn.getresponse()data = res.read()print(data.decode("utf-8"))

Requests:

import requestsurl = "https://cn-east-1.baasapi.com/"payload = {    "appId": "hello",    "api": "hi",    "version": "v1",    "args": {"apiParam": "any"}}headers = {    "Content-Type": "application/json",    "envid": "yorhcDIFv2VLKyKE5YRa-",    "keyid": "frDo9pCfewCfBQ93otisA"}response = requests.request("POST", url, json=payload, headers=headers)print(response.text)C

Libcurl:

CURL *hnd = curl_easy_init();curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(hnd, CURLOPT_URL, "https://cn-east-1.baasapi.com/");struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Content-Type: application/json");headers = curl_slist_append(headers, "envid: yorhcDIFv2VLKyKE5YRa-");headers = curl_slist_append(headers, "keyid: frDo9pCfewCfBQ93otisA");curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}");CURLcode ret = curl_easy_perform(hnd);Clojure

clj-http:

(require '[clj-http.client :as client])(client/post "https://cn-east-1.baasapi.com/" {:headers {:envid "yorhcDIFv2VLKyKE5YRa-"                                                               :keyid "frDo9pCfewCfBQ93otisA"}                                                     :content-type :json                                                     :form-params {:appId "hello"                                                                   :api "hi"                                                                   :version "v1"                                                                   :args {:apiParam "any"}}})C#

HttpClient:

var client = new HttpClient();var request = new HttpRequestMessage{    Method = HttpMethod.Post,    RequestUri = new Uri("https://cn-east-1.baasapi.com/"),    Headers =    {        { "envid", "yorhcDIFv2VLKyKE5YRa-" },        { "keyid", "frDo9pCfewCfBQ93otisA" },    },    Content = new StringContent("{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}")    {        Headers =        {            ContentType = new MediaTypeHeaderValue("application/json")        }    }};using (var response = await client.SendAsync(request)){    response.EnsureSuccessStatusCode();    var body = await response.Content.ReadAsStringAsync();    Console.WriteLine(body);}Ocaml

CoHTTP:

open Cohttp_lwt_unixopen Cohttpopen Lwtlet uri = Uri.of_string "https://cn-east-1.baasapi.com/" inlet headers = Header.add_list (Header.init ()) [ ("Content-Type", "application/json"); ("envid", "yorhcDIFv2VLKyKE5YRa-"); ("keyid", "frDo9pCfewCfBQ93otisA");] inlet body = Cohttp_lwt_body.of_string "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}" inClient.call ~headers ~body `POST uri>>= fun (res, body_stream) -> (* Do stuff with the result *)Powershell

Invoke-WebRequest:

$headers=@{}$headers.Add("Content-Type", "application/json")$headers.Add("envid", "yorhcDIFv2VLKyKE5YRa-")$headers.Add("keyid", "frDo9pCfewCfBQ93otisA")$response = Invoke-WebRequest -Uri 'https://cn-east-1.baasapi.com/' -Method POST -Headers $headers -ContentType 'application/json' -Body '{ "appId": "hello", "api": "hi", "version": "v1", "args": { "apiParam": "any" }}'R

httr:

library(httr)url <- "https://cn-east-1.baasapi.com/"payload <- "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}"encode <- "json"response <- VERB("POST", url, body = payload, add_headers(envid = 'yorhcDIFv2VLKyKE5YRa-', keyid = 'frDo9pCfewCfBQ93otisA', '), content_type("application/json"), encode = encode)content(response, "text")Ruby

net::http

require 'uri'require 'net/http'require 'openssl'url = URI("https://cn-east-1.baasapi.com/")http = Net::HTTP.new(url.host, url.port)http.use_ssl = truehttp.verify_mode = OpenSSL::SSL::VERIFY_NONErequest = Net::HTTP::Post.new(url)request["Content-Type"] = 'application/json'request["envid"] = 'yorhcDIFv2VLKyKE5YRa-'request["keyid"] = 'frDo9pCfewCfBQ93otisA'request.body = "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"v1\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}"response = http.request(request)puts response.read_bodyShellcurl --request POST \  --url https://cn-east-1.baasapi.com/ \  --header 'Content-Type: application/json' \  --header 'envid: yorhcDIFv2VLKyKE5YRa-' \  --header 'keyid: frDo9pCfewCfBQ93otisA' \  --data '{ "appId": "hello", "api": "hi", "version": "v1", "args": {  "apiParam": "any" }}'