# The Global Object g

> Everything your code gets in API Maker through g - the request (headers, params, query, body, auth, event data), the response (status, content type, output, headers, errors), g.sys for the database, system and cache APIs, the logger and the shared space.

Source: https://docs.apimaker.dev/v4/docs/pre-defined-terms/global-object-g.html

Every piece of code you write in API Maker, a custom API, a hook, an event listener, a scheduler, a migration, a process initializer, a test case, is a function of one argument, `g`. In TypeScript :

**TypeScript**

```typescript
import * as T from 'types';
import * as db from 'db-interfaces';

async function main(g: T.IAMGlobal) {
    const rows = await g.sys.db.getAll<db.mongodb.shop.IProducts>({ instance: 'mongodb', database: 'shop', collection: 'products' });
    g.logger.log(rows.length, 'products');
    return rows;
}
module.exports = main;
```

**Python**

```python
from am import G


async def main(g: G):
    rows = await g.sys.db.get_all('mongodb', 'shop', 'products')
    g.logger.log(len(rows), 'products')
    return rows
```

**PHP**

```php
<?php
function main(AmG $g)
{
    $rows = $g->sys->db->getAll('mongodb', 'shop', 'products');
    $g->logger->log(count($rows), 'products');
    return $rows;
}
```

**C#**

```csharp
file static class Api
{
    public static async Task<object?> Main(G g)
    {
        var rows = await g.Sys.Db.GetAll(new GetAll("mongodb", "shop", "products"));
        g.Logger.Log(rows.Count, "products");
        return rows;
    }
}
```

**Go**

```go
package code

import "apimaker/am"

func Main(g *am.G) (any, error) {
	rows, err := g.Sys.Db.GetAll(am.GetAll{Instance: "mongodb", Database: "shop", Collection: "products"})
	if err != nil {
		return nil, err
	}
	g.Logger.Log(len(rows), "products")
	return rows, nil
}
```

**Rust**

```rust
use am::{Errors, G, GetAll, Value, json};

pub fn main(g: &mut G) -> Result<Value, Errors> {
    let rows = g.sys.db.get_all(GetAll::new("mongodb", "shop", "products"))?;
    g.logger.log(format!("{} products", rows.len()));
    Ok(json!(rows))
}
```

**Java**

```java
import am.G;
import am.GetAll;
import am.JsonObject;
import java.util.List;

class Api {
    static Object main(G g) {
        List<JsonObject> rows = g.sys.db.getAll(new GetAll("mongodb", "shop", "products"));
        g.logger.log(rows.size(), "products");
        return rows;
    }
}
```

**Kotlin**

```kotlin
import am.G
import am.GetAll

fun main(g: G): Any? {
    val rows = g.sys.db.getAll(GetAll("mongodb", "shop", "products"))
    g.logger.log(rows.size, "products")
    return rows
}
```

| | |
|---|---|
| `g.req` | What came in : headers, params, query, body, event data, the opened tokens. |
| `g.res` | What goes out : status code, content type, output, headers, errors, warnings. |
| `g.sys` | The APIs of API Maker from code : `db`, `db.gen`, `system`, `cache`, and `test` inside a test case. |
| `g.logger` | `debug`, `log`, `info`, `warn`, `error` : shown with the response on the testing pages, kept by the [log profiles](https://docs.apimaker.dev/v4/docs/logs/logs-and-dashboards.html#log-profiles). |
| `g.shared` | Values every request of the same runner shares, for as long as it runs : a cache, a counter. |

## In every language

Custom APIs, hooks, schedulers and event listeners can also be written in [Python, PHP, C#, Go, Rust, Java and Kotlin](https://docs.apimaker.dev/v4/docs/languages/index.html). They get the same `g`, in the words of their language :

| | Request | Answer | Database | Logger | Shared | Refuse |
|---|---|---|---|---|---|---|
| TypeScript | `g.req.body.id` | `g.res.statusCode = 201` | `await g.sys.db.getAll({…})` | `g.logger.log('a')` | `g.shared.n` | `throw [{ code: 400, message }]` |
| Python | `g.req.body.id` | `g.res.status_code = 201` | `await g.sys.db.get_all('mysql_8', 'inventory', 'customers', limit=10)` | `g.logger.log('a')` | `g.shared.get('n')` | `raise g.Errors(message, code=400)` |
| PHP | `$g->req->body->id` | `$g->res->statusCode = 201` | `$g->sys->db->getAll('mysql_8', 'inventory', 'customers', limit: 10)` | `$g->logger->log('a')` | `$g->shared->n` | `throw new AmErrors($message, 400)` |
| C# | `g.Req.Body["id"]` | `g.Res.StatusCode = 201` | `await g.Sys.Db.GetAll(new GetAll("mysql_8", "inventory", "customers") { Limit = 10 })` | `g.Logger.Log("a")` | `g.Shared.GetValueOrDefault("n")` | `throw new AmErrors(message, 400)` |
| Go | `g.Req.Body().Get("id")` | `g.Res.SetStatusCode(201)` | `g.Sys.Db.GetAll(am.GetAll{Instance: "mysql_8", Database: "inventory", Collection: "customers", Limit: 10})` | `g.Logger.Log("a")` | `g.Shared.Get("n")` | `return nil, am.Fail(400, message)` |
| Rust | `g.req.body()["id"]` | `g.res.set_status_code(201)` | `g.sys.db.get_all(GetAll::new("mysql_8", "inventory", "customers").limit(10))?` | `g.logger.log("a")` | `g.shared.get("n")` | `Err(am::fail(400, message))` |
| Java | `g.req.getBody().get("id")` | `g.res.setStatusCode(201)` | `g.sys.db.getAll(new GetAll("mysql_8", "inventory", "customers").limit(10))` | `g.logger.log("a")` | `g.shared.get("n")` | `throw new AmErrors(message, 400)` |
| Kotlin | `g.req.body["id"]` | `g.res.statusCode = 201` | `g.sys.db.getAll(GetAll("mysql_8", "inventory", "customers").limit(10))` | `g.logger.log("a")` | `g.shared["n"]` | `throw AmErrors(message, 400)` |

Each language page has the full reference and examples : [TypeScript](https://docs.apimaker.dev/v4/docs/languages/typescript.html) · [Python](https://docs.apimaker.dev/v4/docs/languages/python.html) · [PHP](https://docs.apimaker.dev/v4/docs/languages/php.html) · [C#](https://docs.apimaker.dev/v4/docs/languages/csharp.html) · [Go](https://docs.apimaker.dev/v4/docs/languages/go.html) · [Rust](https://docs.apimaker.dev/v4/docs/languages/rust.html) · [Java](https://docs.apimaker.dev/v4/docs/languages/java.html) · [Kotlin](https://docs.apimaker.dev/v4/docs/languages/kotlin.html).

The code editor completes `g` in each of them, and offers the columns of your tables on the rows a call answers : [the code editor in every language](https://docs.apimaker.dev/v4/docs/languages/index.html#editor).

## g.req

| Key | Holds |
|---|---|
| `headers` | The request headers, editable : a pre hook can set `x-am-content-type-response` for the whole call. |
| `params` | The path parameters : `instanceName`, `database`, `collection`, `id`, `primaryKey`, `field` and `order` of distinct, `tenantUsername` for a [multi-tenant](https://docs.apimaker.dev/v4/docs/features/multi-tenant.html) request… |
| `query` | The query parameters as an object : `find`, `select`, `limit`… editable in a pre hook, which is how [row level security](https://docs.apimaker.dev/v4/docs/authorization/handle-role-based-permissions.html) is done. |
| `body` | The body, editable. |
| `eventData` | The data of the event, in an event listener. |
| `auth` | The opened tokens : `authAMUser` (the API user), `authAMDB` (the person, from a DB auth provider), `authCustom`, `authGoogle`, `authAWS`, `authAzure`. |
| `reqInfo` | `url`, `apiCategory`, `reqMethod` and `apiInfo` (`id`, `name`, `schemaType`) : which API is running. |
| `isApiRequestFromUser` | `true` for an HTTP request, `false` for a call made from code. |

**TypeScript**

**Who is calling**

```typescript
const person = g.req.auth.authAMDB;      // the row of your users table, minus its password
const apiUser = g.req.auth.authAMUser;   // name and groups of the API user
```

**Python**

**Who is calling**

```python
person = g.req.auth.authAMDB       # the row of your users table, minus its password
api_user = g.req.auth.authAMUser   # name and groups of the API user
```

**PHP**

**Who is calling**

```php
$person = $g->req->auth->authAMDB;       // the row of your users table, minus its password
$apiUser = $g->req->auth->authAMUser;    // name and groups of the API user
```

**C#**

**Who is calling**

```csharp
var person = g.Req.Auth.GetObject("authAMDB");       // the row of your users table, minus its password
var apiUser = g.Req.Auth.GetObject("authAMUser");    // name and groups of the API user
```

**Go**

**Who is calling**

```go
person := g.Req.Auth().Map("authAMDB")    // the row of your users table, minus its password
apiUser := g.Req.Auth().Map("authAMUser") // name and groups of the API user
```

**Rust**

**Who is calling**

```rust
let person = &g.req.auth()["authAMDB"];       // the row of your users table, minus its password
let api_user = &g.req.auth()["authAMUser"];   // name and groups of the API user
```

**Java**

**Who is calling**

```java
JsonObject person = g.req.getAuth().getObject("authAMDB");       // the row of your users table, minus its password
JsonObject apiUser = g.req.getAuth().getObject("authAMUser");    // name and groups of the API user
```

**Kotlin**

**Who is calling**

```kotlin
val person = g.req.auth.getObject("authAMDB")       // the row of your users table, minus its password
val apiUser = g.req.auth.getObject("authAMUser")    // name and groups of the API user
```

## g.res

| Key | Holds |
|---|---|
| `statusCode` | `T.EStatusCode.OK` (200), `CREATED`, `NO_CONTENT`, `BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `RESOURCE_NOT_FOUND`, `INTERNAL_SERVER_ERROR`… Set by your code, it wins over the one of the API. |
| `contentType` | `T.EContentType.JSON` (default), `XML`, `YAML`, `TEXT`, `HTML`, `OCTET_STREAM`. |
| `output` | The answer. In a post hook, the answer of the API, editable. A custom API returns its output instead. |
| `headers` | Headers to add to the reply. |
| `errors`, `warnings` | The lists of the reply. |
| `shared` | Values of this request : set in a pre hook, read in the API or its post hook. |

**TypeScript**

**An HTML page from a custom API**

```typescript
g.res.contentType = T.EContentType.HTML;
return '<h1>Hello</h1>';
```

**Python**

**An HTML page from a custom API**

```python
g.res.content_type = 'text/html'
return '<h1>Hello</h1>'
```

**PHP**

**An HTML page from a custom API**

```php
$g->res->contentType = 'text/html';
return '<h1>Hello</h1>';
```

**C#**

**An HTML page from a custom API**

```csharp
g.Res.ContentType = "text/html";
return "<h1>Hello</h1>";
```

**Go**

**An HTML page from a custom API**

```go
g.Res.SetContentType("text/html")
return "<h1>Hello</h1>", nil
```

**Rust**

**An HTML page from a custom API**

```rust
g.res.set_content_type("text/html");
Ok(json!("<h1>Hello</h1>"))
```

**Java**

**An HTML page from a custom API**

```java
g.res.setContentType("text/html");
return "<h1>Hello</h1>";
```

**Kotlin**

**An HTML page from a custom API**

```kotlin
g.res.contentType = "text/html"
return "<h1>Hello</h1>"
```

- To send a file, return an object with `__am__downloadFilePath` or `__am__downloadFileOrFolderPaths` : see [files](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html#files).

## g.sys

| Part | Holds |
|---|---|
| `g.sys.db` | The [schema APIs](https://docs.apimaker.dev/v4/docs/apis-all/overview.html) of any table : `getAll`, `getById`, `query`, `saveSingleOrMultiple`, `masterSave`, `updateById`, `updateMany`, `replaceById`, `removeById`, `removeByQuery`, `aggregate`, `count`, `distinct`, `distinctQuery`, `arrayOperations`, `getAllByStream`, `queryByStream`. [Examples](https://docs.apimaker.dev/v4/examples/sys/db/getAll.html). |
| `g.sys.db.gen` | The same calls on the generated APIs, without schema : `getAllGen`, `queryGen`… [Examples](https://docs.apimaker.dev/v4/examples/sys/db/getAll.html#without-a-schema). |
| `g.sys.system` | The [system APIs](https://docs.apimaker.dev/v4/examples/sys/system/system.html) : `encrypt`, `decrypt`, `hash`, `getToken`, `getSecret`, `callExternalApi`, `executeQuery`, `getTableMeta`, `createIndexes`, `dropIndexes`, `getIndexes`, `emitEvent`, `emitEventWS`, `isValidDataForTable`, `isValidDataForCustomAPI`, `multiTenantInstanceUpdated`, `isValidConnectionString`. |
| `g.sys.cache` | Your own keys in Redis and the cache resets : `getKey`, `setKey`, `removeKey`, `resetCacheDB`, `resetCacheCustomApis`, `resetCacheSystemApis`. [Examples](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-set-redis-key-api.html#from-code). |
| `g.sys.test` | In a [test case](https://docs.apimaker.dev/v4/docs/test-cases/test-cases.html) only : `runCustomApi`, `mock`, `clearMocks`, `calls`. |

- Every `g.sys.db` call takes the same `headers` and `queryParams` an HTTP call takes, and runs with the groups of the API user of the request. Hooks are skipped unless you pass `skipHookRunning: false`.
- Pass `true` as the last argument (`getFullResponse`) in TypeScript, or call through `full` in the other languages (`g.sys.db.full.get_all` in Python, `g.Sys.Db.Full.GetAll` in C# and Go), to get the whole `{ success, data, errors, … }` envelope instead of `data`.

## g.logger and g.shared

**TypeScript**

```typescript
const order = { _id: 'A-1001' };
g.logger.log('order ', order._id);         // with the response on the testing pages, in the logs of a log profile
g.logger.error('payment failed : ', 'card declined');
g.res.shared.count = 234;                  // set in a pre hook…
const count = g.res.shared.count;          // …read in the post hook of the same request
g.shared.visits = (g.shared.visits || 0) + 1;   // kept by the runner for the requests which follow
```

**Python**

```python
order = {'_id': 'A-1001'}
g.logger.log('order', order['_id'])        # with the response on the testing pages, in the logs of a log profile
g.logger.error('payment failed :', 'card declined')
g.res.shared.count = 234                   # set in a pre hook…
count = g.res.shared.count                 # …read in the post hook of the same request
g.shared['visits'] = g.shared.get('visits', 0) + 1   # kept by the runner for the requests which follow
```

**PHP**

```php
$order = ['_id' => 'A-1001'];
$g->logger->log('order', $order['_id']);   // with the response on the testing pages, in the logs of a log profile
$g->logger->error('payment failed :', 'card declined');
$g->res->shared->count = 234;              // set in a pre hook…
$count = $g->res->shared->count;           // …read in the post hook of the same request
$g->shared->visits = ($g->shared->visits ?? 0) + 1;   // kept by the runner for the requests which follow
```

**C#**

```csharp
var order = new { _id = "A-1001" };
g.Logger.Log("order", order._id);          // with the response on the testing pages, in the logs of a log profile
g.Logger.Error("payment failed :", "card declined");
g.Res.Shared["count"] = 234;               // set in a pre hook…
var count = g.Res.Shared.GetInt64("count"); // …read in the post hook of the same request
g.Shared.AddOrUpdate("visits", 1, (_, old) => (int)old! + 1);   // kept by the runner for the requests which follow
```

**Go**

```go
order := am.M{"_id": "A-1001"}
g.Logger.Log("order", order["_id"]) // with the response on the testing pages, in the logs of a log profile
g.Logger.Error("payment failed :", "card declined")
g.Res.Shared()["count"] = 234                // set in a pre hook…
count := g.Res.Shared().Int("count")         // …read in the post hook of the same request
g.Shared.Update("visits", func(old any) any { // kept by the runner for the requests which follow
	visits, _ := old.(int)
	return visits + 1
})
```

**Rust**

```rust
let order = json!({ "_id": "A-1001" });
g.logger.log(format!("order {}", order["_id"]));   // with the response on the testing pages, in the logs of a log profile
g.logger.error("payment failed : card declined");
g.res.shared_mut()["count"] = json!(234);           // set in a pre hook…
let count = g.res.shared()["count"].as_i64();       // …read in the post hook of the same request
g.shared.update("visits", |old| json!(old.and_then(|n| n.as_i64()).unwrap_or(0) + 1));   // kept by the runner for the requests which follow
```

**Java**

```java
JsonObject order = JsonObject.of("_id", "A-1001");
g.logger.log("order", order.get("_id"));          // with the response on the testing pages, in the logs of a log profile
g.logger.error("payment failed :", "card declined");
g.res.getShared().put("count", 234);               // set in a pre hook…
long count = g.res.getShared().getLong("count");   // …read in the post hook of the same request
g.shared.merge("visits", 1, (old, one) -> (Integer) old + 1);   // kept by the runner for the requests which follow
```

**Kotlin**

```kotlin
val order = mapOf("_id" to "A-1001")
g.logger.log("order", order["_id"])           // with the response on the testing pages, in the logs of a log profile
g.logger.error("payment failed :", "card declined")
g.res.shared["count"] = 234                    // set in a pre hook…
val count = g.res.shared.getLong("count")      // …read in the post hook of the same request
g.shared.merge("visits", 1) { old, _ -> (old as Int) + 1 }   // kept by the runner for the requests which follow
```

- `debug`, `log`, `info`, `warn` and `error` write the same line : the level is not kept. Objects are printed as indented JSON. In TypeScript the arguments are joined without a separator, in the other languages with a space. The calls are synchronous, no `await`.
- For an error, log its message (`e.message` in TypeScript) or its stack.
- On the native process (`runOnNativeProcess`), `console.log` is not captured : use `g.logger`.
- `g.shared` belongs to one runner : a sandbox has several runners, and a server several sandboxes, so a value there is a cache, never the only copy of something. Values for the rest of one request go in `g.res.shared`.

## Related

- [Custom APIs](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html) · [Pre hooks](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html) · [Code examples](https://docs.apimaker.dev/v4/examples/index.html) · [Cheat sheet](https://docs.apimaker.dev/v4/docs/cheat-sheet.html)
