{"id":18743233,"url":"https://github.com/anthonybudd/express-ts-api-template","last_synced_at":"2025-09-03T07:42:06.903Z","repository":{"id":244841784,"uuid":"804671566","full_name":"anthonybudd/Express-ts-API-Template","owner":"anthonybudd","description":"Production-ready minimal REST API boilerplate using Express.js, Sequelize and MySQL.","archived":false,"fork":false,"pushed_at":"2025-07-17T21:58:31.000Z","size":1145,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-18T02:11:33.460Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anthonybudd.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":"2024-05-23T03:29:59.000Z","updated_at":"2025-07-17T21:58:34.000Z","dependencies_parsed_at":"2024-06-27T01:41:53.038Z","dependency_job_id":"28939f3b-faad-4b83-8752-084777652c43","html_url":"https://github.com/anthonybudd/Express-ts-API-Template","commit_stats":null,"previous_names":["anthonybudd/express-ts-api-boilerplate","anthonybudd/express-ts-api-template"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/anthonybudd/Express-ts-API-Template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonybudd%2FExpress-ts-API-Template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonybudd%2FExpress-ts-API-Template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonybudd%2FExpress-ts-API-Template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonybudd%2FExpress-ts-API-Template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anthonybudd","download_url":"https://codeload.github.com/anthonybudd/Express-ts-API-Template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthonybudd%2FExpress-ts-API-Template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273410260,"owners_count":25100451,"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","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"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":"2024-11-07T16:10:39.741Z","updated_at":"2025-09-03T07:42:06.891Z","avatar_url":"https://github.com/anthonybudd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Express.ts API Template\n\n\u003cimg height=\"75\" src=\"https://raw.githubusercontent.com/anthonybudd/anthonybudd/master/img/express-ts-api-template.png?v=1\"/\u003e\n\nA very mimimal REST API template using Express.ts, Sequelize and MySQL. This project is designed to work out of the box with [AnthonyBudd/Vuetify-SPA-Template](https://github.com/anthonybudd/Vuetify-SPA-template)\n\n\n- 🔐 Auth using JWT's with Passport.js. Optional 2FA.\n- 👥 Simple DB: `Users` -∈ `GroupsUsers` ∋- `Groups`\n- 🌐 Production-ready [OpenApiSpec.yml](./OpenApiSpec.yml) \u0026 [Kubernetes files](./k8s)\n- 🥇 Real-world tested, generated over $50M in revenue\n\n\n```sh\ngit clone git@github.com:anthonybudd/express-ts-api-template.git\ncd express-ts-api-template\n\n# [Optional] Find \u0026 Replace (case-sensaive, whole repo): \"express-api\" =\u003e \"your-api-name\" \nLC_ALL=C find . -type f -name '*.*' -exec sed -i '' s/express-api/your-api-name/g {} +\n\n# Private RSA key for JWT signing\nopenssl genrsa -out private.pem 2048\nopenssl rsa -in private.pem -outform PEM -pubout -out public.pem\n\n# Start app\ncp .env.example .env\nnpm install\ndocker compose up\nnpm run exec:db:refresh\nnpm run exec:test\n\n# [Optional] Code generation command\nnpm run generate -- --model=\"Book\"\nnpm run exec:db:refresh\n```\n\n### DB Structure\nThe DB structure is the optimum balance of functionality and minimalism. A User can belong to many Groups through the GroupsUsers table. This allows you to make very basic single-user applications that do not even require the concept of groups or full SaaS solutions with complex User-Group relationships.\n\n```                                                                \n+--------------+           +---------------+         +--------------+  \n|Users         | --------∈ |GroupsUsers    | ∋------ |Groups        |  \n|--------------|           |---------------|         |--------------|  \n|id            |           |id             |         |id            |  \n|email         |           |groupID        |         |name          |  \n|password      |           |userID         |         |ownerID       |  \n|firstName     |           |role           |         |createdAt     |  \n|lastName      |           |createdAt      |         |updatedAt     |\n|createdAt     |           |updatedAt      |         +--------------+  \n|updatedAt     |           +---------------+                                            \n|...           |                                                      \n+--------------+                      \n```\n### OpenAPISpec\nAbove each route you will see a large comment block, these comments are optional and can be removed if you do not need/want them. \n\nI have found when building large commercial API's that it is far more practical to document the routes next to the code rather than manually updating the OpenAPISpec each time a route is created or modified.\n\n```js\n/**\n * @swagger\n * /auth/login:\n *   post:\n *     description: Get an access token\n *     requestBody:\n *       required: true\n *       content:\n *         application/json:\n *         ... \n */\napp.post('/auth/login', [...\n```\n\nTo auto generate a new OpenAPISpec run the command below\n```sh\nnpm run exec:openapispec\n```\n\n### Generate SDK Client Libraries\nThere is an [OpenAPISpec](./OpenApiSpec.yml) in the root of the repo. The project includes code generation config files for PHP, JavaScript and Swift. Use the below command to generate SDK Client Libraries for your API to `/sdk/dist`. A full list of supported langauages [can be found here.](https://github.com/OpenAPITools/openapi-generator?tab=readme-ov-file#overview)\n\n\n```sh\ndocker run --rm \\\n  -v ${PWD}:/app \\\n  -w /app \\\n  openapitools/openapi-generator-cli batch sdk/config/*.yaml\n```\n\n### Deployment\nFull Kubernetes deployment instructions can be found in [k8s/Deployment.md](./k8s/Deployment.md).\n\n- [api.deployment.yml](./k8s/api.deployment.yml)\n- [api.service.yml](./k8s/api.service.yml)\n- [api.ingress.yml](./k8s/api.ingress.yml)\n\n```sh\nkubectl apply -f .k8s/api.deployment.yml \\\n  -f .k8s/api.ingress.yml \\\n  -f .k8s/api.service.yml \n```\n\n\n### Routes\n| Method      | Route                                                           | Description                           | Payload                               | Response          | \n| ----------- | --------------------------------------------------------------- | ------------------------------------- | ------------------------------------- | ----------------- |  \n| GET         | `/_readiness`                                                   | Kuber readiness check                 | --                                    | \"healthy\"         |  \n| GET         | `/api/v1/_healthcheck`                                          | Returns {status: 'ok'} if healthy     | --                                    | {status: 'ok'}    |  \n| **Auth**    |                                                                 |                                       |                                       |                   |  \n| POST        | `/api/v1/auth/login`                                            | Login                                 | {email, password}                     | {accessToken}     |  \n| POST        | `/api/v1/auth/sign-up`                                          | Sign-up                               | {email, password, firstName, tos}     | {accessToken}     |  \n| GET         | `/api/v1/_authcheck`                                            | Returns {auth: true} if has auth      | --                                    | {auth: true}      |  \n| GET         | `/api/v1/auth/verify-email/:emailVerificationKey`               | Verify email                          | --                                    | {success: true}   |  \n| GET         | `/api/v1/auth/resend-verification-email`                        | Resend verification email             | --                                    | {email}           |  \n| POST        | `/api/v1/auth/forgot`                                           | Forgot                                | {email}                               | {success: true}   |  \n| GET         | `/api/v1/auth/get-user-by-reset-key/:passwordResetKey`          | Get user for given `passwordResetKey` | --                                    | {id, email}       |  \n| POST        | `/api/v1/auth/reset`                                            | Reset password                        | {email, password, passwordResetKey}   | {accessToken}     |  \n| GET         | `/api/v1/auth/get-user-by-invite-key/:inviteKey`                | Get user for given `inviteKey`        | --                                    | {id, email}       |  \n| POST        | `/api/v1/auth/invite`                                           | Complete user invite process          | {inviteKey, email, password, ...}     | {accessToken}     |   \n| **User**    |                                                                 |                                       |                                       |                   |  \n| GET         | `/api/v1/user`                                                  | Get the current user                  |                                       | {User}            |  \n| POST        | `/api/v1/user`                                                  | Update the current user               | {firstName, lastName}                 | {User}            |  \n| POST        | `/api/v1/user/update-password`                                  | Update password                       | {password, newPassword}               | {success: true}   |\n| **Groups**  |                                                                 |                                       |                                       |                   |  \n| GET         | `/api/v1/groups/:groupID`                                       | Returns group by ID                   | --                                    | {Group}           |  \n| POST        | `/api/v1/groups/:groupID`                                       | Update group by ID                    | {name: 'New Name'}                    | {Group}           |  \n| POST        | `/api/v1/groups/:groupID/users/invite`                          | Invite user to group                  | {email}                               | {UserID, GroupID} |  \n| POST        | `/api/v1/groups/:groupID/users/:userID/resend-invitation-email` | Resend invitation email               | {}                                    | {email}           |  \n| POST        | `/api/v1/groups/:groupID/users/:userID/set-role`                | Set user role                         | {role: 'User'/'Admin' }               | {UserID, role}    |  \n| DELETE      | `/api/v1/groups/:groupID/users/:userID`                         | Remove user from group                | --                                    | {UserID}          |  \n\n### Commands\nThere are a few helper scripts and commands for interacting with the application.\n\nSome commands need to be run inside the docker container, these commands have been aliased with an underscore prefix, for exmaple `npm run exec:db:refresh` is an alias for `docker exec -ti express-api npm run db:refresh` which actually runs `./src/scripts/refresh`\n| Command               | Description                   | Exmaple                          | \n| --------------------- | ----------------------------- | -------------------------------- |\n| generate.ts           | Code generation               | `npm run generate -- --model=\"book\"` |\n| renderEmail.ts        | Generate an email locally     | `docker exec -ti express-api ts-node ./src/scripts/renderEmail.ts --template=\"Verify\" --code=\"512616\" --link=\"https://google.com\"` |\n| jwt.ts                | Generate JWT for a user       | `docker exec -ti express-api ts-node ./src/scripts/jwt.ts --userID=\"c4644733-deea-47d8-b35a-86f30ff9618e\"` |\n| forgotPassword.ts     | Generate password reset link  | `docker exec -ti express-api ts-node ./src/scripts/forgotPassword.ts --userID=\"c4644733-deea-47d8-b35a-86f30ff9618e\"` |\n| setPassword.ts        | Set user password             | `docker exec -ti express-api ts-node ./src/scripts/setPassword.ts --userID=\"c4644733-deea-47d8-b35a-86f30ff9618e\" --password=\"password\"` |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthonybudd%2Fexpress-ts-api-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanthonybudd%2Fexpress-ts-api-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthonybudd%2Fexpress-ts-api-template/lists"}