Skip to content

Commit

Permalink
Feat/suggest: 검색어 추천 endpoint 개발 (#20)
Browse files Browse the repository at this point in the history
Add suggest
  • Loading branch information
saehun authored Jun 29, 2024
1 parent 77e8193 commit c0231e8
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 0 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@
"globals": "^15.6.0",
"husky": "^9.0.11",
"jest": "^29.7.0",
"nock": "beta",
"prettier": "^3.3.2",
"prettier-2": "npm:prettier@^2",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.1.4",
Expand Down Expand Up @@ -116,6 +118,7 @@
"moduleNameMapper": {
"src/(.*)": "<rootDir>/$1"
},
"prettierPath": "<rootDir>/../node_modules/prettier-2/index.js",
"collectCoverageFrom": [
"**/*.(t|j)s"
],
Expand Down
45 changes: 45 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AuthModule } from './auth/auth.module';
import { getNodeEnv, isIgnoreEnvFile } from './common/helper/env.helper';
import { envValidation } from './common/helper/env.validation';
import { MapModule } from './map/map.module';
import { SearchModule } from './search/search.module';
import { UserMapModule } from './user-map/user-map.module';
import { UserModule } from './user/user.module';

Expand All @@ -28,6 +29,7 @@ import { UserModule } from './user/user.module';
UserModule,
MapModule,
UserMapModule,
SearchModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
170 changes: 170 additions & 0 deletions src/search/__fixtures__/search-suggest-01.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
[
{
"scope": "https://m.map.kakao.com:443",
"method": "GET",
"path": "/actions/topSuggestV2Json?q=%EA%B3%B1%EC%B0%BD",
"body": "",
"status": 200,
"response": {
"q": "곱창",
"rq": "곱창",
"items": [
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창전골|place",
"key": "곱창전골",
"score": 205.53566862626099
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창집|place",
"key": "곱창집",
"score": 188.05446693446845
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창맛집|place",
"key": "곱창맛집",
"score": 187.20548426318587
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창고|place",
"key": "곱창고",
"score": 177.7693456159605
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창이야기|place",
"key": "곱창이야기",
"score": 175.4641633711495
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창볶음|place",
"key": "곱창볶음",
"score": 174.47027860114386
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창폭식|place",
"key": "곱창폭식",
"score": 173.9772509479613
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창의전설|place",
"key": "곱창의전설",
"score": 173.011751714487
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창구이|place",
"key": "곱창구이",
"score": 172.63051232821823
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창전골맛집|place",
"key": "곱창전골맛집",
"score": 171.64443962743806
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창정비소|place",
"key": "곱창정비소",
"score": 169.5483065183115
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창파는고깃집|place",
"key": "곱창파는고깃집",
"score": 168.73967615372476
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창가|place",
"key": "곱창가",
"score": 167.4168741919948
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창왕김형제|place",
"key": "곱창왕김형제",
"score": 167.2548433301668
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창마을|place",
"key": "곱창마을",
"score": 166.55224354053973
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창나라|place",
"key": "곱창나라",
"score": 166.22590587972797
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창대장|place",
"key": "곱창대장",
"score": 166.09255893492133
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창팩토리|place",
"key": "곱창팩토리",
"score": 166.03831590679385
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창국수|place",
"key": "곱창국수",
"score": 164.5045396989028
},
{
"category": "place",
"highlighted": [[0, 2]],
"item": "곱창지존|place",
"key": "곱창지존",
"score": 163.88699427428617
}
]
},
"rawHeaders": [
"Date",
"Sat, 29 Jun 2024 07:48:32 GMT",
"Content-Type",
"application/json;charset=UTF-8",
"Content-Length",
"2457",
"Connection",
"keep-alive",
"Content-Language",
"ko-KR",
"Strict-Transport-Security",
"max-age=15724800; includeSubDomains"
],
"responseIsBinary": false
}
]
16 changes: 16 additions & 0 deletions src/search/search.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Controller, Get, Query } from '@nestjs/common';
import { ApiQuery, ApiTags } from '@nestjs/swagger';

import { SearchService } from './search.service';

@ApiTags('search')
@Controller('search')
export class SearchController {
constructor(private readonly searchService: SearchService) {}

@ApiQuery({ type: String, name: 'q', description: '검색을 원하는 질의어' })
@Get('suggest')
async searchPlace(@Query('q') q: string) {
return await this.searchService.suggest(q);
}
}
12 changes: 12 additions & 0 deletions src/search/search.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';

import { SearchController } from './search.controller';
import { SearchService } from './search.service';

@Module({
imports: [HttpModule],
controllers: [SearchController],
providers: [SearchService],
})
export class SearchModule {}
43 changes: 43 additions & 0 deletions src/search/search.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { HttpService } from '@nestjs/axios';

import nock from 'nock';

import { SearchService } from './search.service';

nock.back.fixtures = `${__dirname}/__fixtures__`;

describe('search.service', () => {
const sut = new SearchService(new HttpService());

it('can suggest search keyword', async () => {
nock.back.setMode('lockdown');
const { nockDone } = await nock.back('search-suggest-01.json');
const result = await sut.suggest('곱창');

nockDone();
expect(result).toMatchInlineSnapshot(`
[
"곱창전골",
"곱창집",
"곱창맛집",
"곱창고",
"곱창이야기",
"곱창볶음",
"곱창폭식",
"곱창의전설",
"곱창구이",
"곱창전골맛집",
"곱창정비소",
"곱창파는고깃집",
"곱창가",
"곱창왕김형제",
"곱창마을",
"곱창나라",
"곱창대장",
"곱창팩토리",
"곱창국수",
"곱창지존",
]
`);
});
});
Loading

0 comments on commit c0231e8

Please sign in to comment.