In modern development, our applications are less like monoliths and more like bustling hubs, constantly communicating with a web of third-party services via APIs. From sending an email to processing a payment or updating a CRM, API calls are the lifeblood of our business processes.
But this constant communication comes with a hidden cost. Directly integrating API calls into your application code creates brittleness, duplicates effort, and leaves you blind when things go wrong.
What if you could treat every external API call not as a fragile line of code, but as a robust, versioned, and observable service?
With action.do, you can. This guide will show you how to wrap any API call into a reusable, atomic action, transforming your integrations from a liability into a library of reliable building blocks.
At first glance, using a library like axios or fetch to call an API seems simple enough. But as your application scales, this approach reveals its weaknesses:
This is where action.do introduces a paradigm shift.
action.do encourages you to stop thinking of an API call as a simple function and start treating it as a first-class, managed component of your system.
By wrapping an API call in an action.do action, you gain a powerful abstraction layer. Instead of your application talking directly to a dozen different external APIs, it talks to one consistent interface: the action.do platform.
This provides immediate benefits:
Let's walk through a practical example. We want to wrap an API call to an email service provider (like Mailgun or SendGrid) into a reusable send-welcome-email action.
First, we define the action's interface. What inputs does it need, and what will it output?
Next, you'll write the script that action.do executes. This script receives the inputs, performs the API call, and returns the outputs. The platform handles securely injecting secrets like your API key.
// This is the core logic for your action.
// It could be JavaScript, Python, or even a shell script.
async function handler({ inputs, secrets }) {
// 1. Get user email from your database using the userId
const user = await db.users.find(inputs.userId);
const userEmail = user.email;
// 2. Make the API call to your email provider
const response = await fetch('https://api.mailservice.com/v3/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${secrets.MAIL_SERVICE_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: userEmail,
from: 'welcome@yourapp.com',
template: inputs.template
})
});
const data = await response.json();
if (!response.ok) {
// If the API call fails, throwing an error will
// trigger the action.do retry and failure logic.
throw new Error(data.message);
}
// 3. Return the defined outputs
return {
status: data.status,
messageId: data.id
};
}
Once your action is defined and deployed on the action.do platform, executing it from your application code becomes incredibly simple and clean.
Using the action.do SDK, you just call the action by name.
import { DotDo } from '@do-platform/sdk';
const client = new DotDo({ apiKey: 'YOUR_API_KEY' });
// Execute our predefined action, 'send-welcome-email'
async function sendWelcomeEmail(userId: string) {
try {
const result = await client.action('send-welcome-email').execute({
userId: userId,
template: 'new-user-template-2024',
});
console.log(`Action completed with status: ${result.status}`);
console.log(`Track email with ID: ${result.outputs.messageId}`);
return result;
} catch (error) {
console.error(`Action 'send-welcome-email' failed:`, error);
}
}
Look at the beauty of this. Your main application code is completely shielded from the complexities of the email API. It performs one, reliable, auditable task. If you ever switch email providers, you only update the action's script—your application code doesn't change at all.
The true power of action.do is realized when you start composing these atomic actions into larger agentic workflows. Because each action is a standardized, reliable building block, you can chain them together with an orchestrator (like workflow.do) to automate complex business processes.
An onboarding workflow could look like this:
Each step is atomic, auditable, and resilient. If the CRM update fails, the system can retry it independently without affecting the other steps, and the entire workflow's state is visible on a central dashboard.
Stop writing brittle, one-off integrations. Start building a library of powerful, reusable components.
Ready to make your automation flawless? Explore action.do and wrap your first API call today.
What is an 'atomic action'?
An atomic action is a single, indivisible operation that either completes successfully or fails entirely, leaving no partial state. This guarantees data integrity and reliability in your workflows.
How is action.do different from a simple function call?
action.do provides a layer of abstraction with built-in observability, retries, and audit trails. It treats actions as manageable, versioned services, making your automation more robust and transparent than a standard function.
What kind of actions can I perform with action.do?
You can define any action that can be scripted, such as making an API call, sending an email, updating a database record, interacting with a smart contract, or running a shell command.
Can actions be chained together?
Yes. action.do is designed as a fundamental building block. You can use an orchestration agent (like workflow.do) to chain multiple atomic actions together to create complex and powerful services.