Skip to content
Back to skills

Nuxt Gen Api

ASecurity

Gera uma rota de API Nitro para projetos Nuxt com o handler correto — autenticado (defineAuthenticatedEventHandler), seguro (defineSecuredEventHandler) ou público — seguindo as convenções de nomenclatura e estrutura do projeto.

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 12, 2026
developmenttypescriptgoapi

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 12, 2026

npx -y skills add aibot88/sec_skill_store --skill nuxt-gen-api --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nuxt Gen Api?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Nuxt Gen Api
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aibot88-nuxt-gen-api/badge)](https://www.skillsdirectory.com/skills/aibot88-nuxt-gen-api)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: nuxt-gen-api
description: Gera uma rota de API Nitro para projetos Nuxt com o handler correto — autenticado (defineAuthenticatedEventHandler), seguro (defineSecuredEventHandler) ou público — seguindo as convenções de nomenclatura e estrutura do projeto.
---

# nuxt-gen-api — Gerar API Route Nitro

Você está gerando uma rota de API Nitro. Siga as convenções do projeto rigorosamente.

## 1. Coletar informações

Extraia dos argumentos ou pergunte ao usuário:

1. **Recurso** — nome do recurso em inglês, singular (ex: `product`, `order`, `category`)
2. **Método HTTP** — GET, POST, PUT, DELETE (ou múltiplos para scaffold CRUD completo)
3. **Tem parâmetro de rota?** — ex: `/api/admin/products/[id]`
4. **Tipo de proteção:**
   - `authenticated` — requer Firebase Auth + verifica claims (padrão para rotas protegidas)
   - `secured` — requer apenas App Check (sem auth de usuário)
   - `public` — sem proteção
5. **Claim necessário** — `sudo`, ou nenhum (só para `authenticated`)
6. **Onde criar** — ex: `server/api/admin/`, `server/api/me/`, `server/api/`
7. **O que faz** — descrição breve da lógica (ex: "lista produtos ativos ordenados por nome")

## 2. Regras de nomenclatura

```
server/api/admin/products.get.ts           # GET  /api/admin/products
server/api/admin/products.post.ts          # POST /api/admin/products
server/api/admin/products/[id].get.ts      # GET  /api/admin/products/:id
server/api/admin/products/[id].put.ts      # PUT  /api/admin/products/:id
server/api/admin/products/[id].delete.ts   # DELETE /api/admin/products/:id
```

- Recurso sempre em **inglês**
- Kebab-case para recursos compostos (`blog-posts`, `order-items`)
- Nunca use português na URL

## 3. Templates por tipo de proteção

### Handler autenticado com claim sudo (padrão para rotas protegidas)

```typescript
// GET /api/admin/[recurso]
export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const { data, error } = await db()
    .from('[tabela]')
    .select('*')
    .order('[campo]')

  if (error) {
    throw createError({ status: 500, message: error.message })
  }

  return { data }
})
```

### Handler autenticado sem claim específico (apenas login)

```typescript
export default defineAuthenticatedEventHandler(async (event, context) => {
  const userId = context.claims.uid
  // lógica
})
```

### Handler seguro (App Check apenas, sem auth de usuário)

```typescript
export default defineSecuredEventHandler(async (event) => {
  // lógica sem contexto de usuário
})
```

### Handler público

```typescript
export default defineEventHandler(async (event) => {
  // lógica pública
})
```

## 4. Templates por método HTTP

### GET — listar recursos

```typescript
export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const query = getQuery(event)
  const page = Number(query.page) || 1
  const limit = Number(query.limit) || 20

  const { data, error, count } = await db()
    .from('[tabela]')
    .select('*', { count: 'exact' })
    .range((page - 1) * limit, page * limit - 1)
    .order('created_at', { ascending: false })

  if (error) {
    throw createError({ status: 500, message: error.message })
  }

  return { data, total: count, page, limit }
})
```

### GET — buscar por ID

```typescript
export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const { id } = getRouterParams(event)

  const { data, error } = await db()
    .from('[tabela]')
    .select('*')
    .eq('id', id)
    .single()

  if (error || !data) {
    throw createError({ status: 404, message: '[Recurso] não encontrado' })
  }

  return { data }
})
```

### POST — criar recurso

```typescript
import { z } from 'zod'  // se o projeto usar zod

export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const body = await readBody(event)

  // Validação básica
  if (!body.[campo_obrigatorio]) {
    throw createError({ status: 400, message: '[campo] é obrigatório' })
  }

  const { data, error } = await db()
    .from('[tabela]')
    .insert({
      // campos aqui
    })
    .select()
    .single()

  if (error) {
    throw createError({ status: 500, message: error.message })
  }

  return { data }
})
```

### PUT — atualizar recurso

```typescript
export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const { id } = getRouterParams(event)
  const body = await readBody(event)

  const { data, error } = await db()
    .from('[tabela]')
    .update({
      // campos atualizáveis aqui
      updated_at: new Date().toISOString(),
    })
    .eq('id', id)
    .select()
    .single()

  if (error) {
    throw createError({ status: 500, message: error.message })
  }

  if (!data) {
    throw createError({ status: 404, message: '[Recurso] não encontrado' })
  }

  return { data }
})
```

### DELETE — remover recurso

```typescript
export default defineAuthenticatedEventHandler(async (event, context) => {
  if (!context.claims.sudo) {
    throw createError({ status: 403, message: 'Acesso negado' })
  }

  const { id } = getRouterParams(event)

  const { error } = await db()
    .from('[tabela]')
    .delete()
    .eq('id', id)

  if (error) {
    throw createError({ status: 500, message: error.message })
  }

  return { success: true }
})
```

## 5. Scaffold CRUD completo

Se o usuário pedir CRUD completo, gere todos os 5 arquivos de uma vez:

```
server/api/admin/[recurso].get.ts
server/api/admin/[recurso].post.ts
server/api/admin/[recurso]/[id].get.ts
server/api/admin/[recurso]/[id].put.ts
server/api/admin/[recurso]/[id].delete.ts
```

## 6. Verificações antes de criar

- O recurso está em inglês? Se não, converta.
- O diretório existe? Se não, crie-o.
- Já existe um arquivo com esse nome? Se sim, avise o usuário antes de sobrescrever.

## 7. Após criar

Informe:
- Caminho completo do(s) arquivo(s) criado(s)
- URL(s) que serão expostas
- Tipo de proteção aplicada
- Se precisa registrar a rota no `routeRules` do `nuxt.config.ts`

Files in this skill

  • SKILL.md6.4 KB
  • source.json735 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.