Tangled business logic is a silent killer of productivity. As applications grow, core processes like calculating orders, validating users, or generating reports become scattered, duplicated, and difficult to maintain. What if you could capture each piece of business logic in a clean, reusable, and independently deployable unit?
Welcome to function.do. We believe in transforming complex business logic into atomic functions—discrete, single-purpose building blocks that you can execute as simple API endpoints and compose into powerful, automated services.
This tutorial will guide you, step-by-step, to write, deploy, and execute your first atomic function using TypeScript. In just a few minutes, you'll have a live piece of business logic running as a secure, callable API.
Before we dive in, let's clarify what we're building. While similar to a standard serverless function, a function.do agent is designed specifically for business composition.
Think of it as a reusable contract for a piece of work. Each function you deploy is:
Our goal is to treat business logic as a first-class citizen—a Business Logic API you can build, version, and share.
We'll create a simple but practical function: calculateOrderTotal. This function will take a list of items and a tax rate, then return the subtotal, tax, and final total.
First, let's create a new directory for our project and install the necessary dependencies.
# Create and enter the new project directory
mkdir my-first-function
cd my-first-function
# Initialize a Node.js project
npm init -y
# Install the function.do SDK
npm install @do-sdk/core
# Add TypeScript as a development dependency
npm install -D typescript @types/node
# Create a default tsconfig.json file
npx tsc --init
Now for the fun part. Create a new file src/order-calculator.ts and paste the following code. This is the core of your atomic function.
import { Agent, property } from '@do-sdk/core';
// Define the structure for a line item in an order
interface LineItem {
  productId: string;
  quantity: number;
  unitPrice: number;
}
// Create an agent that encapsulates the 'calculateOrderTotal' function
export class OrderCalculator extends Agent {
  
  @property()
  async calculateOrderTotal(
    items: LineItem[], 
    taxRate: number
  ): Promise<{ subtotal: number; tax: number; total: number }> {
    
    // Calculate the subtotal from the items
    const subtotal = items.reduce(
      (acc, item) => acc + item.quantity * item.unitPrice, 0
    );
    // Calculate tax and the final total
    const tax = subtotal * taxRate;
    const total = subtotal * tax;
    // Return the detailed breakdown
    return { subtotal, tax, total };
  }
}
Let's break this down:
With your logic defined, deploying it is a single command. The .do CLI handles the bundling, containerization, and deployment, turning your code into a live API endpoint.
# Authenticate with the .do platform (first time only)
do login
# Deploy your agent
do deploy ./src/order-calculator.ts
That's it! Your OrderCalculator is now live, versioned, and ready to be executed. The platform provides you with a unique endpoint for your new function.
Your business logic is now a fully-fledged API. You can call it from any application, script, or even another function. Here's how to execute it using curl.
curl -X POST https://api.function.do/your-username/order-calculator/calculateOrderTotal \
-H "Content-Type: application/json" \
--data '{
    "items": [
        { "productId": "prod_123", "quantity": 2, "unitPrice": 29.99 },
        { "productId": "prod_456", "quantity": 1, "unitPrice": 99.99 }
    ],
    "taxRate": 0.08
}'
You will get a clean JSON response with the result of your calculation:
{
  "subtotal": 159.97,
  "tax": 12.7976,
  "total": 172.7676
}
Congratulations! You have successfully built and deployed a piece of atomic, reusable business logic.
You didn't just build a serverless function; you built a reusable component.
Now, you can create other functions—like processPayment or sendOrderConfirmationEmail—that call OrderCalculator as part of a larger business workflow. This is the power of composability. Instead of rewriting logic, you build complex services by snapping together simple, reliable blocks.
Ready to stop wrestling with monolithic code and start building a clean, composable Function as a Service ecosystem?
Sign up for function.do for free and deploy your first function today!