Cloud Objects – Redefining front-end and back-end interaction

background

Since 2000, xmlit has become popular as a data exchange format, with server splicing xmlinterfaces, client js obtaining xmlcontent, and dynamically modifying pages.

A few years later, smaller data volumes jsonreplaced it xml.

After the arrival of mobile Internet, the proliferation of interfaces has been exacerbated by the fragmentation of clients.

In the blink of an eye, interfaces have been around for 20 years. Other technologies are developing rapidly, but front-end and back-end interactions have always been interfaces, with little innovation.

js already has importexportwhy can’t calling the back-end interface be the same as calling a front-end module?

Serverless makes all this change.

Amazon lambdacame up with the concept of cloud functions, which is no longer used restfulurlbut is still based on jsonexchanging front-end and back-end data.

uniCloudWe also initially started by supporting cloud functions, but we found that this was still not elegant, concise, intuitive, and unified enough.

Starting HBuilderX 3.4from , ” cloud objectsuniCloud ” were launched , making calling cloud services truly as simple as calling a front-end module.

What are cloud objects

Cloud object: The server writes the API, the client calls the API, and the interface for transmitting json is no longer developed. The ideas are clearer and the code is more streamlined.

For example, the server writes a cloud object news, which exports several methods: add(), getList(), getDetailById(), softDel(), changeContent(), allowPublic(), addComment(), getComments()…etc. method.

The client’s js can directly access importthis newscloud object and then directly call addother methods.

The server sample code is as follows:

In HBuilderX, create a new cloud function/cloud object in the uniCloud/cloudfunctions directory, select the type as cloud object, and name it news. Open the cloud object entrance index.obj.jsand add an add method.

// Cloud object name: news
module.exports = {
    add ( title , content) {
         title = title . trim ()
        content = content. trim ()
         if (! title || !content) {
             return {
                errCode: 'INVALID_NEWS' ,
                errMsg: 'Title or content cannot be empty'
            }
        }
        // ...other logic
        return {
            errCode: 0,
            errMsg: 'Created successfully'
        }
    }
}

Then in the client’s js, importthis newsobject calls its addmethod.

const news = uniCloud.importObject( 'news' ) //The first step is to import cloud objects 
async function add () {
     try {
         const res = await news. add ( 'title demo' , 'content demo' ) //Import cloud objects Then you can directly call the object's method. Pay attention to using asynchronous await.
        uni.showToast({
            title: 'Created successfully'
        })
    } catch (e) { // Comply with uniCloud response body specification https://uniapp.dcloud.net.cn/uniCloud/cf-functions?id=resformat, automatically throw this error
    }
}

You can see that the code of the cloud object is very clear, and the number of lines of code is only 27 .

The same logic using the traditional interface method requires more code, as shown below:

// Call cloud function in traditional way - cloud function code 
// Cloud function name: news 
// The content of cloud function entrance 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_NEWS' ,
                     errMsg : 'NEWS title or content cannot be empty'
                }
            }
            // ...Omit other logic 
            return {
                 errCode : 0 ,
                 errMsg : 'Created successfully'
            }
        }
    }
    return {
         errCode : 'METHOD_NOT_FOUND' ,
         errMsg : `Method[ ${method} ] not found`
    }
};

Calling cloud functions in the traditional way – client code

async function  add () {
     try {
         const  res = uniCloud. callFunction ({
             name : 'news' , 
             data : {
                 method : 'add' ,
                 params : {
                     title : 'title demo' ,
                     content : 'content demo'
                }
            }
        })
        const {
            errCode,
            errMsg
        } = res.result
        if (errCode) {
            uni. showModal ({
                 title : 'Creation failed' ,
                 content : errMsg,
                 showCancel : false
            })
            return
        }
        uni.showToast ({
             title : ' Created successfully'
        })
    } catch (e) {
        uni.showModal ({
             title : ' Creation failed' ,
             content : e.message,
             showCancel : false
        })
    }
}

The above traditional development requires 68 lines of code. Compared with the 27 lines of code of cloud objects , it can be said to be “ugly and long”

More powerful features

1. Preprocessing and postprocessing

No matter which method of the cloud object is requested, _beforethe method will be passed before starting and the method will be executed at the end _after. This helps uniformly check ahead and format errors.

Example:

// news/index.obj.js 
module . exports = {
     _before : function (){
         this . startTime = Date . now () // Record the start time in before and mount it on this for subsequent process use 
        const methodName = this . getMethodName () // Get the cloud object method name of the current request 
        if (methodName === 'add' && ! this . getUniIdToken ()) {
             throw  new  Error ( 'token does not exist' )
        }
    },
    add : function ( title = '' , content = '' ) {
         if (title === 'abc' ) {
             throw  new  Error ( 'abc is not a legal news title' )
        }
        return {
             errCode : 0 ,
             errMsg : 'Created successfully'
        }
    },
    _after ( error, result ) {
         if (error) {
             throw error // If the method throws an error, it will be thrown directly without processing.
        }
        result. timeCost = Date . now () - this . startTime 
        return result
    }
}

2. The return value of the cloud object is compatible with the uniCloud response body specification.

The cloud object return value defaults to uniCloud响应体规范, which facilitates the client to uniformly intercept errors.

Regardless of network abnormalities or token expiration, prompts can be intercepted uniformly.

For details, see uniCloud response body specification

3. Automatically display the interactive interface

Every time when writing code for client networking, developers have to write a bunch of code repeatedly: first call the loading waiting box, then close loading after the networking is completed, and if the server is abnormal, a prompt box will pop up.

Original writing (line 22):

uni.showLoading ( {
     title : 'Networking...'
})
uni. request ({
     url : "xxxx" ,
     success : ( res ) => {
        uni.showToast ( {
             title : 'Added successfully' ,
             icon : 'success' ,
             mask : true ,
             duration : duration
        });
    },
    fail : ( err ) => {
        uni. showModal ({
             content : err. errMsg ,
             showCancel : false
        });
    },
    complete : () => {
        uni.hideLoading ( );
    }
});

Now, when calling methods of cloud objects, the above functions are provided by default.

  • Display the loading waiting box when requesting the start of networking.
  • Hide loading after completion
  • If an error is reported in the request, a pop-up window will be displayed (can also be configured to display a Toast)
const news = uniCloud.importObject( 'news' ) //The first step is to import the cloud object 
try {
     await news. add ( 'title demo' , 'content demo' ) //After importing the cloud object, you can directly call the object's method Now, pay attention to using asynchronous await
    uni.showToast({
        title: 'Added successfully'
    })
} catch (e) {}

As above, it originally required 23 lines of code, but now it can be done in 7 lines!

Of course, these UI strategies can be customized.

  1. URLization

For historical compatibility reasons, Cloud Object also provides a URL solution. Developers can still convert a cloud object into an httpinterface url.

Summarize

There are many benefits of using cloud objects:

  1. clearer logic
  2. More streamlined code
  3. Less collaboration costs (and conflicts~)
  4. When the client calls, there is a complete code prompt in the IDE, and all method parameters can be prompted. (Transmission jsoncannot be ideprompted here)
  5. Automatically supports uniCloud response body specifications to facilitate error interception and unified processing