# Utils

O pacote `@aziontech/utils` é a biblioteca da Azion Lib de funções auxiliares para functions. Duas das funções dele respondem a uma requisição com um arquivo estático de uma single-page application (SPA) ou de uma multi-page application (MPA), e a terceira transforma uma requisição recebida em um objeto simples. As funções não fazem chamadas de API, não precisam de token e retornam o resultado diretamente.

Instale o pacote:

```bash
npm install @aziontech/utils
```

Importe as funções de `@aziontech/utils/edge`. A raiz do pacote exporta apenas dois objetos, `edge` e `node`, por isso `import { mountSPA } from '@aziontech/utils'` falha com um `SyntaxError`. Esta página não documenta a entrada `node`, `@aziontech/utils/node`.

`mountSPA` e `mountMPA` não rodam no Node.js, onde falham com `TypeError: fetch failed`, por isso os exemplos delas rodam dentro de uma function. `parseRequest` roda no Node.js e dentro de uma function. Os exemplos de function desta página são módulos JavaScript servidos localmente com o [azion dev](/pt-br/documentacao/devtools/cli/dev-comando/), e o exemplo de Node.js é um módulo ES em TypeScript que usa `await` de nível superior.

---

## Arquivos estáticos no build

`mountSPA` e `mountMPA` leem arquivos por URLs `file:///`. Dentro de uma function, essas URLs apontam para os arquivos que a configuração `build.memoryFS` do [azion.config.js](/pt-br/documentacao/devtools/cli/azion-config-js/#build) incorpora ao build. Um arquivo que o build não incorpora não pode ser servido.

Os exemplos desta página usam um projeto cuja pasta `data/` contém `index.html`, `about/index.html` e `hello.txt`. Adicione este bloco `build` ao objeto que o `azion.config.mjs` exporta, para que o build incorpore `data/`:

```javascript
build: {
  memoryFS: {
    injectionDirs: ['./data'],
    removePathPrefix: './data',
  },
},
```

`injectionDirs` indica as pastas que o build incorpora. `removePathPrefix` remove o nome da pasta do caminho de cada arquivo, por isso `data/index.html` é lido em `file:///index.html`. Com `removePathPrefix: './'`, o mesmo arquivo é lido em `file:///data/index.html`, e as funções `mount*` não o encontram.

---

## mountSPA

Responde a uma requisição para uma single-page application com um arquivo do build. Um path sem extensão de arquivo, como `/dashboard/settings`, retorna `index.html`. Um path com extensão, como `/hello.txt`, retorna esse arquivo.

```typescript
function mountSPA(requestURL: string): Promise<Response>;
```

| Parâmetro    | Tipo     | Obrigatório | Descrição                                    |
| ------------ | -------- | ----------- | -------------------------------------------- |
| `requestURL` | `string` | Sim         | A URL da requisição recebida, `request.url`. |

Retorna um `Response` que contém o arquivo. Quando o build não tem um arquivo para o path, a chamada lança um erro, `Error: ENOENT: no such file or directory`, e a function responde com status 500 e um body vazio.

Esta function responde a toda requisição com `mountSPA` e registra no log o path e o status:

```javascript
import { mountSPA } from '@aziontech/utils/edge';

export default {
  async fetch(request) {
    // Routes without a file extension get index.html; assets are fetched as they are
    const myApp = await mountSPA(request.url);
    console.log('mountSPA', new URL(request.url).pathname, '->', myApp.status);
    return myApp;
  },
};
```

Com a function servida localmente com `azion dev`, a raiz, uma rota, um arquivo e um arquivo inexistente retornam:

```text
$ curl http://localhost:3333/
HTTP/1.1 200 OK
content-type: text/html

<h1>index</h1>

$ curl http://localhost:3333/dashboard/settings
HTTP/1.1 200 OK
content-type: text/html

<h1>index</h1>

$ curl http://localhost:3333/hello.txt
HTTP/1.1 200 OK
content-type: text/plain

Hello from memoryFS

$ curl http://localhost:3333/missing.css
HTTP/1.1 500 Internal Server Error
Content-Length: 0
```

A function registra no log o status de cada requisição que ela responde e, em seguida, o erro que o arquivo inexistente gera:

```text
mountSPA / -> 200
mountSPA /dashboard/settings -> 200
mountSPA /hello.txt -> 200
Error: ENOENT: no such file or directory, open '<project-dir>/.edge/storage/missing.css'
```

---

## mountMPA

Responde a uma requisição para uma multi-page application com um arquivo do build. Um path sem extensão de arquivo retorna o `index.html` da pasta que o path indica: `/about` e `/about/` retornam `about/index.html`, e `/` retorna `index.html`. Um path com extensão, como `/hello.txt`, retorna esse arquivo.

```typescript
function mountMPA(requestURL: string): Promise<Response>;
```

| Parâmetro    | Tipo     | Obrigatório | Descrição                                    |
| ------------ | -------- | ----------- | -------------------------------------------- |
| `requestURL` | `string` | Sim         | A URL da requisição recebida, `request.url`. |

Retorna um `Response` que contém o arquivo.

Esta function responde a toda requisição com `mountMPA` e registra no log o path e o status:

```javascript
import { mountMPA } from '@aziontech/utils/edge';

export default {
  async fetch(request) {
    // /about is served from about/index.html
    const myApp = await mountMPA(request.url);
    console.log('mountMPA', new URL(request.url).pathname, '->', myApp.status);
    return myApp;
  },
};
```

Com a function servida localmente com `azion dev`, a raiz, uma página com e sem barra final e um arquivo retornam:

```text
$ curl http://localhost:3333/
HTTP/1.1 200 OK
content-type: text/html

<h1>index</h1>

$ curl http://localhost:3333/about
HTTP/1.1 200 OK
content-type: text/html

<h1>about</h1>

$ curl http://localhost:3333/about/
HTTP/1.1 200 OK
content-type: text/html

<h1>about</h1>

$ curl http://localhost:3333/hello.txt
HTTP/1.1 200 OK
content-type: text/plain

Hello from memoryFS
```

---

## parseRequest

Lê uma requisição recebida e retorna o método, as partes da URL, os headers, os cookies, o body e os dados do cliente dela em um único objeto simples.

```typescript
function parseRequest(request: AzionRuntimeRequest): Promise<ParsedRequest>;
```

| Parâmetro | Tipo                  | Obrigatório | Descrição                                                                                                                                          |
| --------- | --------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `request` | `AzionRuntimeRequest` | Sim         | A requisição recebida. Passe a própria requisição, não o fetch event. O tipo vem do pacote [Types](/pt-br/documentacao/devtools/azion-lib/types/). |

Retorna a requisição analisada. O pacote declara o tipo `ParsedRequest`, mas não o exporta, por isso deixe o TypeScript inferir o tipo do resultado. O resultado contém estas propriedades:

| Propriedade                                                                                                                           | Tipo                          | Descrição                                                                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------- |
| `timestamp`                                                                                                                           | `string`                      | O horário da chamada, no formato ISO 8601.                                                                |
| `method`                                                                                                                              | `string`                      | O método HTTP.                                                                                            |
| `url`                                                                                                                                 | `object`                      | As partes da URL: `full`, `protocol`, `hostname`, `path` e `query`, um objeto com os parâmetros de query. |
| `headers`                                                                                                                             | `Record<string, string>`      | Todos os headers da requisição, com nomes em minúsculas.                                                  |
| `cookies`                                                                                                                             | `Record<string, string>`      | Os cookies do header `Cookie`, por nome.                                                                  |
| `body`                                                                                                                                | `string \| null`              | O body da requisição como texto.                                                                          |
| `client`                                                                                                                              | `object`                      | `ip`, o endereço IP do cliente, e `userAgent`, o header `User-Agent`.                                     |
| `referer`, `origin`, `cacheControl`, `pragma`, `contentType`, `contentLength`, `acceptLanguage`, `acceptEncoding`, `priority`, `host` | `string`                      | O valor do header de requisição correspondente, ou `Unknown` quando a requisição não o contém.            |
| `authorization`                                                                                                                       | `string`                      | `Not Present` quando a requisição não tem header `Authorization`.                                         |
| `metadata`                                                                                                                            | `AzionRuntimeRequestMetadata` | Declarado pelo tipo. O resultado de uma chamada local não tem a chave `metadata`.                         |

O exemplo em TypeScript importa `AzionRuntimeRequest` de `@aziontech/types`, por isso instale também esse pacote com `npm install @aziontech/types`. Este exemplo monta uma requisição `POST` manualmente e imprime quatro propriedades do resultado:

```typescript
import { parseRequest } from '@aziontech/utils/edge';
import type { AzionRuntimeRequest } from '@aziontech/types';

// In a function, pass the incoming request; here one is built by hand
const request = new Request('https://example.com/products?id=42', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Cookie: 'session=abc123', 'User-Agent': 'docs-sample' },
  body: JSON.stringify({ qty: 1 }),
}) as AzionRuntimeRequest;

const parsedRequest = await parseRequest(request);
console.log(parsedRequest.method, parsedRequest.url, parsedRequest.cookies, parsedRequest.body);
```

Saída:

```text
POST {
  full: 'https://example.com/products?id=42',
  protocol: 'https:',
  hostname: 'example.com',
  path: '/products',
  query: { id: '42' }
} { session: 'abc123' } {"qty":1}
```

Dentro de uma function, passe a requisição recebida. Esta function retorna o resultado inteiro como JSON:

```javascript
import { parseRequest } from '@aziontech/utils/edge';

export default {
  async fetch(request) {
    const parsedRequest = await parseRequest(request);
    return new Response(JSON.stringify(parsedRequest, null, 2), { headers: { 'content-type': 'application/json' } });
  },
};
```

Com a function servida localmente com `azion dev`, uma requisição `POST` com um cookie e um body JSON retorna o resultado abaixo. Localmente, `client.ip` é `Unknown` e o resultado não tem a chave `metadata`, porque o runtime local não tem `request.metadata`.

```text
$ curl -X POST -H 'Content-Type: application/json' -H 'Cookie: session=abc123' -d '{"qty":1}' 'http://localhost:3333/products?id=42'
HTTP/1.1 200 OK
content-type: application/json

{
  "timestamp": "2026-01-01T12:00:00.000Z",
  "method": "POST",
  "url": {
    "full": "http://localhost:3333/products?id=42",
    "protocol": "http:",
    "hostname": "localhost",
    "path": "/products",
    "query": {
      "id": "42"
    }
  },
  "headers": {
    "accept": "*/*",
    "content-length": "9",
    "content-type": "application/json",
    "cookie": "session=abc123",
    "host": "localhost:3333",
    "user-agent": "curl/8.7.1"
  },
  "cookies": {
    "session": "abc123"
  },
  "body": "{\"qty\":1}",
  "client": {
    "ip": "Unknown",
    "userAgent": "curl/8.7.1"
  },
  "referer": "Unknown",
  "origin": "Unknown",
  "cacheControl": "Unknown",
  "pragma": "Unknown",
  "contentType": "application/json",
  "contentLength": "9",
  "acceptLanguage": "Unknown",
  "acceptEncoding": "Unknown",
  "priority": "Unknown",
  "host": "localhost:3333",
  "authorization": "Not Present"
}
```

---

## Recursos relacionados

- [Azion Lib](/pt-br/documentacao/devtools/azion-lib.md): As bibliotecas que a Azion Lib oferece e o pacote que contém cada uma.
- [Como a Azion Lib funciona](/pt-br/documentacao/devtools/azion-lib/como-funciona.md): Quais módulos da Azion Lib rodam no Node.js, quais rodam dentro de uma function e por quê.
- [azion.config.js](/pt-br/documentacao/devtools/cli/azion-config-js.md): As configurações de build, entre elas memoryFS, que definem quais arquivos uma function pode servir.
- [Azion CLI dev](/pt-br/documentacao/devtools/cli/dev-comando.md): Sirva uma function localmente e teste os arquivos e as requisições que ela processa.
