{"id":48550060,"url":"https://github.com/aziontech/js-azion-api-example","last_synced_at":"2026-04-08T08:04:06.500Z","repository":{"id":343795413,"uuid":"1140179155","full_name":"aziontech/js-azion-api-example","owner":"aziontech","description":"Example REST API using @azion/js-auth and @azion/js-api-errors - Hono + TypeScript","archived":false,"fork":false,"pushed_at":"2026-03-11T21:35:08.000Z","size":78,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-12T00:45:30.059Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aziontech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-22T23:39:48.000Z","updated_at":"2026-03-06T23:13:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aziontech/js-azion-api-example","commit_stats":null,"previous_names":["aziontech/js-azion-api-example"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/aziontech/js-azion-api-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aziontech%2Fjs-azion-api-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aziontech%2Fjs-azion-api-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aziontech%2Fjs-azion-api-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aziontech%2Fjs-azion-api-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aziontech","download_url":"https://codeload.github.com/aziontech/js-azion-api-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aziontech%2Fjs-azion-api-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31545909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"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":[],"created_at":"2026-04-08T08:03:47.790Z","updated_at":"2026-04-08T08:04:06.484Z","avatar_url":"https://github.com/aziontech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @azion/example-api\n\nExample REST API using `@azion/js-auth` and `@azion/js-api-errors` - Hono + TypeScript\n\nThis project demonstrates how to build a production-ready REST API for Azion Edge Functions using:\n\n- **[@azion/js-auth](./js-azion-auth/)** - Authentication library for Azion SSO\n- **[@azion/js-api-errors](./js-azion-api-errors/)** - Error handling following JSON:API specification\n- **[Hono](https://hono.dev/)** - Lightweight web framework\n- **[Drizzle ORM](https://orm.drizzle.team/)** - TypeScript ORM for database access\n- **[Zod](https://zod.dev/)** - Schema validation\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [Project Structure](#project-structure)\n- [API Endpoints](#api-endpoints)\n- [Authentication](#authentication)\n- [Error Handling](#error-handling)\n- [Development](#development)\n- [Deployment](#deployment)\n- [Troubleshooting](#troubleshooting)\n- [Related Libraries](#related-libraries)\n\n---\n\n## Features\n\n- SSO Authentication via session cookies and API tokens\n- JSON:API compliant error responses\n- Request validation with Zod schemas\n- Security middlewares (CORS, secure headers, body limit, timeout)\n- Request ID tracing for debugging\n- Database integration with AWS RDS Data API\n- Runs on both Azion Edge Functions and Bun\n\n---\n\n## Quick Start\n\n### Prerequisites\n\n- [Bun](https://bun.sh/) \u003e= 1.0\n- [Azion CLI](https://www.azion.com/en/documentation/products/azion-cli/overview/) (for deployment)\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone --recurse-submodules git@github.com:aziontech/js-azion-api-example.git\ncd js-azion-api-example\n\n# Install dependencies\nbun install\n\n# Copy environment file\ncp .env.example .env\n# Edit .env with your credentials\n```\n\n### Environment Variables\n\n```env\n# SSO Authentication\nSSO_MODE=stage                    # development | stage | production\nSSO_GQL_SECRET=your_secret_here   # Required for stage/production\n\n# AWS RDS Data API (optional)\nRDS_REGION=us-east-1\nRDS_RESOURCE_ARN=arn:aws:rds:...\nRDS_SECRET_ARN=arn:aws:secretsmanager:...\nRDS_DATABASE=your_database\n```\n\n### Run Locally\n\n```bash\n# Development server (Bun)\nbun run dev\n# Server running at http://localhost:3000\n\n# Edge Runtime simulation (Azion)\nbun run dev:azion\n# Server running at http://localhost:3333\n```\n\n---\n\n## Project Structure\n\n```\njs-azion-api-example/\n├── src/\n│   ├── index.ts           # Hono app configuration\n│   ├── azion.ts           # Edge Functions entry point\n│   ├── server.ts          # Bun development server\n│   ├── config.ts          # SSO/Auth configuration\n│   ├── env.ts             # Environment variable management\n│   ├── types.ts           # TypeScript types\n│   ├── handlers/          # Route handlers\n│   │   ├── health.ts      # Health check endpoints\n│   │   ├── tasks.ts       # Tasks CRUD\n│   │   └── db-test.ts     # Database test endpoints\n│   ├── middleware/        # Hono middlewares\n│   │   ├── auth.ts        # Authentication middleware\n│   │   ├── security.ts    # Security middlewares\n│   │   └── validation.ts  # Request validation\n│   └── db/                # Database layer\n│       ├── config.ts      # RDS configuration\n│       ├── index.ts       # Database client\n│       └── schema.ts      # Drizzle schema\n├── js-azion-auth/         # Authentication library (submodule)\n├── js-azion-api-errors/   # Error handling library (submodule)\n├── azion/                 # Azion configuration\n│   └── azion.json         # Resource definitions\n├── scripts/\n│   └── deploy.sh          # Deployment script\n└── package.json\n```\n\n---\n\n## API Endpoints\n\n| Method | Path | Auth | Description |\n|--------|------|------|-------------|\n| GET | `/health` | No | Health check |\n| GET | `/healthz` | No | Health check (Kubernetes) |\n| GET | `/tasks` | Yes | List all tasks |\n| GET | `/tasks/:id` | Yes | Get task by ID |\n| GET | `/db/test` | Yes | List database users |\n| POST | `/db/test` | Yes | Create database user |\n\n### Example Requests\n\n```bash\n# Health check (public)\ncurl http://localhost:3000/health\n\n# List tasks (requires auth)\ncurl -H \"Authorization: token YOUR_TOKEN\" http://localhost:3000/tasks\n\n# Get task by ID\ncurl -H \"Authorization: token YOUR_TOKEN\" http://localhost:3000/tasks/1\n\n# Create user (requires auth + body)\ncurl -X POST http://localhost:3000/db/test \\\n  -H \"Authorization: token YOUR_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"John Doe\", \"email\": \"john@example.com\"}'\n```\n\n---\n\n## Authentication\n\nThis API uses `@azion/js-auth` for authentication. Protected endpoints require one of:\n\n### API Token\n\n```bash\nAuthorization: token \u003cyour-azion-token\u003e\n# or\nAuthorization: Bearer \u003cyour-azion-token\u003e\n```\n\n### Session Cookie\n\n```bash\nCookie: azsid=\u003csession-id\u003e        # production\nCookie: azsid_stg=\u003csession-id\u003e    # stage\n```\n\n### Authentication Flow\n\n```\n┌─────────┐     ┌──────────────────┐     ┌─────────┐\n│ Client  │────▶│  Example API     │────▶│   SSO   │\n│         │     │  (Edge Function) │     │ GraphQL │\n└─────────┘     └──────────────────┘     └─────────┘\n     │                   │                     │\n     │  1. Request +     │  2. Validate via    │\n     │     Token/Cookie  │     @azion/js-auth  │\n     │                   │────────────────────▶│\n     │                   │                     │\n     │                   │  3. User \u0026 Account  │\n     │                   │◀────────────────────│\n     │                   │                     │\n     │  4. Response      │                     │\n     │◀──────────────────│                     │\n```\n\n### Middleware Usage\n\n```typescript\nimport { azionAuthMiddleware } from './middleware/auth.ts';\n\n// Apply to protected routes\napp.get('/tasks', azionAuthMiddleware, listTasksHandler);\n```\n\n---\n\n## Error Handling\n\nThis API uses `@azion/js-api-errors` for standardized error responses following JSON:API specification.\n\n### Error Response Format\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"10001\",\n      \"title\": \"Not Found\",\n      \"detail\": \"The requested resource was not found.\",\n      \"status\": \"404\",\n      \"meta\": {\n        \"requestId\": \"abc123\"\n      }\n    }\n  ]\n}\n```\n\n### Using Error Codes\n\n```typescript\nimport { APIErrorException, codes, exceptionHandler } from '@azion/js-api-errors';\n\n// Throw specific errors\nthrow new APIErrorException(codes.NOT_FOUND);\nthrow new APIErrorException({\n  errorCode: codes.VALIDATION_ERROR,\n  field: 'email',\n  meta: { received: 'invalid' }\n});\n\n// Global error handler\napp.onError((err, c) =\u003e {\n  return exceptionHandler(err, { request: c.req.raw });\n});\n```\n\n---\n\n## Development\n\n### Available Scripts\n\n```bash\nbun run dev         # Start Bun development server\nbun run dev:azion   # Start Azion Edge Runtime locally\nbun run build:azion # Build for Azion deployment\nbun run typecheck   # Run TypeScript type checking\nbun test            # Run tests\n```\n\n### Entry Points\n\n| File | Purpose | Runtime |\n|------|---------|---------|\n| `src/server.ts` | Development server | Bun |\n| `src/azion.ts` | Edge Functions entry | Azion Edge |\n| `src/index.ts` | Hono app (shared) | Both |\n\n### Environment Variables in Azion\n\nIn Azion Edge Functions, args are passed via `FetchEvent.args`, **not** via `Azion.env.get()`.\n\nThe `src/env.ts` module provides a unified `getEnv()` function:\n- **Azion Edge:** Reads from `FetchEvent.args` (set by `azion.ts`)\n- **Bun/Node:** Reads from `process.env`\n\n---\n\n## Deployment\n\n### Using Deploy Script (Recommended)\n\n```bash\n# Login to Azion (first time)\nazion login\n\n# Deploy\n./scripts/deploy.sh\n```\n\nThe script will:\n1. Load environment variables from `.env`\n2. Generate `azion/args.json` with secrets\n3. Build with `bun build`\n4. Deploy to Azion Edge Functions\n\n### Build\n\n```bash\nbun run build:azion\n# Output: dist/azion.js\n```\n\n\u003e **Important:** Always use `bun build`, not `azion build`. The Azion bundler generates incompatible Node.js imports (`node:fs`, `node:module`) that don't work in the Edge Runtime.\n\n### Manual Deployment\n\n```bash\n# Build\nbun run build:azion\n\n# Copy to expected location\nmkdir -p .edge\ncp dist/azion.js .edge/worker.js\n\n# Deploy\nazion deploy --local --skip-build --yes\n```\n\n\u003e **Note:** Changes may take 15-30 seconds to propagate globally.\n\n---\n\n## Troubleshooting\n\n### Function not updating after deploy\n\n- Propagation takes ~15-30 seconds\n- Try `?nocache=timestamp` to bypass edge cache\n\n### Build fails with Node.js imports\n\nAlways use `bun build --target=browser`. The Azion bundler (`azion build`) adds incompatible `node:fs` and `node:module` imports.\n\n### Args not being read\n\nArgs are passed via `FetchEvent.args`, not `Azion.env.get()`. Make sure:\n1. `setAzionArgs()` is called in `azion.ts`\n2. Config modules use `getEnv()` from `env.ts`\n\n### CI/CD Integration\n\n```yaml\n# GitHub Actions example\n- name: Deploy to Azion\n  run: |\n    cat \u003e .env \u003c\u003c EOF\n    SSO_MODE=${{ vars.SSO_MODE }}\n    SSO_GQL_SECRET=${{ secrets.SSO_GQL_SECRET }}\n    EOF\n    \n    azion login --token ${{ secrets.AZION_TOKEN }}\n    ./scripts/deploy.sh\n```\n\n---\n\n## Related Libraries\n\n### @azion/js-auth\n\nAuthentication library for Azion Edge Functions.\n\n- [Documentation](./js-azion-auth/README.md)\n- [Repository](https://github.com/aziontech/js-azion-auth)\n\n### @azion/js-api-errors\n\nError handling library following JSON:API specification.\n\n- [Documentation](./js-azion-api-errors/README.md)\n- [Repository](https://github.com/aziontech/js-azion-api-errors)\n\n---\n\n## Maintainers\n\n- [**Team Product #1**](mailto:core-squad@azion.com)\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faziontech%2Fjs-azion-api-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faziontech%2Fjs-azion-api-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faziontech%2Fjs-azion-api-example/lists"}