跳到主要内容

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: "latest",    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 去请求你自己的服务器,自行使用密码来鉴权,所以千万不要泄露,以防安全风险。

在 API 编辑时选择需要token后会继续要求选择权限类型,下面是四种 API 权限的解释:

无需权限#

该类型 API 的 token 没有额外功能,token 仅用于验证合法用户和携带数据。

示例如下:

// 请求头:const headers = {  authorization: 'Bearer token',};// 将其验签const tokenData = jwt.verify(headers.authorization, '环境密匙密码');// tokenData 如下所示// {//   userId: 'xxx',//   expired: xxx// }

简单权限#

该类型 API 的 token 中包含 rights 字段,API 设置的权限组和 token 中的权限组要有其中一个对应才可通过。

示例如下:

// 请求头:const headers = {  authorization: 'Bearer token',};// 将其验签const tokenData = jwt.verify(headers.authorization, '环境密匙密码');// tokenData 如下所示// {//   userId: 'xxx',//   rights: ['a','b']// }const apiRights = ['b', 'c'];// 有一个b 对应,所以通过

管理员权限#

在 BaaS 应用中,有一些 API 是面向管理员的,也就是不会被客户端用户调用,比如一些业务数据的,敏感操作的功能。

这些 API 的权限类型是管理员权限,普通的 HTTP 请求不会通过。此时就要构建管理员 Token 了。

在用户系统中,当用户登录时我们会用 jwt 步骤签名用户的 userId,然后在该应用或其他应用中用环境密匙的密码去验证。能够从 headers 的 token 中得出 userId。

而管理员权限则是,在 token 中加入参数identity,其值为admin 。这样就可以通过管理员权限的 API 了。

示例如下:

// 请求头:const headers = {  authorization: 'Bearer token',  ...}// 将其验签const tokenData = jwt.verify(headers.authorization, '环境密匙密码')// tokenData 如下所示// {//   userId: 'xxx',//   identity: 'admin',//   ...// }

用户系统#

rights

该类型建立在应用:用户系统 之上。在用户系统中有一张表为UserRight,它可以通过三个值:userId、appId、目标 permission 来确定一个 rights 组。

此处 API 的权限组类似于简单权限中的权限组,但比较值不再是 token 中的数据,而是用户系统的用户权限表中的 rights 数据。

比如,用户张三的 UserRight 中的记录为:

{  "ids": {    "userId": "zhangsan",    "appId": "org",    "object": "orgId:one"  },  "columns": {    "rights": ["admin", "other"]  }}

加入此时的 API 权限设置中,目标参数来源为 API,权限目标 target 为 orgId,权限组为["admin"]

那么当前端请求该 API 时,会从 API 的 args 参数中拿到 orgId 的值,从 token 中拿到 userId 的值,从 body 中拿到 appId 的值,去查询该条数据的 rights,这时候正好两者有其中一个值对应,该请求通过。

其他类型#

后续我们会上架 RBAC 等各种权限应用,并加入到 API 权限选择中,如果你有其他权限应用希望使用,也可以联系我们加入内置权限类型中。

请求内容 body#

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

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

app

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

version是该 API 的版本号,文档中有标识,如下图的版本。你可以在文档中选择不同版本查看,不同版本要求的 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": "latest",  "args": {    "posts": {      "getColumns": ["title"]    }  }}

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

  • skip: 查询翻页,跳过的条数,int 类型
  • getTotalCount: 是否返回总行数,boolean 类型
  • sorters: 查询排序,数组类型,数组项为对象,有下列字段
    • sorterType 排序类型:
      • 值为column代表是以某个列排序,由columnName决定;
      • 值为ids代表主键排序;
      • 值为union代表相关性排序,使用了 BM25 算法计算相关性;
      • 值为distance代表距离排序,计算列由columnName决定,距离点由points决定;
    • columnName 排序列名
    • orderType 值为asc正序或desc倒序,四种类型都需要该值,默认为倒序从大到小
    • points 为排序距离点,格式为["0,0"]
  • nextToken: 查询翻页,下一页的 token
  • minMatch: 匹配查询最少匹配
  • operator: 匹配查询匹配逻辑
  • rangeFrom: 范围查询 From
  • rangeTo: 范围查询 To
  • factor: 得分查询数值字段
  • searchKey: 嵌套查询的 Key
  • searchValue: 嵌套查询的 Value
  • topLeft: 地理盒子查询的范围
  • bottomRight: 地理盒子查询的范围
  • centerPoint: 地理距离查询的中心点
  • distance: 地理距离查询的距离
  • points: 地理多边形查询的点数组

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

返回内容#

返回内容都是 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版本/args字符串即可将请求以转发至该应用的 API。

Webhook 地址接受GET, POST两种方式,当请求为 POST 时,请求 body 中的 args 参数可以替代上面的 url 地址相关参数,即和正常 API 请求一样。

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

多语言示例#

如果你想在原有的后端服务中调用清林云 BaaS API,那么也可以查看下方的多语言示例集成进其他语言的服务中。

HTTP#

POST / HTTP/1.1Content-Type: application/jsonEnvid: yorhcDIFv2VLKyKE5YRa-Keyid: frDo9pCfewCfBQ93otisAAuthorization: Bearer tokenHost: cn-east-1.baasapi.comContent-Length: 88
{    "appId": "hello",    "api": "hi",    "version": "latest",    "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":"latest","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": "latest",\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: 'latest',  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: 'latest',    args: { apiParam: 'any' },  },};
axios  .request(options)  .then(function (response) {    console.log(response.data);  })  .catch(function (error) {    console.error(error);  });

Dart#

import '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': 'latest',      'args': '{\n\t"appId": "hello",\n\t"api": "hi",\n\t"version": "latest",\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\": \"latest\",\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\": \"latest\",\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\": \"latest\",\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\": \"latest\",\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\": \"latest\",\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": @"latest",                              @"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 Foundation
let headers = [  "Content-Type": "application/json",  "envid": "yorhcDIFv2VLKyKE5YRa-",  "keyid": "frDo9pCfewCfBQ93otisA"]let parameters = [  "appId": "hello",  "api": "hi",  "version": "latest",  "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 Data
let 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 main
import (    "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\": \"latest\",\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", "latest");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: 'latest',    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\": \"latest\",\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": "latest",    "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.client
conn = http.client.HTTPSConnection("cn-east-1.baasapi.com")
payload = "{\n\t\"appId\": \"hello\",\n\t\"api\": \"hi\",\n\t\"version\": \"latest\",\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 requests
url = "https://cn-east-1.baasapi.com/"
payload = {    "appId": "hello",    "api": "hi",    "version": "latest",    "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\": \"latest\",\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 "latest"                                                                   :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\": \"latest\",\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 Lwt
let 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\": \"latest\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}" in
Client.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": "latest",    "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\": \"latest\",\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_NONE
request = 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\": \"latest\",\n\t\"args\": {\n\t\t\"apiParam\": \"any\"\n\t}\n}"
response = http.request(request)puts response.read_body

Shell#

curl --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": "latest",    "args": {        "apiParam": "any"    }}'