{"id":37229472,"url":"https://github.com/abanobmikaeel/appsync-local-server","last_synced_at":"2026-01-15T03:32:53.790Z","repository":{"id":308265887,"uuid":"985346266","full_name":"abanobmikaeel/appsync-local-server","owner":"abanobmikaeel","description":"Local development server for AWS AppSync JavaScript resolvers. Test GraphQL APIs without deploying","archived":false,"fork":false,"pushed_at":"2026-01-12T01:42:26.000Z","size":371,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-12T02:05:58.856Z","etag":null,"topics":["appsync","aws","aws-appsync","developer-tools","graphql","javascript-resolvers","local-development","mock-server","serverless","testing"],"latest_commit_sha":null,"homepage":"https://abanobmikaeel.github.io/appsync-local-server/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abanobmikaeel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-17T15:12:23.000Z","updated_at":"2026-01-12T01:38:59.000Z","dependencies_parsed_at":"2025-08-05T10:46:55.634Z","dependency_job_id":null,"html_url":"https://github.com/abanobmikaeel/appsync-local-server","commit_stats":null,"previous_names":["abanobmikaeel/appsync-local-server"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/abanobmikaeel/appsync-local-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abanobmikaeel%2Fappsync-local-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abanobmikaeel%2Fappsync-local-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abanobmikaeel%2Fappsync-local-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abanobmikaeel%2Fappsync-local-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abanobmikaeel","download_url":"https://codeload.github.com/abanobmikaeel/appsync-local-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abanobmikaeel%2Fappsync-local-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28442288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"online","status_checked_at":"2026-01-15T02:00:08.019Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["appsync","aws","aws-appsync","developer-tools","graphql","javascript-resolvers","local-development","mock-server","serverless","testing"],"created_at":"2026-01-15T03:32:52.967Z","updated_at":"2026-01-15T03:32:53.782Z","avatar_url":"https://github.com/abanobmikaeel.png","language":"TypeScript","readme":"# appsync-local\n\n[![CI](https://github.com/abanobmikaeel/appsync-local-server/actions/workflows/ci.yml/badge.svg)](https://github.com/abanobmikaeel/appsync-local-server/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/appsync-local-server)](https://www.npmjs.com/package/appsync-local-server)\n[![npm downloads](https://img.shields.io/npm/dm/appsync-local-server)](https://www.npmjs.com/package/appsync-local-server)\n[![codecov](https://codecov.io/gh/abanobmikaeel/appsync-local-server/branch/main/graph/badge.svg)](https://codecov.io/gh/abanobmikaeel/appsync-local-server)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nRun AWS AppSync JavaScript resolvers locally. No VTL, just JavaScript.\n\n## Install\n\n```bash\nnpm install -g appsync-local-server\n```\n\n## Usage\n\n```bash\nappsync-local start -c appsync-config.json -p 4000\n```\n\nServer starts at `http://localhost:4000/`\n\n## Config File\n\n```json\n{\n  \"schema\": \"./schema.graphql\",\n  \"apiConfig\": {\n    \"auth\": [{ \"type\": \"API_KEY\", \"key\": \"dev-key\" }]\n  },\n  \"dataSources\": [\n    { \"type\": \"NONE\", \"name\": \"LocalDS\" }\n  ],\n  \"resolvers\": [\n    {\n      \"type\": \"Query\",\n      \"field\": \"getUser\",\n      \"kind\": \"Unit\",\n      \"dataSource\": \"LocalDS\",\n      \"file\": \"./resolvers/getUser.js\"\n    }\n  ]\n}\n```\n\n## Resolver Format\n\nResolvers export `request` and `response` functions:\n\n```javascript\n// resolvers/getUser.js\nexport function request(ctx) {\n  return { id: ctx.arguments.id };\n}\n\nexport function response(ctx) {\n  return { id: ctx.prev.result.id, name: 'Alice' };\n}\n```\n\nContext (`ctx`) includes:\n- `ctx.arguments` - GraphQL arguments\n- `ctx.prev.result` - Result from request function (or previous pipeline function)\n- `ctx.stash` - Shared data across pipeline functions\n- `ctx.source` - Parent resolver result\n- `ctx.identity` - Auth identity info\n- `ctx.request.headers` - HTTP headers\n\n## Using @aws-appsync/utils\n\nWrite your resolvers exactly as you would for AWS AppSync. Standard imports work seamlessly:\n\n```javascript\n// resolvers/createUser.js\nimport { util } from '@aws-appsync/utils';\nimport { put } from '@aws-appsync/utils/dynamodb';\n\nexport function request(ctx) {\n  return put({\n    key: { id: util.autoId() },\n    item: {\n      ...ctx.arguments.input,\n      createdAt: util.time.nowISO8601()\n    }\n  });\n}\n\nexport function response(ctx) {\n  return ctx.prev.result;\n}\n```\n\nThe same resolver code works locally and when deployed to AWS AppSync.\n\n### Available Utilities\n\n**Globals** (`util`, `runtime`, `extensions`) are also available without imports:\n\n```javascript\nexport function request(ctx) {\n  // util is a global - no import needed\n  return { id: util.autoId(), timestamp: util.time.nowEpochSeconds() };\n}\n```\n\n**DynamoDB helpers** from `@aws-appsync/utils/dynamodb`:\n- `get()`, `put()`, `update()`, `remove()` - Single item operations\n- `query()`, `scan()` - Query and scan operations\n- `batchGet()`, `batchPut()`, `batchDelete()` - Batch operations\n- `transactGet()`, `transactWrite()` - Transactions\n- `operations` - Update expression builders (`increment`, `append`, etc.)\n\n### TypeScript Support\n\nInstall `@aws-appsync/utils` for TypeScript types:\n\n```bash\nnpm install --save-dev @aws-appsync/utils\n```\n\n## Data Sources\n\n### NONE\nFor pure JavaScript logic, no external calls:\n\n```json\n{ \"type\": \"NONE\", \"name\": \"LocalDS\" }\n```\n\n### DYNAMODB\nSupports both local DynamoDB and real AWS DynamoDB.\n\n**Local DynamoDB:**\n```json\n{\n  \"type\": \"DYNAMODB\",\n  \"name\": \"UsersTable\",\n  \"config\": {\n    \"tableName\": \"users\",\n    \"region\": \"us-east-1\",\n    \"endpoint\": \"http://localhost:8000\",\n    \"accessKeyId\": \"fakeId\",\n    \"secretAccessKey\": \"fakeSecret\"\n  }\n}\n```\n\nStart local DynamoDB:\n```bash\ndocker run -p 8000:8000 amazon/dynamodb-local\n```\n\n**Real AWS DynamoDB:**\n```json\n{\n  \"type\": \"DYNAMODB\",\n  \"name\": \"UsersTable\",\n  \"config\": {\n    \"tableName\": \"users\",\n    \"region\": \"us-east-1\"\n  }\n}\n```\nOmit `endpoint` to connect to real AWS. Credentials are loaded from the default AWS credential chain (env vars, ~/.aws/credentials, IAM role).\n\n### LAMBDA\nExecute local JavaScript as Lambda:\n\n```json\n{\n  \"type\": \"LAMBDA\",\n  \"name\": \"MyLambda\",\n  \"config\": {\n    \"functionName\": \"processor\",\n    \"file\": \"./lambdas/processor.js\"\n  }\n}\n```\n\nLambda file exports a handler:\n```javascript\nexport async function handler(event, context) {\n  return { result: event.input * 2 };\n}\n```\n\n### HTTP\nCall external HTTP APIs:\n\n```json\n{\n  \"type\": \"HTTP\",\n  \"name\": \"RestAPI\",\n  \"config\": {\n    \"endpoint\": \"https://api.example.com\",\n    \"defaultHeaders\": { \"Authorization\": \"Bearer token\" }\n  }\n}\n```\n\nResolver builds HTTP request:\n```javascript\nexport function request(ctx) {\n  return {\n    method: 'GET',\n    resourcePath: `/users/${ctx.arguments.id}`,\n    params: {\n      headers: { 'Accept': 'application/json' }\n    }\n  };\n}\n\nexport function response(ctx) {\n  return ctx.prev.result.body;\n}\n```\n\n### RDS\nSupports both direct database connections and AWS RDS Data API.\n\n**Local/Direct Connection:**\n```json\n{\n  \"type\": \"RDS\",\n  \"name\": \"Database\",\n  \"config\": {\n    \"engine\": \"postgresql\",\n    \"databaseName\": \"mydb\",\n    \"mode\": \"local\",\n    \"host\": \"localhost\",\n    \"port\": 5432,\n    \"user\": \"postgres\",\n    \"password\": \"password\"\n  }\n}\n```\n\n**AWS RDS Data API:**\n```json\n{\n  \"type\": \"RDS\",\n  \"name\": \"Database\",\n  \"config\": {\n    \"engine\": \"postgresql\",\n    \"databaseName\": \"mydb\",\n    \"mode\": \"aws\",\n    \"region\": \"us-east-1\",\n    \"resourceArn\": \"arn:aws:rds:us-east-1:123456789:cluster:my-cluster\",\n    \"awsSecretStoreArn\": \"arn:aws:secretsmanager:us-east-1:123456789:secret:my-secret\"\n  }\n}\n```\n\nResolver executes SQL:\n```javascript\nexport function request(ctx) {\n  return {\n    operation: 'executeStatement',\n    sql: 'SELECT * FROM users WHERE id = :id',\n    variableMap: { id: ctx.arguments.id }\n  };\n}\n\nexport function response(ctx) {\n  return ctx.prev.result.records[0];\n}\n```\n\n## Pipeline Resolvers\n\nChain multiple functions:\n\n```json\n{\n  \"type\": \"Mutation\",\n  \"field\": \"createUser\",\n  \"kind\": \"Pipeline\",\n  \"file\": \"./resolvers/createUser.js\",\n  \"pipelineFunctions\": [\n    { \"file\": \"./functions/validate.js\", \"dataSource\": \"LocalDS\" },\n    { \"file\": \"./functions/save.js\", \"dataSource\": \"UsersTable\" }\n  ]\n}\n```\n\nMain resolver wraps the pipeline:\n```javascript\n// resolvers/createUser.js\nexport function request(ctx) {\n  ctx.stash.input = ctx.arguments.input;\n  return {};\n}\n\nexport function response(ctx) {\n  return ctx.stash.result;\n}\n```\n\nEach function in the pipeline:\n```javascript\n// functions/validate.js\nexport function request(ctx) {\n  if (!ctx.stash.input.email) {\n    throw new Error('Email required');\n  }\n  return {};\n}\n\nexport function response(ctx) {\n  return ctx.prev.result;\n}\n```\n\n## Authentication\n\n### API Key\n```json\n{\n  \"type\": \"API_KEY\",\n  \"key\": \"your-dev-key\"\n}\n```\n\n### Lambda Authorizer\n\n**With local Lambda file:**\n```json\n{\n  \"type\": \"AWS_LAMBDA\",\n  \"lambdaFunction\": \"./auth/authorizer.js\"\n}\n```\n\n**With mock identity (for local development without a Lambda):**\n```json\n{\n  \"type\": \"AWS_LAMBDA\",\n  \"identity\": {\n    \"sub\": \"user-123\",\n    \"username\": \"testuser\",\n    \"groups\": [\"admin\"]\n  },\n  \"resolverContext\": {\n    \"tenantId\": \"tenant-abc\",\n    \"role\": \"admin\"\n  }\n}\n```\n\nThe `identity` fields are available in resolvers via `ctx.identity`:\n- `ctx.identity.sub` - User ID\n- `ctx.identity.username` - Username\n- `ctx.identity.groups` - User groups array\n\nThe `resolverContext` is available via `ctx.identity.resolverContext` and merged into `ctx.identity.claims`.\n\n### Cognito User Pools\n```json\n{\n  \"type\": \"AMAZON_COGNITO_USER_POOLS\",\n  \"userPoolId\": \"us-east-1_xxxxx\"\n}\n```\n\n### OpenID Connect\n```json\n{\n  \"type\": \"OPENID_CONNECT\",\n  \"issuer\": \"https://your-issuer.com\",\n  \"clientId\": \"your-client-id\"\n}\n```\n\n### IAM\n```json\n{\n  \"type\": \"AWS_IAM\"\n}\n```\n\n### Multiple Auth Methods\nYou can configure multiple auth methods. The first one that succeeds will be used:\n```json\n{\n  \"apiConfig\": {\n    \"auth\": [\n      { \"type\": \"AWS_LAMBDA\", \"identity\": { \"sub\": \"dev-user\" } },\n      { \"type\": \"API_KEY\", \"key\": \"fallback-key\" }\n    ]\n  }\n}\n```\n\n## Full Example\n\nSee `examples/basic/` for a working setup.\n\nRun it:\n```bash\nnpx appsync-local start -c examples/basic/appsync-config.json -p 4000\n```\n\nQuery:\n```bash\ncurl -X POST http://localhost:4000/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"{ listUsers { id name email } }\"}'\n```\n\n## Limitations\n\n- JavaScript resolvers only (no VTL)\n- Local simulation, not real AWS services\n- No subscriptions\n\n## Development\n\n```bash\nnpm install\nnpm run dev -- -c examples/basic/appsync-config.json -p 4000\nnpm test\nnpm run test:e2e\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabanobmikaeel%2Fappsync-local-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabanobmikaeel%2Fappsync-local-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabanobmikaeel%2Fappsync-local-server/lists"}