# Migrando padrões de handler em Functions

As Azion Functions suportam dois padrões de handler: **ES Modules** (recomendado) e **Service Worker** (legado). Este guia explica as diferenças entre eles e como migrar suas functions existentes para o padrão ES Modules.

## Padrões suportados

### ES Modules (recomendado)

O padrão ES Modules é a forma recomendada de estruturar suas functions na Azion. Ele oferece uma sintaxe moderna e limpa, com suporte nativo em produção e melhor desempenho.

```javascript
export default {
  fetch: (request, env, ctx) => {
    return new Response('Hello World');
  },
  firewall: (request, env, ctx) => {
    // Lógica de firewall
    ctx.deny();
  }
};
```

### Service Worker (legado)

O padrão Service Worker é mantido para compatibilidade com código legado. Se você estiver usando esse padrão, a Azion recomenda migrar para ES Modules.

```javascript
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request));
});

addEventListener('firewall', (event) => {
  // Lógica de firewall
  event.deny();
});

async function handleRequest(request) {
  return new Response('Hello World');
}
```

---

## Parâmetros dos handlers

### `fetch(request, env, ctx)`

| Parâmetro | Tipo | Descrição |
|---|---|---|
| `request` | [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) | O objeto da requisição HTTP recebida |
| `env` | Object | Variáveis de ambiente e bindings |
| `ctx` | Object | Contexto de execução. Use `ctx.waitUntil(promise)` para estender o tempo de vida da function para tarefas assíncronas |

### `firewall(request, env, ctx)` — ES Modules

| Parâmetro | Tipo | Descrição |
|---|---|---|
| `request` | [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) | O objeto da requisição HTTP recebida |
| `env` | Object | Variáveis de ambiente e bindings |
| `ctx` | Object | Contexto de execução. Chame `ctx.deny()` para bloquear a requisição imediatamente. Se `ctx.deny()` não for chamado, a requisição continua para o handler `fetch` |

### Evento de firewall — Service Worker

| Propriedade | Descrição |
|---|---|
| `event.request` | Acesso ao objeto Request |
| `event.deny()` | Bloqueia a requisição imediatamente. Se não for chamado, a requisição continua para o handler `fetch` |

---

## Migrando de Service Worker para ES Modules

### Handler fetch básico

**Antes (Service Worker):**

```javascript
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const url = new URL(request.url);

  if (url.pathname === '/api/hello') {
    return new Response(JSON.stringify({ message: 'Hello World' }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  return new Response('Not Found', { status: 404 });
}
```

**Depois (ES Modules):**

```javascript
export default {
  fetch: async (request, env, ctx) => {
    const url = new URL(request.url);

    if (url.pathname === '/api/hello') {
      return new Response(JSON.stringify({ message: 'Hello World' }), {
        headers: { 'Content-Type': 'application/json' }
      });
    }

    return new Response('Not Found', { status: 404 });
  }
};
```

### Handler firewall

**Antes (Service Worker):**

```javascript
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request));
});

addEventListener('firewall', (event) => {
  const clientIP = event.request.headers.get('X-Forwarded-For');
  const userAgent = event.request.headers.get('User-Agent');

  // Bloquear requisições de bots
  if (userAgent && userAgent.includes('bot')) {
    event.deny();
    return;
  }

  // Bloquear IPs específicos
  if (clientIP === '192.168.1.100') {
    event.deny();
    return;
  }

  // Permitir que a requisição continue para o handler fetch
});

async function handleRequest(request) {
  return new Response('Hello World');
}
```

**Depois (ES Modules):**

```javascript
export default {
  fetch: async (request, env, ctx) => {
    return new Response('Acesso concedido');
  },

  firewall: async (request, env, ctx) => {
    const clientIP = request.headers.get('X-Forwarded-For');
    const userAgent = request.headers.get('User-Agent');

    // Bloquear requisições de bots
    if (userAgent && userAgent.includes('bot')) {
      ctx.deny();
      return;
    }

    // Bloquear IPs específicos
    if (clientIP === '192.168.1.100') {
      ctx.deny();
      return;
    }

    // Permitir que a requisição continue para o handler fetch
    return;
  }
};
```

### Usando `waitUntil` para tarefas assíncronas

```javascript
export default {
  fetch: async (request, env, ctx) => {
    // Use waitUntil para tarefas assíncronas que não devem bloquear a resposta
    ctx.waitUntil(logRequest(request));

    return new Response('Hello World');
  }
};

async function logRequest(request) {
  console.log(`Requisição para: ${request.url}`);
}
```

### Firewall avançado com regras baseadas em path

```javascript
export default {
  fetch: async (request, env, ctx) => {
    return new Response('Acesso concedido');
  },

  firewall: async (request, env, ctx) => {
    const url = new URL(request.url);
    const userAgent = request.headers.get('User-Agent');
    const clientIP = request.headers.get('X-Forwarded-For');

    // Bloquear requisições de bots
    if (userAgent && userAgent.includes('bot')) {
      ctx.deny();
      return;
    }

    // Restringir acesso a paths de admin por faixa de IP
    if (url.pathname.startsWith('/admin')) {
      if (!clientIP || !clientIP.startsWith('192.168.')) {
        ctx.deny();
        return;
      }
    }

    // Permitir que a requisição continue para o handler fetch
    return;
  }
};
```

---

## Padrões não suportados

Os seguintes padrões **não** são suportados pelas Azion Functions. Se o seu código utilizar algum deles, migre para o padrão ES Modules.

```javascript
// ❌ Export direto de função
export default function(request) {
  return new Response('Hello');
}

// ❌ Named exports
export function fetch(request) {
  return new Response('Hello');
}

// ❌ Sem export
function handleRequest(request) {
  return new Response('Hello');
}
```

---

## Solução de problemas

### "Unsupported handler pattern detected"

Esse erro aparece quando o código não segue nenhum dos padrões suportados. Para resolver, migre para o padrão ES Modules:

```javascript
export default {
  fetch: async (request, env, ctx) => {
    return new Response('Hello World');
  }
};
```

Como alternativa temporária, use o padrão Service Worker:

```javascript
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  return new Response('Hello World');
}
```

---

## Recursos relacionados

- [Primeiros passos com Functions](/pt-br/documentacao/produtos/guias/edge-functions/primeiros-passos/)
- [Visão geral de Functions](/pt-br/documentacao/produtos/build/applications/functions/)
- [Referência da API do Azion Runtime](/pt-br/documentacao/runtime/visao-geral/)
- [Functions com Firewall](/pt-br/documentacao/produtos/guias/edge-functions/firewall/)