0 / 0 pasos

Checklist de validación completa

Sigue cada sección en orden. Cada paso tiene qué hacer exactamente y qué resultado esperar. Marca cada uno como completo para rastrear el progreso.

JS Resolvers VTL Resolvers Lambda Debug Pipeline Resolvers DynamoDB Expressions GSI Simulation FilterExpression Mock Data CDK Preflight
1

Estructura del proyecto CDK

Crea el layout mínimo para que la extensión detecte todo automáticamente
Crea el directorio de resolvers y mock dataAcción

Dentro de tu proyecto CDK crea esta estructura. La extensión la detecta automáticamente.

EXPLORER mi-proyecto-cdk
mi-proyecto-cdk
lib
appsync
◈schema.graphql← esquema principal
resolvers← resolvers JS/VTL/pipeline
functions← funciones de pipeline
{}mock-data.json← datos de prueba
{}cdk.json
✓ Qué esperar

Al correr AWS: Detect AppSync Project desde el Command Palette, la extensión debería encontrar el schema.graphql y la carpeta resolvers/ automáticamente.

Crea el schema GraphQL con tipos realesCódigo

Guarda esto como schema.graphql. Incluye tipos para probar todos los resolvers.

type User {
  id: ID!
  name: String!
  email: String!
  status: String
  role: String
  createdAt: String
}

type Order {
  id: ID!
  userId: ID!
  total: Float!
  status: String!
  createdAt: String
}

type UserConnection { items: [User], nextToken: String, scannedCount: Int }
type OrderConnection { items: [Order], nextToken: String, scannedCount: Int }

type Query {
  getUser(id: ID!): User
  listUsers(limit: Int, nextToken: String): UserConnection
  getUsersByStatus(status: String!): UserConnection
  listOrders(userId: ID!): OrderConnection
}

type Mutation {
  createUser(name: String!, email: String!, role: String): User
  updateUserStatus(id: ID!, status: String!): User
  deleteUser(id: ID!): User
}

schema { query: Query; mutation: Mutation }
Crea mock-data.json con datos de pruebaConfig

Guarda en la raíz del proyecto como mock-data.json.

{
  "User": [
    { "id": "usr-001", "name": "Ana García", "email": "ana@example.com", "status": "active", "role": "admin" },
    { "id": "usr-002", "name": "Carlos Pérez", "email": "carlos@example.com", "status": "active", "role": "user" },
    { "id": "usr-003", "name": "Laura Soto", "email": "laura@example.com", "status": "inactive", "role": "user" }
  ],
  "Order": [
    { "id": "ord-001", "userId": "usr-001", "total": 150.00, "status": "completed" },
    { "id": "ord-002", "userId": "usr-001", "total": 75.50, "status": "pending" },
    { "id": "ord-003", "userId": "usr-002", "total": 200.00, "status": "completed" }
  ]
}
2

Arrancar el servidor AppSync Offline

Verificar que la extensión detecta el proyecto y levanta en el puerto correcto
Arrancar el servidorAcción

Abre el Command Palette (Cmd+Shift+P) y ejecuta:

AWS: Detect and Start AppSync Offline
✓ Qué esperar

1. Si hay múltiples proyectos en el workspace, aparece un Quick Pick para seleccionar.
2. La notificación dice: AppSync Offline running at http://localhost:4000/graphql
3. El panel "AppSync Offline Studio" se abre con el dot verde parpadeando.
4. La pestaña Schema muestra todos los tipos del schema.

⚠ Si falla

Verifica que el archivo se llame exactamente schema.graphql (no .graphqls). La extensión también soporta carpetas con múltiples archivos *.graphql.

Verificar el health checkAcción

Abre una terminal y ejecuta:

curl http://localhost:4000/health
✓ Respuesta esperada

{"status":"ok","port":4000,"timestamp":"..."}

3

Resolvers JavaScript (APPSYNC_JS)

Crear y probar unit resolvers en JS
Crea los resolvers JS básicosCódigo

Crea estos archivos en resolvers/:

Query.getUser.request.js

export function request(ctx) {
  return {
    operation: 'GetItem',
    key: { id: { S: ctx.arguments.id } },
  };
}

Query.getUser.response.js

export function response(ctx) {
  return ctx.result;
}

Query.listUsers.request.js

export function request(ctx) {
  return {
    operation: 'Scan',
    limit: ctx.arguments.limit || 20,
  };
}

Query.listUsers.response.js

export function response(ctx) {
  return ctx.result;
}
Probar getUser desde el Query EditorAcción

En el panel AppSync Studio, pestaña Query, pega y ejecuta con Ctrl+Enter:

query {
  getUser(id: "usr-001") {
    id
    name
    email
    status
  }
}
✓ Respuesta esperada

{ "data": { "getUser": { "id": "usr-001", "name": "Ana García", "email": "ana@example.com", "status": "active" } } }

Probar ⚡ All IdentitiesAcción

Con la misma query activa, haz clic en el botón ⚡ All Identities.

✓ Qué esperar

La respuesta muestra un objeto con 5 claves: apiKey, cognitoUser, iam, admin, guest — cada uno con el mismo resultado (el resolver no valida identidad en este ejemplo). Los logs muestran 5 trazas agrupadas, cada una con su badge de identidad.

4

Resolver Runner & FilterExpression

Probar el Resolver Runner directo y los filtros DynamoDB
Crear resolver con FilterExpressionCódigo

Crea Query.getUsersByStatus.request.js:

export function request(ctx) {
  return {
    operation: 'Scan',
    filter: {
      expression: '#s = :status',
      expressionNames: { '#s': 'status' },
      expressionValues: { ':status': { S: ctx.arguments.status } },
    },
  };
}

export function response(ctx) {
  return ctx.result;
}
ℹ Nota

Puedes poner request y response en el mismo archivo o en archivos separados. Ambos formatos funcionan.

Ejecutar desde Resolver RunnerAcción

Ve a la pestaña Resolver Runner en el panel y completa:

  • Type.Field: Query.getUsersByStatus
  • Identity: cognitoUser
  • Arguments:
{ "status": "active" }

Haz clic en ▶ Run Resolver.

✓ Qué esperar en el trace

El trace muestra:
• [REQUEST] — operación Scan con FilterExpression
• [RESPONSE] — items filtrados: solo usr-001 y usr-002 (status = active)
• El resultado NO incluye usr-003 (status = inactive)

Verificar historial de runsAcción

Haz clic en Recent Runs (abajo del trace) para expandir.

✓ Qué esperar

Aparece la ejecución anterior con ✓ verde, badge de identidad cognitoUser y timestamp. Al hacer clic sobre ella, los campos Type.Field, Identity y Arguments se restauran automáticamente.

5

Resolvers VTL

Verificar evaluación local de templates Velocity
Crear un resolver VTLCódigo

Crea Query.listOrders.request.vtl:

{
  "operation": "Query",
  "query": {
    "expression": "userId = :uid",
    "expressionValues": {
      ":uid": $util.dynamodb.toDynamoDBJson($ctx.args.userId)
    }
  }
}

Crea Query.listOrders.response.vtl:

$util.toJson($ctx.result)
Probar el resolver VTLAcción

En Resolver Runner:

  • Type.Field: Query.listOrders
  • Arguments: { "userId": "usr-001" }
✓ Qué esperar

El trace muestra la operación Query con la expresión VTL ya evaluada. Resultado: items con ord-001 y ord-002 (userId = usr-001), NO ord-003.

ℹ GSI Simulation

Aunque userId no es la PK de la tabla Order, la extensión simula el GSI filtrando todos los items por ese atributo. No necesitas definir el índice explícitamente en mock-data.json.

6

Pipeline Resolvers

Múltiples funciones encadenadas con ctx.stash y ctx.prev.result
Crear la estructura del pipelineCódigo

Agrega la mutación al schema. Luego crea estos archivos:

EXPLORER resolvers/
resolvers
PIPEMutation.createUser.pipeline.json
JSMutation.createUser.before.js← opcional
JSMutation.createUser.after.js← opcional
functions
JSValidateEmail.request.js
JSValidateEmail.response.js
JSSaveUser.request.js
JSSaveUser.response.js

Mutation.createUser.pipeline.json

{
  "functions": [
    { "name": "ValidateEmail", "dataSource": "NONE" },
    { "name": "SaveUser", "dataSource": "User" }
  ]
}

functions/ValidateEmail.request.js

export function request(ctx) {
  // Guardar en stash para las funciones siguientes
  ctx.stash.email = ctx.arguments.email;
  ctx.stash.validatedAt = '2024-01-01T00:00:00Z';
  if (!ctx.arguments.email.includes('@')) {
    $util.error('Invalid email format', 'ValidationError');
  }
  return {};
}

export function response(ctx) {
  return { validated: true };
}

functions/SaveUser.request.js

export function request(ctx) {
  // ctx.prev.result = resultado de ValidateEmail
  return {
    operation: 'PutItem',
    key: { id: { S: $util.autoId() } },
    attributeValues: {
      name: { S: ctx.arguments.name },
      email: { S: ctx.stash.email },
      role: { S: ctx.arguments.role || 'user' },
      status: { S: 'active' },
    },
  };
}

export function response(ctx) {
  return ctx.result;
}
Ejecutar el pipelineAcción

En Resolver Runner:

  • Type.Field: Mutation.createUser
  • Arguments:
{ "name": "Pedro Ruiz", "email": "pedro@example.com", "role": "admin" }
✓ Trace esperado en el panel

[ValidateEmail → REQUEST] — retorna {}
[ValidateEmail → RESPONSE] — retorna { validated: true }
[SaveUser → REQUEST] — PutItem con id autogenerado
[SaveUser → RESPONSE] — el usuario creado
Respuesta final: el objeto User con el id generado

Ahora prueba con email inválido:

{ "name": "Bad User", "email": "no-es-un-email" }
✓ Qué esperar — error en función 1

El trace muestra [ValidateEmail → ERROR] con mensaje Invalid email format. SaveUser NO se ejecuta. El pipeline se detiene en la primera función fallida.

7

Operaciones DynamoDB completas

UpdateExpression, paginación, composite keys
UpdateItem con UpdateExpressionCódigo

Crea Mutation.updateUserStatus.request.js:

export function request(ctx) {
  return {
    operation: 'UpdateItem',
    key: { id: { S: ctx.arguments.id } },
    update: {
      expression: 'SET #st = :status',
      expressionNames: { '#st': 'status' },
      expressionValues: { ':status': { S: ctx.arguments.status } },
    },
  };
}

export function response(ctx) {
  return ctx.result;
}

En Resolver Runner con:

{ "id": "usr-003", "status": "active" }
✓ Qué esperar

El usuario usr-003 (Laura) ahora tiene status: "active". Corre Query.getUsersByStatus de nuevo con "status": "active" — ahora debe devolver los 3 usuarios.

Paginación con limit + nextTokenAcción

Crea Query.listUsers.request.js con soporte de paginación:

export function request(ctx) {
  return {
    operation: 'Scan',
    limit: ctx.arguments.limit || 2,
    nextToken: ctx.arguments.nextToken || null,
  };
}

En el Resolver Runner usa { "limit": 2 }. El resultado devuelve 2 usuarios y un nextToken. Pega ese token como argumento para obtener la siguiente página.

✓ Qué esperar

Página 1: 2 items + nextToken: "MQ==" (o similar en base64).
Página 2 con ese nextToken: 1 item + nextToken: null (fin de datos).

8

Mock Data & Hot Reload

Recargar datos sin reiniciar el servidor
Probar ↺ Reload DataAcción

1. Ejecuta Mutation.deleteUser para eliminar usr-001.
2. Verifica con Query.getUser que no existe.
3. Haz clic en el botón ↺ Reload Data del panel.
4. Ejecuta Query.getUser nuevamente.

✓ Qué esperar

Después del reload, usr-001 aparece de nuevo. El banner del panel muestra ✓ Mock data reloaded en azul.

Probar AWS: Generate Mock Data from CDKAcción

Corre cdk synth en tu proyecto para generar cdk.out/. Luego ejecuta desde el Command Palette:

AWS: Generate Mock Data from CDK
✓ Qué esperar

La extensión lee cdk.out/*.template.json, encuentra las tablas DynamoDB y genera un mock-data.json con la estructura de keys correcta. El archivo se abre en el editor y los datos se cargan automáticamente.

9

Hot Reload de Schema y Resolvers

Verificar que los cambios se reflejan sin reiniciar
Modificar un resolver en calienteAcción

Con el servidor corriendo, edita cualquier resolver (por ejemplo cambia 'active' por un valor distinto en SaveUser) y guarda el archivo.

✓ Qué esperar

En la pestaña Schema del panel aparece el badge ↻ reloaded en verde por 3 segundos. Las ejecuciones posteriores usan el resolver nuevo sin necesidad de reiniciar el servidor.

10

CDK Preflight & Diff

Validar el stack antes de hacer deploy
Validate Stack IntentAcción

Después de un cdk synth, ejecuta:

AWS: Validate Stack Intent (cdk.out)
✓ Qué esperar

Abre un panel con findings agrupados por severidad (Critical → Low) y un Confidence Score 0–100 con label: Ready to Deploy / Review Needed / etc. Cero findings críticos en un proyecto limpio.

Validate Environment VariablesAcción
AWS: Validate Environment Variables
✓ Qué esperar

Lista cada Lambda con sus env vars clasificadas: static (resuelta), ssm (necesita cloud), secret, token (CDK intrínseco). Si hay SSM refs no resueltas, sugiere el snippet para .env.local.

CDK Diff ExplainerAcción

Cambia algo en tu stack CDK (por ejemplo agrega un env var a una Lambda) y ejecuta:

AWS: Run CDK Diff Explainer
✓ Qué esperar

Cada cambio tiene: tipo de recurso, nivel de riesgo (🔴 Critical / 🟠 High / 🟡 Medium / 🟢 Low), explicación en lenguaje natural, y recomendación. El botón "Export Markdown" genera el reporte para PR review.

11

Lambda Debugging (si tienes Lambda data sources)

Adjuntar VS Code debugger a un handler local
Configurar un Lambda handlerConfig

En .vscode/settings.json:

{
  "awsToolkit.appsync.lambdaHandlers": {
    "UserLambdaDS": "src/handlers/users.ts#handler"
  },
  "awsToolkit.appsync.lambdaDebugPort": 9229
}

Crea el handler en src/handlers/users.ts:

export async function handler(event: any) {
  // Pon un breakpoint aquí ↓
  const { arguments: args, identity } = event;
  return { id: args.id, name: 'From Lambda', identity };
}
ℹ Flujo de debug

1. Pon un breakpoint en el handler.
2. En Resolver Runner selecciona el resolver que usa UserLambdaDS.
3. Haz clic en 🐛 Debug Lambda.
4. VS Code adjunta automáticamente el debugger — la ejecución pausa en el breakpoint.
5. Cuando continues (F5), el resultado aparece en el trace del panel.

12

AWS Service Map

Mapa visual interactivo de servicios generado desde cdk.out — React Flow
Generar el mapa de serviciosAcción

Requiere que cdk.out/ exista. Si no lo tienes, corre primero:

cdk synth

Luego ejecuta desde el Command Palette (Cmd+Shift+P):

AWS: Generate Service Map
✓ Qué esperar

Se abre el panel AWS Service Map con un diagrama React Flow interactivo:
• Un tab por stack CDK (uno por cada *.template.json en cdk.out/).
• Nodos auto-posicionados de izquierda a derecha por tipo de servicio.
• Conexiones con etiquetas que indican el tipo de relación.
• Leyenda dinámica en la barra superior con solo los servicios presentes en el stack.

⚠ Si no aparecen nodos

La extensión lee cdk.out/*.template.json — no el código CDK fuente. Verifica que cdk synth haya completado sin errores y que el directorio no esté vacío.

Verificar conexiones y explorar el mapaVerificar

Para el stack de este proyecto (AppSync + Lambda + DynamoDB + Cognito), el mapa debería mostrar este flujo:

Cognito ──auth──▶ AppSync ──datasource──▶ DataSource ──invokes──▶ Lambda ──env ref──▶ DynamoDB
ℹ Conexiones que detecta automáticamente

datasource — AppSync DataSource con ApiId: {Ref: ...}
invokes — DataSource tipo AWS_LAMBDA con LambdaFunctionArn
reads/writes — DataSource tipo AMAZON_DYNAMODB con TableName
auth — AppSync con UserPoolConfig.UserPoolId
triggers — AWS::Lambda::EventSourceMapping (SQS/SNS → Lambda)
env ref — Lambda con referencias a tablas/colas en Environment.Variables

Prueba la interactividad del panel:

  • Arrastrar nodos — reorganiza el layout a tu gusto
  • Scroll / pinch — zoom in/out
  • MiniMap (esquina inf. derecha) — navegación rápida en stacks grandes
  • Controls (esquina inf. izquierda) — fit view, zoom buttons
  • Tabs — cambia entre stacks CDK si tienes más de uno
✓ Edges animados

Las relaciones triggers e invokes muestran un edge animado (línea de puntos en movimiento) para distinguir flujos de datos activos de referencias de configuración.


✓

Resumen de cobertura actual

✓ Cubierto

JS / VTL / Lambda resolvers
Pipeline resolvers (stash, prev.result)
DynamoDB: GetItem, PutItem, UpdateItem, DeleteItem
FilterExpression, KeyConditionExpression
UpdateExpression (SET/REMOVE/ADD)
GSI simulation (query por cualquier atributo)
Composite keys (pk+sk)
Paginación (limit + nextToken)
Mock Data hot reload
Schema hot reload
Multi-identity runner
CDK Preflight + Confidence Score
Env Var classification
CDK Diff risk analysis
AWS Service Map (React Flow)

⚠ No cubierto (reportar si encuentras)

BatchGetItem / BatchWriteItem
TransactGetItems / TransactWriteItems
Subscriptions (WebSocket)
@auth directive enforcement
Lambda Layers locales
RDS / HTTP / EventBridge data sources