Skip to content
This page View Markdown Open in ChatGPT Open in Claude

Utility classes

A utility class is code shared by all your code : helpers, validations, pricing rules, clients of external services, interfaces. Write it once on the Utility Classes page (APIs & Logic → Utility Classes), in TypeScript or in any other language API Maker runs, and use it in all the code of that language. In TypeScript you import it anywhere with utils/<Name>.

Create one

Click +, give a path (a folder to group them) and a name. The name is unique, starts with a capital letter, and is what you import.

The utility class Calculator
class Calculator {
    add(x: number, y: number) {
        return x + y;
    }
    multi(x: number, y: number) {
        return x * y;
    }
}
let temp = new Calculator();
export = temp;
A custom API which uses it
1
2
3
4
5
6
7
import * as T from 'types';
import * as calc from 'utils/Calculator';

async function main(g: T.IAMGlobal) {
    return { sum: calc.add(3, 6), product: calc.multi(3, 6) };
}
module.exports = main;
The utility class Calculator
1
2
3
4
5
6
def add(x, y):
    return x + y


def multi(x, y):
    return x * y
A custom API which uses it
1
2
3
4
5
import Calculator as calc


async def main(g):
    return {'sum': calc.add(3, 6), 'product': calc.multi(3, 6)}
The utility class Calculator
<?php
class Calculator
{
    public static function add($x, $y)
    {
        return $x + $y;
    }

    public static function multi($x, $y)
    {
        return $x * $y;
    }
}
A custom API which uses it
1
2
3
4
5
<?php
function main(AmG $g)
{
    return ['sum' => Calculator::add(3, 6), 'product' => Calculator::multi(3, 6)];
}
The utility class Calculator
1
2
3
4
5
6
public static class Calculator
{
    public static double Add(double x, double y) => x + y;

    public static double Multi(double x, double y) => x * y;
}
A custom API which uses it
1
2
3
4
5
6
7
file static class Api
{
    public static async Task<object?> Main(G g)
    {
        return new { sum = Calculator.Add(3, 6), product = Calculator.Multi(3, 6) };
    }
}
The utility class Calculator, in the folder utils
1
2
3
4
5
6
7
8
9
package calculator

func Add(x, y float64) float64 {
    return x + y
}

func Multi(x, y float64) float64 {
    return x * y
}
A custom API which uses it
package code

import (
    "apimaker/am"
    calc "apimaker/src/utility_classes/utils---Calculator"
)

func Main(g *am.G) (any, error) {
    return am.M{"sum": calc.Add(3, 6), "product": calc.Multi(3, 6)}, nil
}
The utility class Calculator
1
2
3
4
5
6
7
pub fn add(x: f64, y: f64) -> f64 {
    x + y
}

pub fn multi(x: f64, y: f64) -> f64 {
    x * y
}
A custom API which uses it
1
2
3
4
5
6
7
use am::{Errors, G, Value, json};

use crate::Calculator as calc;

pub fn main(g: &mut G) -> Result<Value, Errors> {
    Ok(json!({ "sum": calc::add(3.0, 6.0), "product": calc::multi(3.0, 6.0) }))
}
The utility class Calculator
1
2
3
4
5
6
7
8
9
public class Calculator {
    public static double add(double x, double y) {
        return x + y;
    }

    public static double multi(double x, double y) {
        return x * y;
    }
}
A custom API which uses it
1
2
3
4
5
6
7
8
import am.G;
import java.util.Map;

class Api {
    static Object main(G g) {
        return Map.of("sum", Calculator.add(3, 6), "product", Calculator.multi(3, 6));
    }
}
The utility class Calculator
1
2
3
4
5
object Calculator {
    fun add(x: Double, y: Double) = x + y

    fun multi(x: Double, y: Double) = x * y
}
A custom API which uses it
1
2
3
4
5
import am.G

fun main(g: G): Any? {
    return mapOf("sum" to Calculator.add(3.0, 6.0), "product" to Calculator.multi(3.0, 6.0))
}
  • In TypeScript the file exports an instance (export = temp), so the importer calls the methods directly. The other languages name what a class declares the way they import things : see below.
  • The class can hold state : a connection opened in a method stays for the life of the sandbox.

Use one

  • Works in custom APIs, pre and post hooks, event listeners, schedulers, migration scripts, process initializers, WebSocket connect code and test cases.
  • Press Ctrl+Space after utils/ in the editor to see every class.
  • A method which needs API Maker takes g as a parameter : Pricing.total(g, order).

The classes of a language

The list of the page has a dropdown next to its search : All languages, then each language on each of its runtimes (TypeScript on Node.js, TypeScript on Bun, Python, C# on .NET…), with how many classes each one shows. A choice shows the classes the code of that language uses, in the tree and in the grid : the classes written in TypeScript or JavaScript for Node.js and for Bun alike, the classes written in Python for Python. A class added while the list shows a language starts in that language.

On the API testing page, Show Utility Classes next to the code opens the dialog of the classes with the ones the code of the editor uses : those of its language, on its runtime. Pick All languages, or another language, in the dialog to see the others. An API without code of its own opens it with every class.

Interfaces

A utility class can export interfaces and types, for every piece of code to share (a class, a record, a struct in the other languages) :

The utility class Inf
1
2
3
4
5
6
7
8
9
class Inf {
}
let temp = new Inf();
export = temp;
export interface IUserP {
    firstName: string;
    lastName: string;
    phone: number;
}
A custom API which uses it
1
2
3
4
5
6
7
8
import * as T from 'types';
import * as inf from 'utils/Inf';

async function main(g: T.IAMGlobal) {
    const data: inf.IUserP = { firstName: 'John', lastName: 'Doe', phone: 123456789 };
    return data;
}
module.exports = main;
The utility class Inf
1
2
3
4
5
6
7
8
from dataclasses import dataclass


@dataclass
class UserP:
    firstName: str
    lastName: str
    phone: int
A custom API which uses it
1
2
3
4
5
6
7
8
from dataclasses import asdict

from Inf import UserP


async def main(g):
    data = UserP(firstName='John', lastName='Doe', phone=123456789)
    return asdict(data)
The utility class Inf
<?php
final class UserP
{
    public function __construct(
        public string $firstName,
        public string $lastName,
        public int $phone,
    ) {
    }
}
A custom API which uses it
1
2
3
4
5
<?php
function main(AmG $g)
{
    return new UserP(firstName: 'John', lastName: 'Doe', phone: 123456789);
}
The utility class Inf
public record UserP(string firstName, string lastName, long phone);
A custom API which uses it
1
2
3
4
5
6
7
file static class Api
{
    public static async Task<object?> Main(G g)
    {
        return new UserP("John", "Doe", 123456789);
    }
}
The utility class Inf, in the folder utils
1
2
3
4
5
6
7
package inf

type UserP struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Phone     int    `json:"phone"`
}
A custom API which uses it
package code

import (
    "apimaker/am"
    inf "apimaker/src/utility_classes/utils---Inf"
)

func Main(g *am.G) (any, error) {
    return inf.UserP{FirstName: "John", LastName: "Doe", Phone: 123456789}, nil
}
The utility class Inf
1
2
3
4
5
6
7
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UserP {
    pub first_name: String,
    pub last_name: String,
    pub phone: u64,
}
A custom API which uses it
1
2
3
4
5
6
7
8
use am::{Errors, G, Value};

use crate::Inf::UserP;

pub fn main(g: &mut G) -> Result<Value, Errors> {
    let data = UserP { first_name: "John".to_owned(), last_name: "Doe".to_owned(), phone: 123456789 };
    Ok(serde_json::to_value(data)?)
}
The utility class Inf
1
2
3
4
public class Inf {
    public record UserP(String firstName, String lastName, long phone) {
    }
}
A custom API which uses it
1
2
3
4
5
6
7
import am.G;

class Api {
    static Object main(G g) {
        return new Inf.UserP("John", "Doe", 123456789);
    }
}
The utility class Inf
data class UserP(val firstName: String, val lastName: String, val phone: Long)
A custom API which uses it
1
2
3
4
5
import am.G

fun main(g: G): Any? {
    return UserP("John", "Doe", 123456789)
}

In every language

Pick the language of the class in the title bar of its editor. A new class starts as a small example of the language, with a comment which says how the other code names it. Each language does it its own way, the same in a sandbox and in the Git repository :

Language The class Tax in the folder utils/ In the code
TypeScript the module utils/Tax import * as Tax from 'utils/Tax', Tax.add(100)
Python the module Tax from Tax import add
PHP what its file declares (no namespace of its own) Tax::add(100), add_tax(100), TAX_RATE
C# what its file declares, compiled with the code Tax.Add(100)
Go a package, imported by its folder import tax "apimaker/src/utility_classes/utils---Tax"
Rust the module Tax of the crate of the code use crate::Tax::add;
Java the class Tax, compiled with the other classes of Java Tax.add(100)
Kotlin what its file declares (it starts as an object Tax), compiled with the other classes of Kotlin Tax.add(100.0)
The utility class Tax
export const RATE = 0.2;

export function add(amount: number): number {
    return Math.round(amount * (1 + RATE) * 100) / 100;
}
A custom API
import * as T from 'types';
import * as Tax from 'utils/Tax';

async function main(g: T.IAMGlobal) {
    return { total: Tax.add(g.req.body.amount) };
}
module.exports = main;
The utility class Tax
RATE = 0.2


def add(amount):
    return round(amount * (1 + RATE), 2)
A custom API
from Tax import add


async def main(g):
    return {"total": add(g.req.body.amount)}
The utility class Tax
<?php
const TAX_RATE = 0.2;

class Tax
{
    public static function add($amount)
    {
        return round($amount * (1 + TAX_RATE), 2);
    }
}
A custom API
<?php
function main($g)
{
    return ['total' => Tax::add($g->req->body->amount)];
}
The utility class Tax
public static class Tax
{
    public const double Rate = 0.2;

    public static double Add(double amount) => Math.Round(amount * (1 + Rate), 2);
}
A custom API
file static class Api
{
    public static async Task<object?> Main(G g)
    {
        return new { total = Tax.Add(g.Req.Body.GetDouble("amount")) };
    }
}
The utility class Tax, in the folder utils
package tax

import "math"

var Rate = 0.2

func Add(amount float64) float64 {
    return math.Round(amount*(1+Rate)*100) / 100
}
A custom API
package code

import (
    "apimaker/am"
    tax "apimaker/src/utility_classes/utils---Tax"
)

func Main(g *am.G) (any, error) {
    return am.M{"total": tax.Add(g.Req.Body().Float("amount"))}, nil
}
The utility class Tax
pub const RATE: f64 = 0.2;

pub fn add(amount: f64) -> f64 {
    (amount * (1.0 + RATE) * 100.0).round() / 100.0
}
A custom API
use am::{Errors, G, Value, json};

use crate::Tax;

pub fn main(g: &mut G) -> Result<Value, Errors> {
    Ok(json!({ "total": Tax::add(g.req.body()["amount"].as_f64().unwrap_or(0.0)) }))
}
The utility class Tax
public class Tax {
    public static final double RATE = 0.2;

    public static double add(double amount) {
        return Math.round(amount * (1 + RATE) * 100) / 100.0;
    }
}
A custom API
import am.G;
import java.util.Map;

class Api {
    static Object main(G g) {
        return Map.of("total", Tax.add(g.req.getBody().getDouble("amount")));
    }
}
The utility class Tax
object Tax {
    const val RATE = 0.2

    fun add(amount: Double): Double = Math.round(amount * (1 + RATE) * 100) / 100.0
}
A custom API
import am.G

fun main(g: G): Any? = mapOf("total" to Tax.add(g.req.body.getDouble("amount")))
  • A class is used by the code of its own language; code of another language reaches what it does through a custom API.
  • A class which is saved is what the next request runs with : nothing restarts.
  • The rules of names, what a class keeps between requests, and how the repository resolves the same imports are on Languages and runtimes.
  • Declarations for the editors (utils/ and Ctrl+Space) and interfaces are for the classes written in TypeScript. The coverage of test runs counts the lines of the classes of every language.

Versions

A utility class has versions and one active version. The code which imports it always gets the active one, at once, without a restart. Keep the old version until the new one has proven itself, and switch back in one click.

Testing

A test case imports the class the way custom APIs do and calls its methods, with mocks for the g.sys calls it makes and coverage of its lines.

Good to know

  • Utility classes are files in Git under src/utility_classes/ and deploy with a pull.
  • A utility class runs where its importer runs : in the sandbox, or on the native process for a native custom API.
  • A new account comes with a sample utility class to read.