# node:util

O módulo `node:util` reúne as funções auxiliares do Node.js para tarefas comuns com dados: formatar strings, inspecionar objetos para depuração, converter funções no estilo callback em promises e verificar tipos de valores em tempo de execução. O Azion Runtime oferece suporte ao módulo por meio da compatibilidade com Node.js. Dentro de uma function, use `util.promisify()` para adaptar código baseado em callbacks a `async`/`await` e `util.inspect()` para registrar dados estruturados no log.

---

## Exemplos

Cada exemplo é uma function completa que importa `util` de `node:util`. A resposta abaixo de cada exemplo é a que uma function com deploy feito retorna.

### Promisify e inspect

Esta function converte uma função no estilo callback em uma promise, aguarda a promise e registra o resultado no log com `util.inspect()`:

```javascript
/**
 * An example of using Node.js Util API in an Azion Function.
 * Support:
 * - Partially supported (Extended by library `util`)
 * @module runtime-apis/nodejs/util/main
 * @example
 * // Build and run with the Azion CLI:
 * azion build
 * azion dev
 */
import util from "node:util";

const myTest = (callback) => {
  try {
    callback(null, "Success!");
  } catch (err) {
    callback(err);
  }
};

/**
 * An example of using the Node.js Util API in an Azion Function.
 * @param {*} event
 * @returns {Promise<Response>}
 */
const main = async (event) => {
  const promisifyTest = util.promisify(myTest);
  const result = await promisifyTest();
  console.log(util.inspect(result, { showHidden: false, depth: null }));

  return new Response("Done!", { status: 200 });
};

export default main;
```

A function registra `"Success!"` no log e responde com:

```text
Done!
```

### Conversão de callback em promise

Esta function encapsula uma API baseada em callbacks com `util.promisify()` e a chama duas vezes com `await`:

```javascript
import util from "node:util";
import { setTimeout } from "node:timers";

// Simulate a callback-based API
const fetchData = (id, callback) => {
  setTimeout(() => {
    if (id > 0) {
      callback(null, { id, data: `Item ${id}`, timestamp: Date.now() });
    } else {
      callback(new Error("Invalid ID"));
    }
  }, 100);
};

// Convert to promise-based
const fetchDataAsync = util.promisify(fetchData);

const main = async (event) => {
  try {
    // Now can use with async/await
    const result1 = await fetchDataAsync(1);
    const result2 = await fetchDataAsync(2);

    console.log("Result 1:", result1);
    console.log("Result 2:", result2);

    return new Response(JSON.stringify({ results: [result1, result2] }), {
      headers: { "Content-Type": "application/json" }
    });
  } catch (error) {
    console.error("Error:", error.message);
    return new Response(JSON.stringify({ error: error.message }), {
      status: 400,
      headers: { "Content-Type": "application/json" }
    });
  }
};

export default main;
```

A function responde com os dois resultados:

```json
{"results":[{"id":1,"data":"Item 1","timestamp":1767268800000},{"id":2,"data":"Item 2","timestamp":1767268800000}]}
```

Os dois timestamps são iguais porque, em uma function após o deploy, `Date.now()` não avança durante uma requisição.

### Inspeção profunda de objetos

Esta function inspeciona os detalhes da requisição e um objeto aninhado, e monta uma string com `util.format()`:

```javascript
import util from "node:util";

const main = async (event) => {
  // Complex object to inspect
  const requestInfo = {
    url: event.request.url,
    method: event.request.method,
    headers: Object.fromEntries(event.request.headers),
    timestamp: new Date().toISOString()
  };

  // Nested object
  const complexData = {
    level1: {
      level2: {
        level3: {
          value: "deep",
          array: [1, 2, { nested: true }]
        }
      }
    }
  };

  // Inspect with options
  const inspected = util.inspect(requestInfo, {
    depth: null,        // Unlimited depth
    colors: false,      // Explicitly disabled since output goes into JSON response
    compact: false,     // Multi-line output
    showHidden: false,  // Don't show non-enumerable
    maxArrayLength: 10  // Limit array display
  });

  console.log("Request info:", inspected);

  // Format string with placeholders
  const formatted = util.format(
    "Request %s to %s at %s",
    requestInfo.method,
    requestInfo.url,
    requestInfo.timestamp
  );
  console.log(formatted);

  return new Response(JSON.stringify({
    requestInfo,
    formatted,
    inspectedDepth: util.inspect(complexData, { depth: 2 })
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

Para uma requisição `GET` a `https://example.com/`, a function responde com os detalhes da requisição, a string formatada e o objeto inspecionado:

```json
{"requestInfo":{"url":"https://example.com/","method":"GET","headers":{"accept":"*/*","cdn-loop":"azion.com; steps=1","host":"example.com","user-agent":"curl/8.7.1","x-forwarded-for":"192.0.2.10","x-forwarded-source-port":"6109"},"timestamp":"2026-01-01T12:00:00.000Z"},"formatted":"Request GET to https://example.com/ at 2026-01-01T12:00:00.000Z","inspectedDepth":"{\n  \"level1\": {\n    \"level2\": {\n      \"level3\": {\n        \"value\": \"deep\",\n        \"array\": [\n          1,\n          2,\n          {\n            \"nested\": true\n          }\n        ]\n      }\n    }\n  }\n}"}
```

No Azion Runtime, `util.inspect()` imprime `complexData` como texto JSON indentado, com todos os níveis expandidos, embora a chamada passe `depth: 2`.

### Formatação de strings e descontinuação

Esta function formata strings com placeholders, marca uma função como obsoleta com `util.deprecate()` e a chama:

```javascript
import util from "node:util";

// Mark a function as deprecated
const oldFunction = util.deprecate(
  () => "This is the old function",
  "oldFunction is deprecated. Use newFunction instead."
);

const newFunction = () => "This is the new function";

const main = async (event) => {
  const results = [];

  // String formatting with %s, %d, %j, %%
  results.push(util.format("Hello %s!", "World"));
  results.push(util.format("Number: %d, String: %s", 42, "test"));
  results.push(util.format("JSON: %j", { key: "value" }));
  results.push(util.format("Percent: %%"));

  // Style strings (for console output)
  // Note: ANSI codes are only meaningful in terminal output
  // They will appear as escape sequences in HTTP responses
  const styled = util.format(
    "%s %s %s",
    "\x1b[31mRed\x1b[0m",
    "\x1b[32mGreen\x1b[0m",
    "\x1b[34mBlue\x1b[0m"
  );
  console.log(styled); // Useful in logs only

  // Call the deprecated function and its replacement
  const oldResult = oldFunction();
  const newResult = newFunction();

  // Get object's own property names
  const obj = { a: 1, b: 2, c: 3 };
  const keys = Object.keys(obj);

  return new Response(JSON.stringify({
    formattedStrings: results,
    oldFunctionResult: oldResult,
    newFunctionResult: newResult,
    objectKeys: keys
    // Note: styled string not included - ANSI codes not useful in JSON
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

A function responde com as strings formatadas e o resultado de cada função:

```json
{"formattedStrings":["Hello World!","Number: 42, String: test","JSON: {\"key\":\"value\"}","Percent: %"],"oldFunctionResult":"This is the old function","newFunctionResult":"This is the new function","objectKeys":["a","b","c"]}
```

Os placeholders `%s`, `%d`, `%j` e `%%` funcionam como o exemplo mostra. O placeholder `%i` não é substituído: `util.format()` mantém `%i` na saída como foi escrito.

---

## APIs suportadas

A tabela lista o status de cada API de `node:util` no Azion Runtime:

| API                               | Status                        |
| --------------------------------- | ----------------------------- |
| `util.promisify()`                | 🟢 Com suporte                |
| `util.inspect()`                  | 🟢 Com suporte                |
| `util.format()`                   | 🟢 Com suporte                |
| `util.deprecate()`                | 🟢 Com suporte                |
| `util.isDeepStrictEqual()`        | 🟢 Com suporte                |
| `util.inherits()`                 | 🟡 Obsoleta (use classes ES6) |
| `util.callbackify()`              | 🟡 Parcialmente suportado     |
| `util.formatWithOptions()`        | 🟡 Parcialmente suportado     |
| `util.getSystemErrorMap()`        | 🟡 Parcialmente suportado     |
| `util.getSystemErrorName()`       | 🟡 Parcialmente suportado     |
| `util.log()`                      | 🟡 Parcialmente suportado     |
| `util.stripVTControlCharacters()` | 🟡 Parcialmente suportado     |
| `util.styleText()`                | 🟡 Parcialmente suportado     |
| `util.types.isDate()`             | 🟢 Com suporte                |
| `util.types.isRegExp()`           | 🟢 Com suporte                |
| `util.types.isPromise()`          | 🟢 Com suporte                |
| `util.types.isArrayBuffer()`      | 🟢 Com suporte                |
| `util.types.isNativeError()`      | 🔴 Sem suporte                |
| `util.types.isTypedArray()`       | 🟢 Com suporte                |
| `util.types.isMap()`              | 🟢 Com suporte                |
| `util.types.isSet()`              | 🟢 Com suporte                |
| `util.types.isCryptoKey()`        | 🟢 Com suporte                |
| `util.types.isKeyObject()`        | 🟢 Com suporte                |

As APIs marcadas como 🟡 Parcialmente suportado têm funcionalidade limitada em comparação com a implementação completa do Node.js.

`util.types` verifica o tipo de um valor em tempo de execução, como alternativa a `instanceof`. `util.types.isDate()`, `util.types.isPromise()` e `util.types.isRegExp()` retornam `true` para um valor correspondente. `util.types.isNativeError()` lança `Error: [unenv] util.types.isNativeError is not implemented yet!` em uma function após o deploy e com `azion dev`.

O Node.js considera `util.inherits()` obsoleta desde a v5.0.0; use a sintaxe `class` com `extends`. No Azion Runtime, `EventEmitter` de `node:events` é uma classe, então uma função construtora que chama `EventEmitter.call(this)` para herdar dela lança `TypeError: Class constructor e cannot be invoked without 'new'`.

---

## Recursos relacionados

- [APIs do Node.js](/pt-br/documentacao/devtools/runtime/node.md): O status de cada módulo do Node.js no Azion Runtime, incluindo `util`.
- [Use APIs do Node.js com polyfills](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/functions-e-runtime/use-polyfills.md): Como o build transforma imports `node:` em código que é executado no Azion Runtime.
- [node:events](/pt-br/documentacao/devtools/runtime/node/events.md): A classe `EventEmitter`, para estender com a sintaxe `class` em vez de `util.inherits()`.
- [Documentação de util do Node.js](https://nodejs.org/api/util.html): A referência completa do Node.js para cada API de `node:util` da tabela.
