{"id":26452961,"url":"https://github.com/q00/api_server_boilerplate","last_synced_at":"2025-10-08T17:12:42.284Z","repository":{"id":43650005,"uuid":"236033217","full_name":"Q00/api_server_boilerplate","owner":"Q00","description":"typescript express board boilerplate using routing controller","archived":false,"fork":false,"pushed_at":"2023-01-24T01:17:26.000Z","size":1235,"stargazers_count":76,"open_issues_count":27,"forks_count":9,"subscribers_count":1,"default_branch":"development","last_synced_at":"2025-04-04T13:44:41.203Z","etag":null,"topics":["action","back-end","docker","oauth","project-template","redoc","routing-controller","sentry","server","service","starter-template","swagger","typeorm","typescript","typescript-express-boilerplate"],"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/Q00.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-24T15:57:48.000Z","updated_at":"2025-03-02T14:54:38.000Z","dependencies_parsed_at":"2023-02-13T08:15:39.292Z","dependency_job_id":null,"html_url":"https://github.com/Q00/api_server_boilerplate","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/Q00/api_server_boilerplate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Q00%2Fapi_server_boilerplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Q00%2Fapi_server_boilerplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Q00%2Fapi_server_boilerplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Q00%2Fapi_server_boilerplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Q00","download_url":"https://codeload.github.com/Q00/api_server_boilerplate/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Q00%2Fapi_server_boilerplate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278981518,"owners_count":26079640,"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-10-08T02:00:06.501Z","response_time":56,"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":["action","back-end","docker","oauth","project-template","redoc","routing-controller","sentry","server","service","starter-template","swagger","typeorm","typescript","typescript-express-boilerplate"],"created_at":"2025-03-18T18:40:43.891Z","updated_at":"2025-10-08T17:12:42.279Z","avatar_url":"https://github.com/Q00.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eWelcome to api_server_boilerplate 👋\u003c/h1\u003e\n\u003cp\u003e\n  \u003cimg alt=\"Version\" src=\"https://img.shields.io/badge/version-1.0.0-blue.svg?cacheSeconds=2592000\" /\u003e\n  \u003ca href=\"https://github.com/Q00/api_server_boilerplate/blob/development/README.md\" target=\"_blank\"\u003e\n    \u003cimg alt=\"Documentation\" src=\"https://img.shields.io/badge/documentation-yes-brightgreen.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"#\" target=\"_blank\"\u003e\n    \u003cimg alt=\"License: MIT\" src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href =\"https://github.com/google/gts\"\u003e\u003cimg alt=\"Cody Style: Google\" src=\"https://img.shields.io/badge/code%20style-google-blueviolet.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e easy to use typescript express boilerplate. You can use board api, user api, error tracking etc..\n\n---\n\n### 🏠 [Homepage](https://github.com/Q00/api_server_boilerplate/blob/development/README.md)\n\n## Install\n\n```sh\nyarn install\n# after put your env flie\nyarn db:dev sync # development environment\n# or\nyarn db:sync # production environment\n```\n\n## Usage\n\n```sh\nyarn dev # development environment\nyarn start # production environment\n```\n\n## Run tests\n\n```sh\nyarn prepare\nyarn build\nyarn test\n\n```\n\nOr you can use debug with vscode\n\n## code\n\n### model\n\nThere are base models. You can extend this base models.\n\n#### Base model\n\n```typescript\nexport abstract class BaseModel {\n  @IsInt()\n  @Generated('increment')\n  @PrimaryColumn({ type: 'bigint', transformer: [bigIntTransformer] })\n  id!: number;\n\n  @IsDate()\n  @CreateDateColumn()\n  createdAt!: Date;\n\n  @IsDate()\n  @UpdateDateColumn()\n  updatedAt!: Date;\n\n  @IsDate()\n  @Column({ nullable: true, type: 'date', default: null })\n  deletedAt?: Date | null;\n}\n```\n\nAlso There are base board, base comment model.\n\n#### Base board model\n\n```typescript\n// you can extends this class making child board and add user\n\nexport abstract class BaseBoard extends BaseModel {\n  @Column({ length: 50 })\n  @IsString()\n  title!: string;\n\n  @IsString()\n  @Column({ type: 'text' })\n  content!: string;\n\n  @IsInt()\n  @Column({ default: 0 })\n  reportCount!: number;\n}\n```\n\n#### Base comment model\n\n```typescript\n// you can extends this class making child comment and add user\n\nexport abstract class BaseComment extends BaseModel {\n  @Column({ length: 50 })\n  @IsString()\n  @MaxLength(50)\n  comment!: string;\n\n  @Column({ default: 0 })\n  @IsInt()\n  reportCount!: number;\n}\n```\n\n### service\n\nThrer are base services. You can extend this base services to other child service.\n\n#### Base service\n\n```typescript\n// you can extends this BaseService to use common method\n\nexport abstract class BaseService\u003cT extends BaseModel\u003e {\n  protected genericRepository: Repository\u003cT\u003e;\n  private repo: ObjectType\u003cT\u003e;\n  constructor(repo: ObjectType\u003cT\u003e) {\n    this.genericRepository = getConnection().getRepository(repo);\n    this.repo = repo;\n  }\n}\n```\n\nAnd then you just call super call with your using repository\n\n```typescript\n  constructor() {\n    super(RepoName);\n  }\n```\n\n#### Base board service\n\n```typescript\n@Service()\nexport abstract class BaseBoardService\u003cT extends BaseBoard\u003e extends BaseService\u003c\n  T\n\u003e {\n  constructor(repo: ObjectType\u003cT\u003e) {\n    super(repo);\n  }\n}\n```\n\nThis service is base board service. In this service, there are common method about board. You can extend this service to other child board service.\n\n#### Base comment service\n\n```typescript\nexport abstract class BaseCommentService\u003c\n  T extends BaseComment\n\u003e extends BaseService\u003cT\u003e {\n  constructor(repo: ObjectType\u003cT\u003e) {\n    super(repo);\n  }\n}\n```\n\nThis service is base comment service. This service is very similar to base board service.\n\n### Provider\n\nThis module makes OAUTH logic. You can use base provider to extends other OAUTH.\n\n```typescript\nexport abstract class BaseProvider {\n  protected accessToken: string;\n  protected instance: AxiosInstance | null;\n  constructor() {\n    this.accessToken = '';\n    this.instance = null;\n  }\n  setToken(accessToken: string) {\n    this.accessToken = accessToken;\n  }\n\n  setInstance(url: string, headers: object) {\n    this.instance = apiClient(url, headers);\n    this.instance.interceptors.response.use(\n      (response) =\u003e response,\n      (err) =\u003e Promise.reject(err),\n    );\n  }\n\n  getInstance() {\n    return this.instance;\n  }\n\n  async generateToken(userId: number) {\n    return `Bearer ${Authentication.generateToken(userId)}`;\n  }\n}\n```\n\nAuth Conroller use this provider to make JWT token.\n\n### Controller\n\nThere are BaseAuthController, BaseCommentController and Other Controller. This project use [routing-controllers](https://github.com/typestack/routing-controllers) and [typedi](https://github.com/typestack/typedi). Thier README help you understand this architecture.\n\n#### Base Auth Controller\n\n```typescript\nexport class BaseAuthController\u003cT extends BaseProvider\u003e extends BaseController {\n  // this can be used in child class (ExampleAuthController)\n  protected userAccountService: UserAccountService;\n  protected userService: UserService;\n  constructor(protected provider: T) {\n    super();\n    this.provider = provider;\n    this.userAccountService = Container.get(UserAccountService);\n    this.userService = Container.get(UserService);\n  }\n}\n```\n\n#### Base Comment Controller\n\n```typescript\nexport abstract class BaseCommentController\u003c\n  U extends BaseComment,\n  T extends BaseCommentService\u003cU\u003e\n\u003e extends BaseController {\n  protected service: T;\n  constructor(service: T) {\n    super();\n    this.service = service;\n  }\n}\n```\n\nIf you want to extends this controller, you should call super with service like below.\n\n```typescript\n@JsonController('/example_board_comment')\nexport class ExampleBoardCommentController extends BaseCommentController\u003c\n  ExampleBoardComment,\n  ExampleBoardCommentService\n\u003e {\n  //this private service automaticaly injected by typedi\n  constructor(private exampleBoardCommentService: ExampleBoardCommentService) {\n    super(exampleBoardCommentService);\n  }\n}\n```\n\n### DTO\n\nTo make request schema, this project use [class-validator](https://github.com/typestack/class-validator). This request schema will be shown in swagger ui or Redoc.\n\n### Interceptor\n\nThis module use [routing-controllers](https://github.com/typestack/routing-controllers) interceptor\n\n### Middleware\n\nThis module use [routing-controllers](https://github.com/typestack/routing-controllers) Middleware\n\n### Database\n\nThis project use [typeorm](https://typeorm.io/) and connect with [Postgres](https://www.postgresql.org/).\n\n#### Naming Strategy\n\nusing snake case.\n\n```typescript\nexport class NamingStrategy extends DefaultNamingStrategy {\n  tableName(targetName: string, userSpecifiedName: string | undefined): string {\n    return plural(snakeCase(userSpecifiedName || targetName));\n  }\n\n  relationName(propertyName: string): string {\n    return snakeCase(propertyName);\n  }\n\n  columnName(propertyName: string, customName: string) {\n    return snakeCase(customName || propertyName);\n  }\n\n  joinColumnName(relationName: string, referencedColumnName: string) {\n    return snakeCase(`${relationName}_${referencedColumnName}`);\n  }\n\n  joinTableColumnName(\n    tableName: string,\n    propertyName: string,\n    columnName: string,\n  ) {\n    return snakeCase(`${tableName}_${columnName || propertyName}`);\n  }\n}\n```\n\n#### config\n\n```typescript\nconst typeOrmConfig: PostgresConnectionOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  namingStrategy: new NamingStrategy(),\n  port: Number(process.env.DB_PORT),\n  username: process.env.DB_USER,\n  password: process.env.DB_PW,\n  database: process.env.DATABASE,\n  synchronize: false,\n  logging: false,\n  entities: [`${path.join(__dirname, '..', 'model')}/**.[tj]s`],\n  migrations: [`${path.join(__dirname, '..', 'model')}/migration/**.[tj]s`],\n};\n```\n\n## Env variable\n\n```\nDB_HOST=\nDB_USER=\nDB_PW=\nPORT= # your server port\nDB_PORT=\nDATABASE= # database name\nTEST_TOKEN= # jwt token to use in testing\nSENTRY_DSN= # sentry dsn\n```\n\n## Author\n\n👤 **Q00 \u003cjqyu.lee@gmail.com\u003e**\n\n- Website: https://velog.io/@q00\n- Github: [@Q00](https://github.com/Q00)\n\n## 🤝 Contributing\n\nContributions, issues and feature requests are welcome!\u003cbr /\u003eFeel free to check [issues page](https://github.com/Q00/api_server_boilerplate/issues).\u003cbr/\u003eIf you want to contribute this repo, check [contribute page](./CONTRIBUTING.md)\n\n## 🔍 Relase note \u0026\u0026 Change log\n\nRelease note and change log are exist in [CHANGELOG](./CHANGELOG.md)\n\n## Show your support\n\nGive a ⭐️ if this project helped you!\n\n---\n\n_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fq00%2Fapi_server_boilerplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fq00%2Fapi_server_boilerplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fq00%2Fapi_server_boilerplate/lists"}