# cloud object

Added in HBuilderX 3.4.0

# Background and Advantages

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:

  1. Clearer logic
  2. Leaner code
  3. Fewer collaboration costs (and contradictions~)
  4. There are complete code prompts in the IDE when the client calls, and the method parameters can be prompted. (Transfer json can not be prompted in ide)
  5. Default supports uniCloud response body specification, which is convenient for error interception and unified processing

# Getting started

# Create cloud object

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

# Client call

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:

  1. try catch
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)
}
  1. then catch (promise writing)
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 object API

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.

# Get client information

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

  • The information reported by the client may be tampered in theory, and the legality of the data sent from the front end should be verified in actual business
  • Except for clientIP, other client information can only be obtained by calling the uni-app client as a cloud object
  • The cloud object is slightly different from the client platform obtained in the cloud function. The cloud function does not match the platform value of the app platform of the vue2 and vue3 versions. The vue2 is 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 preferedAppPlatform

# Get cloud information

Interface 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

# Get client token

云对象自动管理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

# Get the name of the currently called method

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
	}
}

# Get the current parameter list

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']
	}
}

# Get current request id

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
		}
	}
}

# Get http information when urlized

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

  • httpInfo.path represents the access path with the configured urlized path as the root path. With the configuration /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判断
}

# Built-in special method

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

# Preprocessing _before

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: '创建成功'
		}
	}
}

# Post-processing _after

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
	}
}

# Timing _timing

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

# Cloud object return value

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:

  • If it is a normal result (errCode is false value [0, false, null, undefined, ...] or the result does not contain errCode), do not throw an error object (e)
  • If it is an error result (errCode is true), combine the errCode and errMsg in the result into an error object (e) and throw
  • If it is an uncaught error by other cloud functions, directly combine the error code and error information into an error object (e) and throw

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 js error object is not json, console.log(e) directly, and only the errMsg after toString() can be obtained. instead of an expanded json structure. So you need to print the sub properties of the e object separately.

# Multiple calling methods of cloud objects

# Client calls

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')

# Call

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')

# Timing trigger

Added in HBuilderX 3.5.2

For detailed usage reference: Timed triggering of cloud objects

# urlify

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

# Call cloud objects across service spaces

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

  • The above sample code should use try catch or then catch to handle error capture in actual development

# Cloud object multiple methods share logic

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)
	}
}

# 云对象的接收参数的体积上限

  • 支付宝小程序云接收参数大小不可超过6MB
  • The size of Alibaba Cloud receiving parameters cannot exceed 1MB
  • The size of Tencent Cloud receiving parameters cannot exceed 5MB

Since the transport layer also has contextual information, developers need to pay attention to controlling the parameter volume when sending parameters to cloud objects.

# Automatically display the interactive interface

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.

  1. The loading waiting box is displayed when the request for networking starts,
  2. Hide loading after the end
  3. If the request reports an error, display a pop-up window (can also be configured to display Toast)

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.

  • To disable the automatically displayed UI, please pass in the parameter customUI: true when importing cloud objects on the client side

example:

uniCloud.importObject('todo', {
	customUI: true // 取消自动展示的交互提示界面
})
  • To customize the UI displayed by default, configure as follows:
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

  1. The configuration takes effect only for the cloud object instance returned by the current importObject
  2. This function only takes effect when the client calls cloud objects. Calling cloud objects from cloud functions or cloud objects does not take effect

# run locally

Documentation moved to: Cloud object run locally

# jsdoc + syntax hints

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 //请根据实际需要返回值
	}
}

# Using cookies in cloud objects

For details, see: Using cookies in url-based scenarios

# Precautions

  • Cloud objects and cloud functions are in the cloudfunctions directory, but different from cloud functions, the entry of cloud objects is 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. **
  • All methods starting with _ are private and not accessible to clients
  • Cloud objects can also refer to public modules or packages on npm in the same way as cloud functions.
  • The exported method of the cloud object cannot be an arrow function, exporting an arrow function will cause this to point incorrectly

# Complex example

DCloud 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.