DEV Community

Cover image for Total.js v5: Schemas and Actions.
Louis Bertson
Louis Bertson

Posted on

Total.js v5: Schemas and Actions.

Total.js v5: Schemas and Actions.

If you’re diving into Total.js development, you’ve chosen a robust, modern framework that’s packed with powerful features for building fast, scalable applications. At the heart of Total.js are two essential concepts that will guide much of your backend logic: schemas and actions.
Schemas and actions might seem complex at first, but once you understand how they work together, they’ll become some of your favorite tools in the framework. In this guide, I’ll break down these concepts, show you
how to set them up, and walk you through practical examples that will empower you to create an organized, flexible codebase.

Let's get started!

Understanding schemas and actions in Total.js

In Total.js, schemas and actions play distinct roles that complement each other:

  • Schemas: These are blueprints for organizing data and the operations that manage it. With schemas, you define the structure of your data and associate it with specific actions that can perform tasks on it, such as creating, updating, or deleting records.

  • Actions: Actions in Total.js represent business logic for performing specific tasks. Actions can be tied to schemas (schema actions) or created as standalone functions that handle tasks not directly linked to any schema.

Think of schemas as structured “folders” where you organize your data logic, while actions are the “tools” that operate on that data. You’ll be able to call actions as needed, whether they belong to a schema or stand alone, and they’re especially useful for handling backend operations like processing user input or interacting with a database.

Getting Started with Schemas in Total.js

1. Setting Up a Basic Schema

A schema in Total.js is more than just a data structure. It’s a powerful way to group related actions that handle specific tasks for a particular type of data. Here’s a simple example of creating a schema for Users.
In your total.js application create a folder schemas and then create a file users.js inside to paste the following:

NEWSCHEMA('Users', function(schema) {
    // Action: list
    schema.action('list', {
        name: 'Listing operation',
        query: '*search:String', // Query parameters
        action: function($) {
            // Action logic goes here
            $.success(); // Send a success response
        }
    });

    // Action: insert
    schema.action('insert', {
         name: 'Creation operation',
        input: '*name:String, *email:Email', // Input validation
        action: function($, model) {
            // Action logic for inserting user
            $.success(model); // Respond with the inserted model data
        }
    });

    // Action: read
    schema.action('read', {
         name: 'Reading operation',
        params: '*id:UID', // Parameter validation
        action: function($) {
            // Action logic to read a user by ID
            $.success(); // Send a success response
        }
    });
});
Enter fullscreen mode Exit fullscreen mode

In this example, we created a schema called Users with three actions:

  • list: Returns a list of users based on search parameters.
  • insert: Adds a new user to the database with validation for required fields (name and email).
  • read: Retrieves a specific user by their unique ID.

By organizing these actions within the Users schema, you create a cohesive set of operations for handling user data.

2. Linking Schemas to Routes

To make these schema actions accessible via HTTP requests, you can link them to routes in Total.js. This will allow your frontend or API clients to call these actions. Just create a controller file controllers/api.js to put the following:

exports.install = function () {
        ROUTE('GET  /api/users/         --> Users/list');
        ROUTE('POST /api/users/insert   --> Users/insert');
        ROUTE('GET  /api/users/{id}     --> Users/read');
}
Enter fullscreen mode Exit fullscreen mode

In this example:

  • A GET request to /api/users/ will call the list action.
  • A POST request to /api/users/insert will invoke the insert action.
  • A GET request to /api/users/{id}/ will trigger the read action with a unique user ID passed in the URL.

This structure keeps your routing and backend logic organized and straightforward.

Standalone actions

While schema actions are great for data-centric tasks, sometimes you’ll need an action that performs a standalone operation, not linked to a specific schema. Standalone actions are defined independently and can be used for any custom backend functionality.

1. Creating a Standalone Action

Total.js recommand to create your actions file in actions folder. But you can put them somewhere else like (schemas,definitions,modules,etc)
Let’s say we want to create a standalone action called find. This action accepts query parameters for pagination and sorting without being tied to a schema.

Let us create this file in actions/default.js and copy/paste the following:

NEWACTION('find', {
    query: 'page:Number,sort:String',
    params: 'projectid:String',
    action: function($) {
        // Logic to find specific data based on query and params
        $.success(); // Send a success response
    }
});
Enter fullscreen mode Exit fullscreen mode

This find action can be called to handle any general-purpose data search, making it a flexible solution for various backend needs.

2. Connecting standalone actions to routes

Just like schema actions, standalone actions need to be linked to routes to be accessed from your API or frontend.

ROUTE('GET /api/find/           --> find');
Enter fullscreen mode Exit fullscreen mode

With this route, a GET request to /api/find/ will call the standalone find action.

Using ACTION()

Total.js provides the ACTION() method, a way to call both schema-related and standalone actions in your code.

Example

Let’s call the Users/insert action we created earlier using ACTION():

ACTION('Users/insert', { name: 'John', email: 'johndoe@gmail.com' }).callback(function(err, response) {
    if (err) {
        console.error('Action error:', err);
    } else {
        console.log('User insert response:', response);
    }
});

Enter fullscreen mode Exit fullscreen mode

Here, we specify the Users/insert action and pass a search query to find users with “John” in their data. You can use this approach to call any schema or standalone action, making ACTION() a highly flexible tool.

Advanced: Calling Schema Actions Within Other Schema Actions

Total.js allows you to call actions within the same schema using the $.action method. This feature is powerful for creating complex workflows that involve multiple steps.

Example: Nested Schema Actions

Let’s say we want an action in the Users schema to first list users, then perform additional processing based on that list.

NEWSCHEMA('Users', function(schema) {
    schema.action('list', {
        name: 'Listing users',
        query: 'search:String',
        action: function($) {
            $.success([{ name: 'John Doe' }, { name: 'Jane Doe' }]); // Sample data
        }
    });

    schema.action('proccess', {
        action: async function($) {
            // Call the list action within the same schema
            $.action('list').callback(function(err, users) {
                if (err) return $.invalid(err);

                // Process users after retrieving the list
                users.forEach(user => {
                    console.log('Processing user:', user.name);
                });
                $.success('Users processed successfully!');
            });

            // or 
            // var response = await $.action('list').query({ search: 'totaljs' }).user($.user).promise($);


        }
    });
});
Enter fullscreen mode Exit fullscreen mode

In this example, proccess calls list within the Users schema. This structure is great for chaining operations within schemas and gives you full control over workflow management.

Advanced usage

Total.js v5 allows so many other usages of NEWSCHEMA and NEWACTION for very specific cases. We are not going to cover them here because we are preparing another blog post for them. But if you are curious about learning them you can check this blog post

Key Takeaways and Tips

Working with schemas and actions in Total.js can elevate your application’s structure and efficiency. Here are some key points to keep in mind:

  • Schemas are collections of related actions tied to specific data entities. Use them to organize and validate your data-centric actions.
  • Standalone actions allow you to build independent functions for tasks that don’t fit within a schema.
  • Use ACTION() for flexible action calls, whether they’re schema-based or standalone.
  • Route linking connects your actions to HTTP endpoints, making your backend logic accessible via API routes.
  • For more complex workflows, nested actions within schemas give you a streamlined way to manage multi-step processes.

With these foundations in place, you’re ready to start building robust, modular backend logic in Total.js! Experiment with different schema and action configurations, and don’t hesitate to explore Total.js’s extensive documentation as you continue to master this flexible framework.

Happy coding!

Top comments (0)