# Your Own Code - a First Custom API

> Write your first custom API in API Maker - one function behind a URL. Set its name, path and method, write the code with the global object g, save it, test it in API Testing, and call it from your app. Then see where else your code can run.

Source: https://docs.apimaker.dev/v4/docs/getting-started/first-custom-api.html

The ready-made APIs read and write your tables. When you need more, like a report, a total, or a call to another service, you write a **custom API** : one function behind a URL. You write it in the admin panel, and it works as soon as you save it. There is nothing to build or deploy.

> **In short**
>
> - A custom API has two parts : **Basic Info** (its name, path, method, and who may call it) and **Code** (one function).
> - Your function gets one object, `g` : the request in `g.req`, your databases in `g.sys.db`.
> - What the function returns is the answer. Save it, then press **Test**.

- Video: [Your First Custom API: From a Function to a Live Endpoint](https://apimaker.dev/videos/first-custom-api) (5 min)

## 1. Add a custom API

Open **APIs & Logic → Custom API**, then press **+** (Add New). The dialog has three tabs : **Basic Info**, **Code** and **Docs**.

[![A new custom API : its name, path, method and access in the Basic Info tab](https://docs.apimaker.dev/assets/images/screens/ca-dialog.webp)](https://docs.apimaker.dev/assets/images/screens/ca-dialog.webp)

1. Tabs : **Basic Info**, **Code**, **Docs**.
2. Its name, its path, its method, who may call it.

**Basic Info** says where the API answers and who may call it. It is a few lines of TypeScript. Write these :

**Basic Info**

```typescript
import * as T from 'types';

let customApi: T.ICustomApiSettingsTypes = {
    name: 'Top Products',
    path: '/top-products',
    requestMethod: T.ERequestMethod.GET,
    apiAccessType: T.EAPIAccessType.TOKEN_ACCESS,   // callers need a token
    errorList: [],
};
module.exports = customApi;
```

## 2. Write the code

Open the **Code** tab. The language is TypeScript : you can pick another one above the editor.

[![The Code tab of a custom API : the language picker and the code of the function](https://docs.apimaker.dev/assets/images/screens/ca-code.webp)](https://docs.apimaker.dev/assets/images/screens/ca-code.webp)

1. The language and its runtime : TypeScript is the default.
2. Your function. `g` brings the request and every API of API Maker.

Write a function named `main`. It reads the most expensive products of the sample shop, and returns their names and prices :

**Code**

```typescript
import * as T from 'types';

async function main(g: T.IAMGlobal) {
    const limit = Number(g.req.query.limit || 5);          // ?limit=3 in the URL

    const products = await g.sys.db.query({
        instance: 'mongodb', database: 'shop', collection: 'products',
        find: { is_active: true },
        sort: '-price_cents',                              // most expensive first
        limit: limit,
    });

    g.logger.log(`${products.length} products read`);
    return products.map((p: any) => ({ name: p.name, price: p.price_cents / 100, currency: p.currency }));
}
module.exports = main;
```

Type `g.` in the editor : it lists what `g` holds. It also knows your instances, tables and fields, and completes them as you type.

## 3. Save and test

Press **Save**. Your API shows in the tree of the page. Press its **Test** button.

[![The new custom API in the tree of the Custom API page, with its Test button](https://docs.apimaker.dev/assets/images/screens/ca-tree.webp)](https://docs.apimaker.dev/assets/images/screens/ca-tree.webp)

1. Your custom API, in its folder.
2. **Test** opens it in API Testing.

**API Testing** opens on your API. Press **SEND**.

[![The custom API in API Testing : SEND and its answer](https://docs.apimaker.dev/assets/images/screens/ca-test.webp)](https://docs.apimaker.dev/assets/images/screens/ca-test.webp)

1. **SEND** calls it.
2. The status and the time it took.
3. What your function returned.

The answer is what `main` returned, inside the usual envelope : `{ "success": true, "statusCode": 200, "data": [ … ] }`. The **Logs** tab shows what `g.logger.log` wrote. Change the code, press **Save Code**, and press **SEND** again : the new code answers at once.

## 4. Call it from your app

The URL of a custom API is `/api/custom-api/<account>/<path>` :

```bash
curl -s "$AM/api/custom-api/admin/top-products?limit=3" \
  -H "x-am-authorization: $TOKEN"
```

The token is the one of [step 6 of Your first API](https://docs.apimaker.dev/v4/docs/getting-started/first-api.html#6-call-it-from-your-app).

## Where else your code can run

A custom API runs when an app calls its URL. Your code can also run at other moments :

| Code | It runs | Example |
|---|---|---|
| [Pre hook](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html) | before an API | keep a person to their own rows |
| [Post hook](https://docs.apimaker.dev/v4/docs/apis-all/hooks/postHook-api.html) | after an API | hide a field in the answer |
| [Event](https://docs.apimaker.dev/v4/docs/apis-all/events/user-created-events-api.html) | after something happened | an order is saved : send an email |
| [Scheduler](https://docs.apimaker.dev/v4/docs/apis-all/schedulers/user-created-schedulers-api.html) | on a timer | every night : clean old carts |
| [WebSocket event](https://docs.apimaker.dev/v4/docs/pages/web-socket-event-page.html) | when your apps should hear of a change | a new order shows live on a screen |
| [Utility class](https://docs.apimaker.dev/v4/docs/utility-class/utility-class.html) | when your other code calls it | a price calculation used by ten APIs |
| [Test case](https://docs.apimaker.dev/v4/docs/test-cases/test-cases.html) | when you run the tests | check that Top Products answers |

## In another language

TypeScript, Python, PHP, C#, Go, Rust, Java and Kotlin all work. Pick the language above the editor : it offers a template. The [Hello world](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html#hello-world) of the custom APIs page shows the same function in all eight.

More : [Custom APIs](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html) (every setting, files, errors) · [the global object g](https://docs.apimaker.dev/v4/docs/pre-defined-terms/global-object-g.html) · [code examples](https://docs.apimaker.dev/v4/examples/index.html).
