English
Added in HBuilderX 3.4.0
Twenty years ago, the development of restful interfaces became popular. The server wrote the interface, the client called the interface, and transmitted json.
Now, a new pattern to replace restful is coming.
Cloud objects, the server writes the API, the client calls the API, and no longer develops the interface for transmitting json. Clearer thinking and simpler code.
For example, the server writes a cloud object todo, which has methods such as add, get, remove, and update. The client-side js can directly import the todo cloud object and directly call methods such as add.
The server sample code is as follows:
Create a new cloud function in the uniCloud/cloudfunctions directory in HBuilderX, select the type as cloud object, and name it todo. Open the cloud object entry index.obj.js and add an add method.
// Cloud object name: todo
module.exports = {
add(title, content) {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...other logic
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
Then in the client's js, import the todo object and call its add method
const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
uni.showToast({
title: '创建成功'
})
} catch (e) {
// Compliant with uniCloud response body specification https://uniapp.dcloud.net.cn/uniCloud/cf-functions?id=resformat, this error will be thrown automatically
uni.showModal({
title: '创建失败',
content: e.errMsg,
showCancel: false
})
}
}
You can see that the code of the cloud object is very clear, and the number of lines of code is only 33 lines.
For the same logic, using the traditional interface method requires more code, see below:
// Call cloud function in traditional way - cloud function code
// Cloud function name: todo
// The content of cloud function entry index.js is as follows
'use strict';
exports.main = async (event, context) => {
const {
method,
params
} = event
switch(method) {
case 'add': {
let {
title,
content
} = params
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...omit other logic
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
return {
errCode: 'METHOD_NOT_FOUND',
errMsg: `Method[${method}] not found`
}
};
// traditional way to call cloud function - client code
async function addToDo () {
try {
const res = await uniCloud.callFunction({
name: 'todo',
data: {
method: 'add',
params: {
title: 'title demo',
content: 'content demo'
}
}
})
const {
errCode,
errMsg
} = res.result
if(errCode) {
uni.showModal({
title: '创建失败',
content: errMsg,
showCancel: false
})
return
}
uni.showToast({
title: '创建成功'
})
} catch (e) {
uni.showModal({
title: '创建失败',
content: e.message,
showCancel: false
})
}
}
The above traditional development requires 68 lines of code. Compared with the 33 lines of code for cloud objects, not only the workload is heavy, but the logic is not as clear as cloud objects.
_Note: The above examples are only for the convenience of beginners to understand. In actual development, for simple database operations, using clientDB to directly operate the database at the front end is a simpler solution with less code, and no cloud code needs to be written.
Summarize the benefits of cloud objects:
Cloud objects are actually the encapsulation of cloud functions. Like creating a cloud function, right-click in the uniCloud/cloudfunctions
directory to create a new cloud function, select the cloud object type, and enter the cloud object name to create a cloud object. Here, take the cloud object todo as an example, the created cloud object contains an index.obj. js
.
An empty cloud object with the following contents
// cloudfunctions/todo/index.obj.js
module.exports = {
}
The default cloud object template does not contain any methods, we add an add method for this object as an example.
// cloudfunctions/todo/index.obj.js
module.exports = {
add: function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...other logic, such as manipulating the todo data table to add data
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
At this point, the cloud object todo has an accessible method. Next, let's see how to use the client to call the methods in this cloud object
The client obtains an instance of the cloud object through the uniCloud.importObject
method, and can call the methods in the cloud object through this instance. The usage is as follows
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
Through the code block cco
, you can quickly enter the following code:
const todo = uniCloud.importObject('todo')
In actual business, error capture needs to be considered. There are two calling methods:
const todo = uniCloud.importObject('todo')
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
console.log(res)
} catch (e) {
console.log(e.errCode)
console.log(e.errMsg)
}
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
console.log(res)
}).catch(e => {
console.log(e.errCode)
console.log(e.errMsg)
})
importObject parameter description
interface ImportObjectOptions {
/**
* 是否移除自动展示的ui
*/
customUI?: boolean;
/**
* loading界面配置
*/
loadingOptions?: ImportObjectLoadingOptions;
/**
* 错误提示配置
*/
errorOptions?: ImportObjectErrorOptions;
/**
* 使用安全网络的方法及安全网络类型
*/
secretMethods?: Record<string, keyof typeof SECRET_TYPE>;
/**
* 转化云对象内未捕获的错误或客户端网络错误
*/
parseSystemError?: (params: ParseSystemErrorParams) => Promise<ParsedSystemError> | ParsedSystemError;
}
Cloud objects, as a type of cloud functions, can call all node APIs and uniCloud APIs.
uniCloud has many APIs, see also: uniCloud API List
In addition to the above APIs, the this object of the cloud object has a number of dedicated methods to obtain the context information of the current request.
Unlike the context
when the cloud function is input, the cloud object does not have a context
. It obtains context information through several built-in methods mounted by this object. Please note that developers avoid mounting methods with the same name on this.
From HBuilderX 3.4.9 onwards, this interface can obtain client information returned by
getSystemInfo
of all clients. For a complete list of fields, please refer to: [getSystemInfo](https://uniapp.dcloud.net.cn/api/system/info.html #getsysteminfo)
Interface form
this.getClientInfo()
Example:
module.exports = {
add: function() {
const clientInfo = this.getClientInfo()
// clientInfo = {
// clientIP,
// appId,
// deviceId,
// source,
// }
}
}
return value
The information returned by getClientInfo is based on the client's uni.getSystemInfo, with some additional information added.
In addition to the fields returned by getSystemInfo
, the following information is also included
property name | type | description |
---|---|---|
clientIP | string | client ip |
userAgent | string | Client ua, note that the client getSystemInfoSync in a non-local operating environment will also get the ua parameter and upload it to the cloud object, but the cloud object will get ua from the http request header instead of ua in clientInfo |
source | string | The source of the call, see the return value below. HBuilderX 3.5.1+ |
requestId | string | 请求id。HBuilderX 3.5.1+ |
scene | string | 场景值。客户端uni.getLaunchOptionsSync返回的scene参数,新增于HBuilderX 3.5.1 |
getClientInfo().source, returns the cloud function call source, its value range is:
value | description |
---|---|
client | uni-app client import cloud object call |
function | Called by other cloud functions or cloud objects |
http | After the cloud object is URLized, call HBuilderX 3.5.2+ through http access |
timing | Timing task calls cloud object HBuilderX 3.5.2+ |
server | upload and run the cloud function |
Precautions
app-plus
, and the vue3 is app
. Regardless of whether the client is vue2 or vue3, the platform obtained from the app platform is app
. This point needs special attention when using uni-id. For details, see: uni-id document preferedAppPlatformInterface form
this.getCloudInfo()
Example
module.exports = {
add: function(){
const cloudInfo = this.getCloudInfo()
// cloudInfo = {
// provider,
// spaceId,
// functionName,
// functionType,
// }
}
}
return value
参数名 | 类型 | 必备 | 说明 |
---|---|---|---|
provider | string | 是 | 服务空间供应商,支付宝小程序云为:alipay ,阿里云为:aliyun ,腾讯云为:tencent |
spaceId | string | 是 | 服务空间Id |
useOldSpaceId | boolean | 是 | 当前获取的服务空间id是否为迁移前的服务空间id,新增于HBuilderX 3.6.13 |
functionName | string | 是 | 云对象名称,新增于HBuilderX 3.5.1 |
functionType | string | 是 | 云对象此值固定为cloudobject ,新增于HBuilderX 3.5.1 |
云对象自动管理uni-id
的token。开发者无需手动管理。如果不了解uni-id
,请参考
Interface form
this.getUniIdToken()
Example
module.exports = {
add: function(){
const token = this.getUniIdToken()
if(!token) {
// Invalid login status
}
}
}
The obtained token is an encrypted string. To unlock the token and get the user's uid, role, and permission, you need to import the uni-id-common public module and call the checkToken method. See details
This method is mainly used in interceptor methods such as _before
to judge the information uploaded by the client for processing. For example, when it is found that the client calls method a, a special logic is executed. See Preprocessing below for details.
Interface form
this.getMethodName()
Example
module.exports = {
_before: function() { // _before的用法请看后续章节
const methodName = this.getMethodName() // add
}
}
In the common methods of cloud objects, parameters can be obtained directly. This method is mainly used in interceptor methods such as __before
to judge the information uploaded by the client for processing. See Preprocessing below for details.
Interface form
this.getParams()
Example
module.exports = {
_before: function() { // _before的用法请看后续章节
const params = this.getParams() // ['title demo', 'content demo']
}
}
Interface form
this.getUniCloudRequestId()
Example
module.exports = {
_after: function(error, result) {
if(error) {
const requestId = this.getUniCloudRequestId()
// log(requestId, error) records the log when an error occurs, the log method needs to be implemented by itself
}
}
}
Added in HBuilderX 3.5.2
It can only be used when the cloud object is URLized. For how to use the cloud object URLization, please refer to: Cloud object URLization
Interface form
this.getHttpInfo()
Example
module.exports = {
_before: function() { // _before的用法请看后续章节
const httpInfo = this.getHttpInfo()
}
}
httpInfo is an object in the integrated request format, the structure is as follows
{
path: 'HTTP请求路径,如 /hello',
httpMethod: 'HTTP请求方法,如 GET',
headers: {HTTP请求头},
queryStringParameters: {HTTP请求的Query,键值对形式},
body: 'HTTP请求体',
isBase64Encoded: 'true or false,表示body是否为Base64编码'
}
Notice
/test
as the cloud object url path, when accessing /test/a/b/c
, the path is /a/b/c
Example
Use GET request https://${cloud object Urlized domain name}/${trigger path}/${cloud object method name}?a=1&b=2
, the event
received by the cloud object is
{
path: '/${云对象方法名}',
httpMethod: 'GET',
headers: {HTTP请求头},
queryStringParameters: {a: "1", b: "2"},
isBase64Encoded: false
}
Use POST request https://${cloud object Urlized domain name}/${trigger path}/${cloud object method name}
, the event.body
received by the cloud object is the data sent by the request, ** The default content-type of uni.request is application/json**
// Take uni.request as an example
uni.request({
method: 'POST',
url: 'https://${云对象Url化域名}/${触发路径}/${云对象方法名}',
data: {
a: 1,
b: 2
},
success(res) {
console.log(res);
}
})
// httpInfo of cloud object
{
path: '/${云对象方法名}',
httpMethod: 'POST',
headers: {
...
"content-type": 'application/json'
},
isBase64Encoded: false,
body: '{"a":1,"b":2}', // 注意此处可能是base64,需要根据isBase64Encoded判断
}
Note: All methods starting with _
are private and not accessible to clients. That is, when the client calls the cloud object, the method starting with _ cannot be called.
There are currently 3 built-in special methods: _before
, _after
, _timing
A special method _before
can be created in the cloud object to perform preprocessing before calling regular methods, generally used for interceptors, unified authentication, parameter verification, etc.
The logic of the following example is that when the client calls the add method of the todo cloud object, the logic in the _before
method will be executed first. When it is judged that the add method is used, the client token will be verified. If the verification fails, an error will be reported and returned to the client. , check by continuing to execute the add method.
// todo/index.obj.js
module.exports = {
_before: function(){
const methodName = this.getMethodName()
if(methodName === 'add' && !this.getUniIdToken()) {
throw new Error('token不存在')
}
},
add: function(title = '', content = '') {
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
The counterpart to the preprocessing _before
is the postprocessing _after
. A special method _after
can be created in the cloud object to reprocess the return result or the error thrown by this method call
See the following example:
// todo/index.obj.js
module.exports = {
_before: function(){
this.startTime = Date.now() // 在before内记录开始时间并在this上挂载,以供后续流程使用
},
add: function(title = '', content = '') {
if(title === 'abc') {
throw new Error('abc不是一个合法的todo标题')
}
return {
errCode: 0,
errMsg: '创建成功'
}
},
_after(error, result) {
if(error) {
throw error // 如果方法抛出错误,也直接抛出不处理
}
result.timeCost = Date.now() - this.startTime
return result
}
}
Added in HBuilderX 3.5.2
Scheduled tasks can be configured in the uniCloud web console. After configuring a cloud object, the built-in method _timing
of the cloud object will be executed periodically
For detailed usage reference: Timed triggering of cloud objects
The data returned by the cloud object to the client, including normal data and error objects.
In theory, developers can use any method to return the data format in the correct state, either a string or a json object.
However, when handling errors, it is recommended to use uniCloud response body specification, so that the client can intercept errors uniformly.
When an error is reported inside a cloud object, such as an error returned by a non-developer code such as a method name error, the uniCloud response body specification will automatically be used to throw an error object.
When the developer code actively reports an error, such as a parameter verification error, because the error object (e) cannot be directly written, it needs to be returned in accordance with the uniCloud response body specification. Add errCode
and errMsg
to the json object.
After the uni-app framework gets the response result of the cloud object, it will identify whether it contains errCode
and errMsg
, and then automatically create an error object (e), the strategy is as follows:
That is to say, when the developer's front-end code calls cloud objects, try catch or then catch is required. When no error is reported, return the result directly in try
or in res
of then()
, and get the error object e in catch (e) {}
when an error is reported.
Whether it is a system error (such as a network problem, cloud function timeout problem), or a feedback error from the developer's business, it is all caught in catch
.
The error object (e) thrown by the client has the following properties
Attribute Name | Type | Required | Description |
---|---|---|---|
errCode | string|number | No | Error Code |
errMsg | string | no | error message |
requestId | string | No | The requestId of the current request. Local debugging does not have this value, it needs to be run in the service space |
detail | Object | No | full error response (only if the response conforms to the uniCloud response body specification) |
See the following examples for details:
// cloud object code todo/index.obj.js
module.exports = {
add: async function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...other logic
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
// client code
const todo = uniCloud.importObject('todo')
// If title and content are not passed, the cloud function returns an incorrect response
try {
await todo.add()
} catch (e) {
// e.errCode === 'INVALID_TODO'
// e.errMsg === 'TODO title or content cannot be empty'
// e.requestId === 'xxxx'
}
// Pass in the correct title and content, and the cloud function returns the original response
try {
const res = await todo.add('title demo', 'content demo')
// res = {errCode: 0,errMsg: 'created successfully'}
} catch (e) {}
Notice
The client obtains an instance of the cloud object through the uniCloud.importObject
method. The usage is as follows
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
Cloud functions or cloud objects can also call cloud objects in the same service space, and the usage is the same as when the client calls cloud objects.
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
Added in HBuilderX 3.5.2
For detailed usage reference: Timed triggering of cloud objects
Added in HBuilderX 3.5.2
When the external system needs to access the cloud object, the cloud object can be encapsulated into an HTTP URL. For detailed usage reference: cloud object uses url
The cloud or client has the uniCloud.init method to obtain the uniCloud instance of other service spaces. Using the importObject of this instance, you can call the cloud objects of other service spaces. Reference
Both the client and Tencent Ali are supported. The cloud uniCloud.init
method is only supported by Tencent Cloud, and can only obtain the uniCloud instance of Tencent Cloud service space under the same account.
Sample code
const mycloud = uniCloud.init({
provider: 'tencent',
spaceId: 'xxx'
})
const todo = mycloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
Notice
Different methods exported by a cloud object cannot call each other. For example, in the following example, the addTodo method cannot be called inside the tryAddTodo method.
Only the logic shared by multiple methods can be placed outside the object exported by the cloud object for the method call of the cloud object. For example, the following extracts the public function pureAddTodo :
// todo.obj.js
// The async before the method is based on its own business, not necessarily async
async function pureAddTodo(title, content) {
// ...add todo logic
}
module.exports = {
async tryAddTodo() {
try {
return addTodo(title, content) // 一定会失败。只能调用 pureAddTodo 这样的非导出方法。
} catch (e) {
return {
errCode: 'add-todo-failed'
}
}
},
async addTodo(title, content) {
return pureAddTodo(title, content)
}
}
Since the transport layer also has contextual information, developers need to pay attention to controlling the parameter volume when sending parameters to cloud objects.
Added in HBuilderX 3.4.6, this adjustment is an incompatible update.
Background: When writing the code for the client to connect to the network, the developer will inevitably write a bunch of code repeatedly: first call the loading waiting box, and then close the loading after the network is completed. If the server is abnormal, a prompt will pop up.
Starting from HBuilderX 3.4.6, the interactive/prompt interface will be automatically displayed by default when calling the method of the cloud object.
If the UI displayed by default does not meet your needs, you can customize some interactive content through configuration, or you can directly close the automatically displayed interactive interface.
customUI: true
when importing cloud objects on the client sideexample:
uniCloud.importObject('todo', {
customUI: true // 取消自动展示的交互提示界面
})
uniCloud.importObject('todo', {
customUI: false, // 是否取消自动展示的交互界面。默认为false,配置为true时取消自动展示的交互提示界面,以下配置均不再生效
loadingOptions: { // loading相关配置
title: '加载中...', // 显示的loading内的提示文字。默认值为:加载中...
mask: true // 是否使用透明遮罩,配置为true时不可点击页面其他内容。默认值为:true
},
errorOptions: { // 错误界面相关配置
type: 'modal', // 错误信息展示方式,可取值:modal(弹框,默认)、toast(toast消息框)。默认值为:modal
retry: false // 是否展示重试按钮,仅在type为modal时生效。用户点击重试按钮时将重新请求调用的方法,默认为false
},
parseSystemError({ // 转化云对象内未捕获的错误,或客户端网络错误
objectName, // 云对象名
methodName, // 方法名
params, // 调用方法时传的参数,注意params是一个数组
errCode, // 请求返回的错误码
errMsg // 请求返回的错误信息
} = {}){
return {
errMsg: '系统错误,请稍后再试' // 用于展示的错误信息
}
}
})
Notice
importObject
Documentation moved to: Cloud object run locally
All js methods in HBuilderX support the syntax hint system of jsdoc+.
Enter a comment in a specific format through /**
at the beginning of the method, and you can see the parameter prompt when calling the method of this cloud object.
/**
* method1方法描述
* @param {string} param1 参数1描述
* @returns {object} 返回值描述
*/
method1(param1) {
if (!param1) {
return {
errCode: 'PARAM_IS_NULL',
errMsg: '参数不能为空'
}
}
return {
param1 //请根据实际需要返回值
}
}
For details, see: Using cookies in url-based scenarios
index.obj.js
, while cloud functions are index.js
. **In order to correctly distinguish uniCloud between the two, there is no index.obj.js in the cloud function, nor index.js in the cloud object. **_
are private and not accessible to clientsthis
to point incorrectlyDCloud officially developed uni-id-co
, which is a more complex cloud object, used to match uni-id-pages Realize functions such as cloud-integrated user registration and login. The code is open source for reference.
The uniCloud server and client interact in three ways: cloud function, cloud object, and clientDB.
After publishing from cloud objects, traditional cloud functions are no longer recommended.
If it is mainly based on database operations, it is recommended to use clientDB, and the development efficiency is the highest.
If the server side does not operate the database, or there is complex logic that should not be exposed on the front end, it is recommended to use cloud objects.