{"id":20936285,"url":"https://github.com/danangfir/user-post","last_synced_at":"2025-12-28T07:29:06.517Z","repository":{"id":249561055,"uuid":"831851655","full_name":"danangfir/user-post","owner":"danangfir","description":"Nestjs Authentication and Blog","archived":false,"fork":false,"pushed_at":"2024-07-30T14:23:42.000Z","size":119,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-19T20:01:35.690Z","etag":null,"topics":["bcryptjs","express","jest","jwt","mongodb","mongoose","nestjs","passport","supertest"],"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/danangfir.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}},"created_at":"2024-07-21T19:46:54.000Z","updated_at":"2024-07-30T14:23:45.000Z","dependencies_parsed_at":"2024-07-30T17:57:28.624Z","dependency_job_id":null,"html_url":"https://github.com/danangfir/user-post","commit_stats":null,"previous_names":["danangfir/user-post"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danangfir%2Fuser-post","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danangfir%2Fuser-post/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danangfir%2Fuser-post/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danangfir%2Fuser-post/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danangfir","download_url":"https://codeload.github.com/danangfir/user-post/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243330259,"owners_count":20274037,"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":["bcryptjs","express","jest","jwt","mongodb","mongoose","nestjs","passport","supertest"],"created_at":"2024-11-18T22:19:00.654Z","updated_at":"2025-12-28T07:29:06.465Z","avatar_url":"https://github.com/danangfir.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Kenapa saya memekai pattern ini karena ini praktik terbaik yang dianjurkan dalam pengembangan aplikasi menggunakan NestJS. \n\nMenurut Blog ini:\n\nhttps://medium.com/deno-the-complete-reference/5-best-practices-for-nestjs-applications-831d0566a534\n\nhttps://dev.to/drbenzene/best-nestjs-practices-and-advanced-techniques-9m0\n\nhttps://github.com/weiwensangsang/nestjs-best-practices?tab=readme-ov-file\n\nBerikut adalah penjelasan mengapa pattern ini digunakan dan manfaatnya.\n\n## Modularisasi \n\nModularisasi adalah pemisahan aplikasi menjadi modul-modul kecil yang independen namun saling berinteraksi. Setiap modul memiliki tanggung jawab spesifik dan tidak tergantung pada modul lain untuk fungsionalitas dasarnya\n\nModularisasi memungkinkan kita untuk memisahkan logika aplikasi berdasarkan domain atau fitur, sehingga memudahkan pengembangan, pemeliharaan, dan pengujian\n\nDengan modularisasi, tim yang berbeda dapat bekerja secara paralel pada modul yang berbeda tanpa saling mengganggu\n\nSelain itu, modul yang telah ada dapat dengan mudah digunakan kembali dalam proyek lain atau di bagian lain dari proyek yang sama.\n\nContoh kodenya:\n```typescript\n// users.module.ts\nimport { Module } from '@nestjs/common';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { UsersService } from './users.service';\nimport { UsersController } from './users.controller';\nimport { User, UserSchema } from './user.schema';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),\n  ],\n  providers: [UsersService],\n  controllers: [UsersController],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n```\nModul ini memisahkan logika terkait pengguna, termasuk skema MongoDB dan layanan pengguna.\n\nContoh Kode Module Utamanya:\n```typescript\n// app.module.ts\nimport { Module } from '@nestjs/common';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { UsersModule } from './users/users.module';\nimport { PostsModule } from './posts/posts.module';\nimport { AuthModule } from './auth/auth.module';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true,\n    }),\n    MongooseModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) =\u003e ({\n        uri: configService.get\u003cstring\u003e('DATABASE_URL'),\n        useNewUrlParser: true,\n        useUnifiedTopology: true,\n      }),\n      inject: [ConfigService],\n    }),\n    UsersModule,\n    PostsModule,\n    AuthModule,\n  ],\n})\nexport class AppModule {}\n```\n`app.module.ts` adalah jantung konfigurasi aplikasi NestJS, mengatur koneksi database, memuat pengaturan, dan menggabungkan berbagai modul fitur untuk membangun aplikasi yang berfungsi secara optimal.\n## Dependency Injection (DI)\n\nDependency Injection adalah teknik di mana objek atau fungsi menerima dependensi yang mereka butuhkan dari luar, bukan menciptakan sendiri\n\nDependency Injection memudahkan pemeliharaan kode karena kita bisa dengan mudah mengganti atau meningkatkan dependensi tanpa mengubah kode yang menggunakan dependensi tersebut\n\nTeknik ini juga meningkatkan testability karena memungkinkan penggunaan mock atau stub untuk dependensi selama pengujian\n\nDependency Injection juga mengurangi keterikatan antara komponen, sehingga setiap komponen dapat berkembang secara mandiri.\n\nContoh Kodenya:\n```typescript\n// auth.service.ts\nimport { Injectable } from '@nestjs/common';\nimport { UsersService } from '../users/users.service';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private usersService: UsersService,\n    private jwtService: JwtService\n  ) {}\n\n  async validateUser(username: string, password: string): Promise\u003cany\u003e {\n    const user = await this.usersService.findOneByUsername(username);\n    if (user \u0026\u0026 user.password === password) {\n      const { password, ...result } = user;\n      return result;\n    }\n    return null;\n  }\n\n  async login(user: any) {\n    const payload = { username: user.username, sub: user._id };\n    return {\n      access_token: this.jwtService.sign(payload),\n    };\n  }\n}\n```\nDi sini, `AuthService` menerima `UsersService` sebagai dependensi melalui DI, memungkinkan `AuthService` menggunakan metode yang disediakan oleh `UsersService`.\n\n## MVC (Model-View-Controller)\n\nMVC adalah arsitektur yang memisahkan aplikasi menjadi tiga komponen utama: Model, View, dan Controller\n\nArsitektur MVC memisahkan tanggung jawab antara penyimpanan data (Model), tampilan (View), dan logika aplikasi (Controller)\n\nHal ini memudahkan pemeliharaan kode karena setiap komponen memiliki tanggung jawab spesifik\n\nMVC juga memudahkan pengembangan dan peningkatan fitur baru tanpa mempengaruhi komponen lain.\n\nContoh kodenya:\n```typescript\n// posts.controller.ts\nimport { Controller, Get, Post, Body, Param, Put, Delete, BadRequestException } from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { Post as PostModel } from './post.schema';\n\n@Controller('posts')\nexport class PostsController {\n  constructor(private readonly postsService: PostsService) {}\n\n  @Get()\n  async findAll(): Promise\u003cPostModel[]\u003e {\n    return this.postsService.findAll();\n  }\n\n  @Get(':id')\n  async findOne(@Param('id') id: string): Promise\u003cPostModel\u003e {\n    if (!id || id.length !== 24) {\n      throw new BadRequestException('Invalid Post ID');\n    }\n    return this.postsService.findOne(id);\n  }\n\n  @Post()\n  async create(@Body() post: { title: string; content: string; userId: string }): Promise\u003cPostModel\u003e {\n    if (!post.userId) {\n      throw new BadRequestException('User ID is required');\n    }\n    return this.postsService.create(post);\n  }\n\n  @Put(':id')\n  async update(@Param('id') id: string, @Body() post: { title: string; content: string; userId: string }): Promise\u003cPostModel\u003e {\n    if (!post.userId) {\n      throw new BadRequestException('User ID is required');\n    }\n    if (!id || id.length !== 24) {\n      throw new BadRequestException('Invalid Post ID');\n    }\n    return this.postsService.update(id, post);\n  }\n\n  @Delete(':id')\n  async remove(@Param('id') id: string): Promise\u003cvoid\u003e {\n    if (!id || id.length !== 24) {\n      throw new BadRequestException('Invalid Post ID');\n    }\n    await this.postsService.remove(id);\n  }\n}\n```\nDi sini, `PostsController` mengelola permintaan HTTP dan berinteraksi dengan `PostsService` yang mengelola logika bisnis dan berinteraksi dengan `Post` model.\n\n## E2E Testing (End-to-End Testing)\n\nE2E Testing adalah metode pengujian di mana seluruh alur kerja aplikasi diuji dari awal hingga akhir untuk memastikan bahwa semua bagian sistem berfungsi bersama-sama seperti yang diharapkan\n\nE2E Testing memastikan bahwa semua komponen aplikasi berfungsi bersama dengan baik dan memungkinkan kita mendeteksi masalah yang mungkin tidak terlihat dalam pengujian unit atau pengujian integrasi\n\nPengujian ini sangat penting untuk memastikan bahwa aplikasi berfungsi dengan baik dari perspektif pengguna akhir.\n\nContoh kodenya:\n```typescript\n// tests/posts.e2e-spec.ts\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport request from 'supertest';\nimport { AppModule } from '../src/app.module';\n\ndescribe('PostsController (e2e)', () =\u003e {\n  let app: INestApplication;\n\n  beforeAll(async () =\u003e {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('should create a post', async () =\u003e {\n    const userResponse = await request(app.getHttpServer())\n      .post('/users')\n      .send({ username: 'testuser', password: 'testpassword' })\n      .expect(201);\n\n    const userId = userResponse.body._id;\n\n    await request(app.getHttpServer())\n      .post('/posts')\n      .send({ title: 'Test Post', content: 'This is a test post', userId })\n      .expect(201)\n      .then((response) =\u003e {\n        expect(response.body).toHaveProperty('_id');\n        expect(response.body.title).toBe('Test Post');\n        expect(response.body.content).toBe('This is a test post');\n        expect(response.body.user).toBe(userId);\n      });\n  });\n\n  it('should retrieve all posts', async () =\u003e {\n    await request(app.getHttpServer())\n      .get('/posts')\n      .expect(200)\n      .then((response) =\u003e {\n        expect(Array.isArray(response.body)).toBe(true);\n      });\n  });\n\n  afterAll(async () =\u003e {\n    await app.close();\n  });\n});\n\n```\nPengujian ini memastikan bahwa endpoint `POST /posts` dapat membuat posting baru dan endpoint `GET /posts` dapat mengambil semua posting yang ada. Ini memverifikasi bahwa berbagai komponen aplikasi berfungsi bersama-sama dengan benar.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanangfir%2Fuser-post","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanangfir%2Fuser-post","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanangfir%2Fuser-post/lists"}