Hands-on API Development with Zoho Catalyst ZEST
APIs help different applications talk to each other, making software more powerful. Zoho Catalyst ZEST makes it easy to build APIs without writing a full backend from scratch. With ZEST, you can define API structures using XML (Zest Specification), and Catalyst will generate a working server stub for you. This speeds up development and ensures consistency.
Published on February 27, 2025

1. Introduction
APIs help different applications talk to each other, making software more powerful. Zoho Catalyst ZEST makes it easy to build APIs without writing a full backend from scratch. With ZEST, you can define API structures using XML (Zest Specification), and Catalyst will generate a working server stub for you. This speeds up development and ensures consistency.
In this guide, you will learn step by step how to create an API using ZEST in Zoho Catalyst. We will cover everything from setting up your environment to writing your ZSpec file, generating the server stub, and testing your API. Whether you are a beginner or an experienced developer, this hands-on guide will help you build APIs faster and more efficiently with Zoho Catalyst ZEST.
2. What is ZEST?
ZEST (Zoho Extension Specification Toolkit) is a powerful tool provided by Zoho Catalyst that simplifies API development. It allows developers to define APIs using a structured XML-based format called ZSPEC (ZEST Specification). With ZEST, you can describe your API, define data models, and set rules for request and response handling—all within a single file.
ZEST is an enhanced alternative to OpenAPI, offering additional features such as advanced data validation, dynamic request-response handling, and automated SDK and server stub generation. This means developers can design and implement APIs quickly without writing extensive boilerplate code.
Once you define your API in ZSPEC, you can use ZEST to generate ready-to-use server stubs and SDKs in multiple programming languages, making it easier to integrate with applications.
3. Why Use ZEST for API Development?
ZEST offers several advantages over traditional API development methods. Here are some key reasons why developers prefer ZEST:
- Automated Code Generation: Instead of manually writing API boilerplate code, ZEST can generate server stubs and SDKs for different programming languages, including Java, Python, and Node.js.
- Enhanced Validation: ZSPEC allows you to enforce strict validation rules for request data. For example, you can specify whether a field is required, unique, or should follow a specific format.
- Dynamic Request & Response Handling: You can define conditional logic that modifies API requests or responses based on certain values (e.g., requiring a postal code if the country is “India”).
- Seamless Integration with Zoho Catalyst: ZEST is built to work within the Zoho ecosystem, making it an excellent choice for businesses that use Zoho services.
- Supports Serverless Deployment: ZEST allows APIs to be deployed as serverless functions on Zoho Catalyst, reducing infrastructure management.
By using ZEST, developers can create robust, scalable, and secure APIs faster while ensuring high-quality standards.
4. How ZEST Works
ZEST follows a structured workflow to simplify API development. Here’s how it works:
Define API in ZSPEC:
- You create a ZSPEC file that describes your API, including data models, endpoints, authentication, and response structures.
- The ZSPEC file acts as a blueprint for your API.
Upload to Zoho Catalyst Spec Studio:
- Once the ZSPEC file is ready, you upload it to Zoho Catalyst.
- The Spec Studio tool allows you to edit the ZSPEC file, generate documentation, and preview the API structure.
Generate Server Stub or SDK:
- ZEST lets you export a server stub in multiple frameworks (e.g., Java Spring Boot, Catalyst Appsail).
- If you need an SDK for client applications, ZEST can generate it in various programming languages like Python, PHP, and JavaScript.
5. Building a User Management API with ZSPEC in ZEST
This section will teach you from scratch how to create a User Management API using ZSPEC in ZEST. We will go step by step, explaining each concept in detail in a way that is easy to understand.
By the end of this guide, you will know how to:
- Define users as a resource in ZSPEC.
- Implement security with OAuth 2.0 to control access.
- Create API endpoints for managing users (CRUD operations)..
- Use pagination to handle large datasets efficiently.
- Deploy the API and test it using Postman.
5.1 Understanding What We Are Building
Before we start writing the ZSPEC file, let’s understand what we are creating. The user management API we will be building allows a system to:
- Store user data in a structured way.
- Allow authorized users to create, read, update, and delete users.
- Implement security so that only admins can modify user data.
5.2 Prerequisites
Before proceeding, ensure you have the following in place:
- A Zoho Catalyst Account.
- Java SDK installed with Spring Boot.
- Basic knowledge of Java, XML, and API development.
5.3 Setting Up ZEST in Zoho Catalyst
Since ZEST is a tool within Zoho Catalyst, you must set up your API inside a Catalyst project before you can start defining it.
To get started:
- Create a new project: Click on Create a New Project or open an existing project.
- Navigate to the ZEST section: Open your project and find the ZEST tool.
- Start defining your API: Click on Start Exploring to enter Spec Studio, where you will write your ZSPEC file.
- Once ZEST is set up, you are ready to start defining your API.
5.4 Defining the User Resource in ZSPEC
A resource in an API is an entity that the system manages. In our case, the users resource represents people who have accounts in the system.
Each user will have various attributes, such as:
- A unique ID to identify them.
- A username to display in the system.
- An email address for authentication.
- A role (Admin, User, Guest) to define permissions.
- Timestamps to track when the user was created or updated.
5.4.1 Declaring the User Resource in ZSPEC
To begin defining our API, we need to declare the resource in ZSPEC.
<?xml version="1.0" encoding="UTF-8"?>
<resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="users" pre-loaded="false" product="zentrails" specification="1.0.0" file-version="01jmjwwrajt9ehktrdab60vb03">
Here’s what happens in the code above:
- name=”users” → This tells ZEST that our API manages user data.
- pre-loaded=”false” → This means the API is not preloaded in Catalyst—we define it manually.
- product=”zentrails” → This associates the API with a product named Zentrails.
- specification=”1.0.0″ → This is the version of the ZSPEC file format being used.
- file-version=”01jmjwwrajt9ehktrdab60vb03″ → This is a unique identifier for this version of the file.
This declaration initializes the ZSPEC file, allowing us to start defining the API.
5.4.2 Creating the User Data Structure
Now that we have declared our API, we need to define how user data is stored. A data structure in ZSPEC defines how a resource (like a user) is stored and accessed. It specifies:
- Which attributes the resource has (e.g., id, username, email).
- What type of data each attribute holds (e.g., string, integer, datetime).
- Whether an attribute is required or optional.
A basic user includes only essential details, like the user’s ID and username. We can create the data structure for our user management API this way:
<structure name="MinifiedUser" ref-name="MinifiedUser" lookup="users">
<property name="id" type="long_string" required-for="all" />
<property name="username" type="string" required-for="all" />
</structure>
● name=”MinifiedUser” → The name of the basic user structure.
● lookup=”users” → This links the structure to the users resource.
● The
● id: A unique identifier for the user.
● username: A string representing the user’s display name.
This lightweight user object is useful when listing users in a table or dropdown menu. A full user profile includes more details, such as email, role, and timestamps.
<structure name="User" ref-name="User" extend="MinifiedUser">
<property name="email" type="string" required-for="all" />
<property name="role" type="string" values="Admin,User,Guest" default-value="User" />
<property name="created_at" type="datetime" required-for="response" />
<property name="updated_at" type="datetime" required-for="response" />
</structure>
5.5 Implementing Authentication with OAuth 2.0
Security is essential when building an API, especially one that manages user data. Without proper authentication, anyone could access, modify, or delete user accounts, leading to security vulnerabilities.
To prevent unauthorized access, we will implement OAuth 2.0 authentication in our User Management API. This ensures that:
- Only authorized users can access the API.
- API requests include a secure token for validation.
- Sensitive operations like creating, updating, or deleting users require authentication.
In ZSPEC, we define OAuth 2.0 authentication using the <oauth2> tag.
<oauth2 name="OAuth2Flow">
<authorization-url path="https://accounts.zoho.com/oauth/v2/auth">
<operation category="action" method="post" name="Authorization Request">
<response status="200" />
</operation>
</authorization-url>
<token-url path="https://accounts.zoho.com/oauth/v2/token">
<operation category="action" method="post" name="Generate Token">
<response status="200" />
</operation>
</token-url>
<refresh-url path="https://accounts.zoho.com/oauth/v2/token">
<operation category="action" method="post" name="Refresh Token">
<response status="200" />
</operation>
</refresh-url>
</oauth2>
Breaking it down:
- <authorization-url> → The login page where users enter their credentials to receive an authorization code.
- <token-url> → The URL where the authorization code is exchanged for an OAuth access token.
- <refresh-url> → If a token expires, users can request a new one without logging in again.
To ensure security, all API operations must require authentication. This is done by adding the <authentication> tag in each endpoint.
<url path="/user-management/1.0.0/users">
<operation category="read" method="get" name="Get Users">
<error condition="RESPONSE:$.status >= 400" />
<response-ref name="SuccessActionResponse" />
<authentication location="header" name="Authorization" schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.READ" type="oauth2" />
</operation>
</url>
With the setup above, we created a system that:
- Requires authentication using OAuth 2.0 (schema=”OAuth2Flow”).
- Specifies a scope (users.READ), ensuring only authorized users can access the endpoint.
- Rejects unauthorized requests with an error response (RESPONSE:$.status >= 400).
We apply the same authentication process to all API operations:
- Creating a user (POST /users)
- Updating user details (PUT /users/{id})
- Deleting a user (DELETE /users/{id})
5.6 Defining API Endpoints for User Management
Now that our API requires authentication, let’s define the CRUD operations for managing users.
5.6.1 Retrieving All Users (GET /users)
This endpoint retrieves a list of users.
<url path="/user-management/1.0.0/users">
<operation category="read" method="get" name="Get Users">
<error condition="RESPONSE:$.status >= 400" />
<response-ref name="SuccessActionResponse" />
<authentication location="header" name="Authorization"
schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.READ" type="oauth2" />
</operation>
</url>
- The GET method fetches all users from the database.
- OAuth 2.0 authentication is required (users.READ).
- If the request is successful, a list of users is returned in JSON format.
5.6.2 Creating a New User (POST /users)
The POST endpoint adds a new user to the system.
<url path="/user-management/1.0.0/users">
<operation category="create" method="post" name="Create Users">
<error condition="RESPONSE:$.status >= 400 || $.status == 'error'" />
<request-body-ref name="UsersBody" />
<response status="201">
<content>
<encode type="application/json" />
<structure-ref name="ResponseWrapper" />
</content>
</response>
<authentication location="header" name="Authorization" schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.CREATE" type="oauth2" />
</operation>
</url>
Here, we:
- Used the POST method to create a new user.
- Requires authentication (users.CREATE).
- If successful, returns a 201 Created response with the new user’s details.
5.6.3 Updating a User (PUT /users/{id})
This endpoint modifies user details.
<url path="/user-management/1.0.0/users/{id}">
<operation category="update" method="put" name="Update Users">
<error condition="RESPONSE:$.status >= 400 || $.status == 'error'" />
<request-body-ref name="UsersBody" />
<response-ref name="SuccessActionResponse" />
<authentication location="header" name="Authorization" schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.UPDATE" type="oauth2" />
</operation>
</url>
- We use the PUT method to update a user’s details.
- Requires authentication (USER_MANAGEMENT.users.UPDATE).
- The id in the URL identifies which user is being updated.
5.6.4 Deleting a User (DELETE /users/{id})
We can remove a user from the system with this endpoint.
<url path="/user-management/1.0.0/users/{id}">
<operation category="delete" method="delete" name="Delete Users">
<error condition="RESPONSE:$.status >= 400 || $.status == 'error'" />
<argument-ref name="id" />
<response-ref name="SuccessActionResponse" />
<authentication location="header" name="Authorization" schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.DELETE" type="oauth2" />
</operation>
</url>
Like the other methods, here we:
- Used the DELETE method to remove a user.
- Requires authentication (users.DELETE).
- If the user ID does not exist, the API returns a 404 Not Found error.
5.7 Implementing Pagination in the User Management API
When working with large datasets, retrieving all users at once is inefficient. If we have thousands or millions of users, returning them all in a single request would:
- Increase server response time.
- Consume too much memory.
- Make the API slower for clients.
To solve this problem, we implement pagination, which allows clients to fetch a limited number of users at a time while providing a way to navigate through the dataset. When implementing pagination, we include the following parameters in API requests:
- page → Specifies which page of results to retrieve.
- per_page → Defines how many users to return per page.
- count → Displays the total number of records available.
- more_records → Indicates whether more users are available after the current page.
Example Request:
GET /user-management/1.0.0/users?page=2&per_page=10
Example Response:
{ "status": "success", "response": [ { "id": "123", "username": "johndoe", "email": "johndoe@example.com" }, { "id": "124", "username": "janedoe", "email": "janedoe@example.com" } ], "info": { "page": 2, "per_page": 10, "count": 150, "more_records": true } }
5.7.1 Defining Pagination in ZSPEC
We define a structure called PaginationInfo that holds pagination details.
<structure name="PaginationInfo" ref-name="PaginationInfo">
<property name="page" required-for="response" type="integer" example-value="1"/>
<property name="per_page" required-for="response" type="integer" example-value="10"/>
<property name="count" required-for="response" type="integer" example-value="150"/>
<property name="more_records" required-for="response" type="boolean"/>
</structure>
5.7.2 Adding Pagination to the GET /users Endpoint
Now, we update our user retrieval endpoint to include pagination.
<url path="/user-management/1.0.0/users">
<operation category="read" method="get" name="Get Users">
<error condition="RESPONSE:$.status >= 400" />
<response status="200">
<content>
<encode type="application/json" />
<structure name="ResponseWrapper">
<property name="status" type="string" values="success" required-for="all" />
<property name="response" type="collections" required-for="all">
<structure-ref name="User" />
</property>
<property name="info" type="map" required-for="all">
<structure-ref name="PaginationInfo" />
</property>
</structure>
</content>
</response>
<authentication location="header" name="Authorization" schema="OAuth2Flow" scopes="USER_MANAGEMENT.users.READ" type="oauth2" />
</operation>
</url>
Our GET endpoint now returns a paginated response, including page, per_page, count, and more_records.
5.8 Generating and Running the Server Stub for the User Management API
Once we have fully defined our API in ZSPEC, we need to generate a server stub and deploy it so that clients can use it. Zoho Catalyst allows us to export a ZSPEC file as a server stub, serverless function, or SDK.
For this guide, we will be using a server stub.
5.8.1 Exporting the Spring Boot Server Stub from Zoho Catalyst
- Open the ZSPEC file you want to generate a server stub for.
- Click on the export icon and select Server Stub > Spring.
- Wait for the generation to finish.
- Download the generated code.
Note:
The downloaded server stub is not fully implemented. Database logic, business logic, and user storage are missing, meaning you must manually implement them. The better and more descriptive your ZSPEC file is, the better the generated codes.
The downloaded project only contains the src folder. To make it a fully functional Spring Boot project, you need to:
- Replace the src folder in a new Spring Boot project (created via Spring Initializr).
- Add missing dependencies in pom.xml or build.gradle.
- Manually implement the missing logic
- Now you can start the Spring Boot server with the command below:
mvn spring-boot:run
./gradlew bootRun
If your setup is error-free, your project should run this way:
5.9 Testing the API in Postman
5.9.1 Get All Users (GET /users)
Send a GET request to:
http://localhost:8080/user-management/1.0.0/users
The response should be an empty list initially.
{
"users": [
{
"username": "johndoe",
"email": "johndoe@example.com",
"role": "User"
}
]
}
The response should confirm the user was created.
You can test the PUT and DELETE endpoints this same way. Thanks for staying to this point!
6. Conclusion
Zoho Catalyst ZEST makes API development easier by handling many complex tasks, like request validation and authentication. Instead of writing everything from scratch, you can define your API using ZSPEC, and ZEST will generate a structured server stub for you.
In this guide, we built a User Management API, covering everything from defining resources and setting up authentication to implementing pagination and testing in Postman. With ZEST, you can create scalable and secure APIs faster while following best practices.
Now that you understand how ZEST works, you’re ready to start building your own APIs with Zoho Catalyst ZEST—efficiently and with less effort.