{"id":29395125,"url":"https://github.com/neilveil/express-tools","last_synced_at":"2025-07-10T11:14:53.150Z","repository":{"id":190359119,"uuid":"400094277","full_name":"neilveil/express-tools","owner":"neilveil","description":"NodeJS back-end framework built on top of Express.","archived":false,"fork":false,"pushed_at":"2025-04-06T11:36:00.000Z","size":833,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-09T11:49:22.503Z","etag":null,"topics":["api","backend","caching","development","encryption","express","expressjs","framework","logging","response","server","validation"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/express-tools","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/neilveil.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","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}},"created_at":"2021-08-26T08:20:23.000Z","updated_at":"2025-04-06T11:36:04.000Z","dependencies_parsed_at":"2024-01-06T07:02:12.852Z","dependency_job_id":null,"html_url":"https://github.com/neilveil/express-tools","commit_stats":null,"previous_names":["neilveil/express-tools"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/neilveil/express-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neilveil%2Fexpress-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neilveil%2Fexpress-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neilveil%2Fexpress-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neilveil%2Fexpress-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neilveil","download_url":"https://codeload.github.com/neilveil/express-tools/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neilveil%2Fexpress-tools/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264473756,"owners_count":23613954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["api","backend","caching","development","encryption","express","expressjs","framework","logging","response","server","validation"],"created_at":"2025-07-10T11:14:50.857Z","updated_at":"2025-07-10T11:14:53.145Z","avatar_url":"https://github.com/neilveil.png","language":"TypeScript","readme":"# Express Tools - The Server Wizard 🚀\r\n\r\n[![Downloads](https://img.shields.io/npm/dm/express-tools.svg)](https://www.npmjs.com/package/express-tools) [![Version](https://img.shields.io/npm/v/express-tools.svg)](https://www.npmjs.com/package/express-tools)\r\n\r\n**Strictly typed, production-ready, no-configuration server.**\r\n\r\nExpress Tools allows you to build a **conventional API server** or a **strictly typed server** using **Typed Bridge**. It simplifies server development with minimal setup, making it easier to maintain type safety across the backend and frontend.\r\n\r\n## 🌟 Key Features\r\n\r\n- **API Server**: Production ready API server with 0 configuration.\r\n- **Typed Bridge**: Strictly typed server functions tightly coupled with front-end.\r\n\r\n## 📦 Installation\r\n\r\nInstall Express Tools via npm:\r\n\r\n```bash\r\nnpm i express-tools\r\n```\r\n\r\n## Build API Server\r\n\r\nAPI server components:\r\n\r\n- Express App: `const app = createApp()`\r\n- Server: `const server = startServer(app, 8080)`\r\n- Controller: `_c(async (args, context) =\u003e {})`\r\n- Validator: Request handler `_v({})`\r\n- Context middleware: `etConfig.contextParser = (req: Request) =\u003e { return {} }`\r\n\r\n### Create express app \u0026 start server\r\n\r\n```ts\r\nimport { createApp, startServer } from 'express-tools'\r\n\r\nconst app = createApp()\r\nconst server = startServer(app, 8080)\r\n```\r\n\r\nTest server: `http://localhost:8080/health`\r\n\r\n### Add new route\r\n\r\n```ts\r\nimport { _c } from 'express-tools'\r\n\r\napp.post(\r\n  // Route\r\n  '/demo',\r\n  // Controller\r\n  _c(async (args: { id: number }) =\u003e {\r\n    console.log(args.id)\r\n    return { id: args.id, name: 'Express Tools' }\r\n  })\r\n)\r\n```\r\n\r\n### Validate request with `zod`\r\n\r\n```ts\r\nimport { _c, $z } from 'express-tools'\r\n\r\nconst demoRequest = { id: $z.number().min(1) }\r\n\r\napp.post(\r\n  // Route\r\n  '/demo',\r\n  // Validator\r\n  _v({ id: $z.number().min(1) }),\r\n  // Controller\r\n  _c(async (args: { id: number }) =\u003e {\r\n    return { id: args.id, name: 'Express Tools' }\r\n  })\r\n)\r\n```\r\n\r\nUse `ajv` or `joi` validator\r\n\r\n```ts\r\n// AJV\r\nimport { $a } from 'express-tools'\r\netConfig.validator = 'ajv'\r\n\r\n// Joi\r\nimport { $j } from 'express-tools'\r\netConfig.validator = 'joi'\r\n```\r\n\r\n### Add context middleware\r\n\r\n```ts\r\nimport { etConfig } from 'express-tools'\r\n\r\ntype context = {\r\n  name: string\r\n  authorization: string\r\n}\r\n\r\netConfig.contextParser = (req: Request): context =\u003e {\r\n  const headers = req.headers\r\n  return { name: 'Express Tools', authorization: headers.authorization || 'NO_AUTH' }\r\n}\r\n\r\napp.post(\r\n  // Route\r\n  '/demo',\r\n  // Validator\r\n  _v({ id: $z.number().min(1) }),\r\n  // Controller\r\n  _c(async (args: { id: number }, context: context) =\u003e {\r\n    return { id: args.id, name: context.name }\r\n  })\r\n)\r\n```\r\n\r\n## Build Typed Bridge\r\n\r\nTyped Bridge components:\r\n\r\n- Bridge file: Main bridge file from which types are exported for front-end.\r\n- Paths: Server function path like `user.fetch`, similar to routes.\r\n- Server functions: Actual server function which holds the business logic, similar to controller.\r\n- Context parser: To provide context from request to server functions.\r\n- Arguments: Server function arguments.\r\n- Context: Server function context parsed with context parser.\r\n\r\n### Create express app \u0026 start server\r\n\r\n`server.ts`\r\n\r\n```ts\r\nimport { createApp, startServer } from 'express-tools'\r\n\r\nconst app = createApp()\r\nconst server = startServer(app, 8080)\r\n```\r\n\r\n### Create Bridge\r\n\r\n`bridge/index.ts`\r\n\r\n```ts\r\nimport * as user from './user.bridge'\r\n\r\nexport default {\r\n  'user.fetch': user.fetch,\r\n  'user.update': user.update\r\n}\r\n```\r\n\r\n`bridge/user.bridge.ts`\r\n\r\n```ts\r\nexport const fetch = async (\r\n  args: { id: number },\r\n  context: { name: string; authorization: string }\r\n): { id: number; name: string } =\u003e {\r\n  return { id: args.id, name: 'Express Tools' }\r\n}\r\n\r\nexport const update = async () =\u003e {}\r\n```\r\n\r\n`server.ts`\r\n\r\n```ts\r\nimport { createBridge } from 'express-tools'\r\n\r\napp.use('/bridge', createBridge(bridge))\r\n```\r\n\r\n### Call Typed Bridge functions from front-end\r\n\r\nGenerate typed bridge file\r\n\r\n`package.json`\r\n\r\n```json\r\n{\r\n  \"scripts\": {\r\n    \"gen-typed-bridge\": \"express-tools gen-typed-bridge --src ./src/bridge/index.ts --dest ./typedBridge.ts\"\r\n  }\r\n}\r\n```\r\n\r\n**src**: Typed Bridge source file\r\n**dest**: Output declaration file path\r\n\r\nImport generated `typedBridge.ts` file in front-end \u0026 call server functions.\r\n\r\n```ts\r\nimport typedBridge from './typedBridge'\r\n\r\n// Need to be set once\r\n// Set typed bridge server host\r\ntypedBridgeConfig.host = 'http://localhost:8080/bridge'\r\n// Set headers (optional)\r\ntypedBridgeConfig.headers = { authorization: 'Basic mydemotoken==' }\r\n\r\n..\r\n\r\nconst user = await typedBridge['user.fetch']({ id: 1 })\r\n```\r\n\r\n\u003e Generated Typed Bridge file can also be hosted publicly as it's doesn't contains any code, only the server functions schema. Every time front-end server started, it can be automatically synced using tools like [clone-kit](https://www.npmjs.com/package/clone-kit).\r\n\r\n## Express Tools config\r\n\r\n```ts\r\nimport { etConfig } from 'express-tools'\r\n\r\netConfig.logs.request = true // Enable request logging\r\netConfig.logs.response = true // Enable response logging\r\netConfig.logs.error = true // Enable error logging\r\n\r\netConfig.idPrefix = '' // Request id prefix (useful in tracing request in microservice architecture)\r\netConfig.responseDelay = 0 // Custom response delay in milliseconds\r\netConfig.gracefulShutdown = false // Wait for processes to complete after shutdown\r\netConfig.validator = 'zod' // Validator to use inside `_v`\r\netConfig.contextParser = (req: Request) =\u003e {} // Middleware to add context with the request\r\n```\r\n\r\n## Developer\r\n\r\nDeveloped \u0026 maintained by [neilveil](https://github.com/neilveil). Give a star to support my work.\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneilveil%2Fexpress-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneilveil%2Fexpress-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneilveil%2Fexpress-tools/lists"}