[project] ๐ŸŽฌMovyes: ์˜ํ™” ์ปค๋ฎค๋‹ˆํ‹ฐ React ํ”„๋กœ์ ํŠธ - ์˜ํ™” ์ •๋ณด API

์˜ค์˜ค๊ตฌยท2023๋…„ 1์›” 4์ผ
4
post-thumbnail

์˜ํ™” ์ •๋ณด

์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ redux ๋ฐ DB์— ์ €์žฅํ•œ๋‹ค.
๋ฐ์ดํ„ฐ ์ œ๊ณต์€ ์˜คํ”ˆ API๋ฅผ ์‚ฌ์šฉํ•จ.

KMDb : https://www.kmdb.or.kr/info/api/apiDetail/6

์˜ํ™” ์ง„ํฅ ์œ„์›ํšŒ : https://www.kobis.or.kr/kobisopenapi/homepg/apiservice/searchServiceInfo.do?serviceId=searchDailyBoxOffice


์„ธ๋ถ€ ๊ธฐ๋Šฅ ์ •๋ฆฌ

  • ์˜ํ™” ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ์ดํ„ฐ ํŒจ์นญ
    • ๋ฐ•์Šค ์˜คํ”ผ์Šค ์˜ํ™”
    • ์ตœ๊ทผ ๊ฐœ๋ด‰ํ•œ ์˜ํ™”
  • ์ œ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ํŒ์—…์ฐฝ์œผ๋กœ ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ

๊ณ ๋ฏผ

1. API๊ฐ€ ์—†๋‹ค๋‹ˆ..!

๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๋Š”๊ฑด ๊ธˆ๋ฐฉ ํ•˜์ง€!
์ž์‹ ๋งŒ๋งŒํ•˜๊ฒŒ ์‹œ์ž‘ํ–ˆ๋Š”๋ฐ ์˜ˆ์ƒ๋ชปํ•œ ๋‚œ๊ด€์ด ์ƒ๊ฒผ๋‹ค. ๋‚ด๊ฐ€ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” API๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒโ€ฆ OMG
๋‚˜๋Š” ์˜ํ™” ์ค„๊ฑฐ๋ฆฌ์™€ ํฌ์Šคํ„ฐ๊ฐ€ ํฌํ•จ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ๋ฐ ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ์ด๋‚˜ ๋„ค์ด๋ฒ„์—์„œ๋„ ํ•ด๋‹น ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” API๊ฐ€ ์—†์—ˆ๋‹ค. ์ด์ „์— ํ•ด์™ธ ์˜ํ™” API๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋Š” ์˜ํ™” ์ œ๋ชฉ, ์ค„๊ฑฐ๋ฆฌ, ์ธ๋„ค์ผ ๋“ฑ ๋‹ค์–‘ํ•œ ์ •๋ณด๊ฐ€ ๋ชจ๋‘ ์ œ๊ณต๋์–ด์„œ ๋‹น์—ฐํžˆ ๊ตญ๋‚ด API๋„ ๋น„์Šทํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์งˆ ์ค„ ์•Œ์•˜์–ด์„œ ๋ฉ˜๋ถ•์ด์—ˆ๋‹ค.

ํ•œ๊ตญ ๊ธฐ์ค€์˜ ์˜ํ™” ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ด์„œ ๊ผญ ๊ตญ๋‚ด API๊ฐ€ ํ•„์š”ํ–ˆ๋Š”๋ฐ ํฌ๊ธฐํ•ด์•ผํ•˜๋‚˜ ์‹ถ์€ ์ฐฐ๋‚˜ KMDb์—์„œ ์ œ๊ณตํ•˜๋Š” API๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. ์—ฌ๊ธด ์•„๋Š” ์‚ฌ๋žŒ๋„ ์ž˜ ์—†๋Š”๊ฑฐ ๊ฐ™๊ณ  ์ž๋ฃŒ๋„ ๋งŽ์ด ์—†์–ด์„œ ํ™œ์šฉ๋ฐฉ๋ฒ•์€ ๋ณ„๋„์˜ ๊ฒŒ์‹œ๊ธ€๋กœ ๋งŒ๋“œ๋ ค๊ณ  ํ•œ๋‹ค.

์ฃผ์˜ํ•  ์ ์€ API ์„ค๋ช… ๋ฌธ์„œ์˜ ์š”์ฒญ์ธ์ž๊ณผ ์ถœ๋ ฅ๊ฐ’ ๋ณ€์ˆ˜๋ช…์ด ์ข€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. poster๊ฐ™์€ ๊ฒฝ์šฐ๋„ ๋ฌธ์„œ์—๋Š” posterURL์ด๋ผ๊ณ  ๋˜์–ด์žˆ๋Š”๋ฐ ์‹ค์ œ๋กœ๋Š” posters์ž„. ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” ๋ฌธ์„œ์˜ ๋ณ€์ˆ˜๋ช…๊ณผ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ผญ ํ™•์ธํ•˜์ž!

2. ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์€๋ฐ

KMDb์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊ทธ๋ƒฅ ์˜ํ™” ์ •๋ณด๊ฐ€ ์ „๋ถ€์ด๋‹ค. ์ด๋ ‡๊ฒŒ API์ˆ˜๊ธ‰๋‚œ์— ๋น ์งˆ์ค„์€ ์ƒ์ƒ๋„ ๋ชปํ•˜๊ณ  ์ด๋ฏธ ๋ฉ”์ธํ™”๋ฉด์—์„œ ์ธ๊ธฐ ์˜ํ™”๋“ค ์ดค๋ฅด๋ฅต ๋ฉ‹์žˆ๊ฒŒ ๋œจ๋Š”๊ฑฐ ๋‹ค ๊ตฌ์ƒํ•ด๋†จ๋Š”๋ฐ ํ‘ํ‘,,

์•„๋ฌด๋ฆฌ ์ƒ๊ฐํ•ด๋„ ๋ฐ•์Šค์˜คํ”ผ์Šค๋ฅผ ํฌ๊ธฐํ•  ์ˆ˜๊ฐ€ ์—†์–ด์„œ ๋จธ๋ฆฌ๋ฅผ ๊ตด๋ ค๋ดฃ๋‹ค.

๋ฐ•์Šค์˜คํ”ผ์Šค API๋Š” ์˜ํ™” ์ง„ํฅ ์œ„์›ํšŒ์—์„œ ์ œ๊ณตํ•˜๋Š”๋ฐ ๊ฑฐ๊ธด ์ค„๊ฑฐ๋ฆฌ๋ž‘ ํฌ์Šคํ„ฐ ์ •๋ณด๊ฐ€ ์—†๊ณ ... KMDb๋Š” ์ง„์งœ ์˜ํ™”์ •๋ณด๋งŒ ์žˆ๊ณ ... ํ ...

๋‘๊ฐœ ์„ž์–ด์“ฐ๋ฉด ๋˜๊ฒ ๋„ค!

๋ฐฉ๋ฒ•์€ ์˜ ์”ธํ”Œํ•˜๋‹ค.
1. ์ผ๋ณ„ ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋จผ์ € ๋ฐ›์•„์™€์„œ
2. ์‘๋‹ต๋ฐ์ดํ„ฐ ์ค‘ KMDb์š”์ฒญ์ธ์ž๋กœ ์จ๋จน์„ ์ˆ˜ ์žˆ์„๋งŒํ•œ๊ฑธ ๋ฝ‘์•„๋‚ด๊ณ 
3. ๋ฝ‘์•„๋‚ธ ๋ฐ์ดํ„ฐ๋ฅผ KMDb ์š”์ฒญ์ธ์ž๋กœ ๋„ฃ์–ด์„œ ์˜ํ™” ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.

KMDb์—์„œ ๋ฐ•์Šค์˜คํ”ผ์Šค์— ์žˆ๋Š” ์˜ํ™”์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด์™€์•ผ ํ•˜๋ฏ€๋กœ ์š”์ฒญ ์ธ์ž๋ฅผ ์ž˜ ์จ๋จน๋Š”๊ฒŒ ์ œ์ผ ์ค‘์š”ํ–ˆ๋‹ค. ๋‘ API์— ๊ณตํ†ต๋œ ์˜ํ™” ์ฝ”๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์•˜๊ฒ ์ง€๋งŒ ๊ทธ๋Ÿฐ๊ฑด ์—†์—ˆ์Œใ…œใ…œ ๋‚˜๋Š” ์ œ๋ชฉ, ๊ฐœ๋ด‰์ผ, ์ œ์ž‘์—ฐ๋„ ์„ธ๊ฐ€์ง€ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญ ์ธ์ž๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.

3. API ํ˜ธ์ถœ ํšŸ์ˆ˜ ์ œํ•œ

2๋ฒˆ์ฒ˜๋Ÿผ ๋‘ API๋ฅผ ์„ž์–ด์“ฐ๋ฉด ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ ํ˜ธ์ถœ ํšŸ์ˆ˜ ๊ฑฑ์ •์„ ์•ˆํ• ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค.

KMDb์˜ ํ˜ธ์ถœ ์ œํ•œ ํšŸ์ˆ˜๋Š” ์ผ์ผ 1000ํšŒ์ธ๋ฐ
๋ฐ•์Šค์˜คํ”ผ์Šค ๋ชฉ๋ก์„ ๋“ค๊ณ ์˜ฌ๋•Œ ํ•œ๋ฒˆ์— 10๋ฒˆ์”ฉ ํ˜ธ์ถœํ•˜๋‹ˆ๊นŒ.. ํŽ˜์ด์ง€ ๋ฐฑ๋ฒˆ๋งŒ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ๋... ์ด๋ ‡๊ฒŒ ๋ณด๋ฉด ์ ˆ๋Œ€ ๋งŽ์€ ํšŸ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒํ•˜๋ฉด ํ˜ธ์ถœ์„ ๋œ ํ• ์ˆ˜์žˆ์„์ง€ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ db๋ฅผ ํ™œ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

์˜ํ™” ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋จผ์ € db์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์—†๋‹ค๋ฉด api๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ db์—๋„ ์ €์žฅํ•œ๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด ์ตœ์ดˆ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ์˜ํ™”๊ฐ€ ์•„๋‹Œ ์ด์ƒ db์—๋งŒ ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ API ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ๋งŽ์ด ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ ์ตœ์ดˆ ๊ฒ€์ƒ‰์‹œ์—๋Š” db์ ‘๊ทผ๊ณผ apiํ˜ธ์ถœ์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์ง„ํ–‰๋˜๋ฏ€๋กœ ์†๋„๊ฐ€ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ๋‹ค.

4. ์ตœ์‹  ๊ฐœ๋ด‰ ์˜ํ™” ํ•„ํ„ฐ๋ง

API๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฝ‘์•„๋‚ผ ๋•Œ ํ˜„์žฌ์ผ์„ ๊ธฐ์ค€์œผ๋กœ ์ตœ์‹  ๊ฐœ๋ด‰ํ•œ ์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ์ ๋‹นํ•œ ๊ฐฏ์ˆ˜๋งŒํผ ๊ฐ€์ ธ์™€์•ผํ–ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” ๊ธฐ๊ฐ„ ๊ฒ€์ƒ‰์šฉ API ์ธ์ž ์ค‘ ๊ฐœ๋ด‰์ผ ์‹œ์ž‘์„ ์˜๋ฏธํ•˜๋Š” releaseDts ์— ์˜ค๋Š˜ ์ผ์ž๋ฅผ ์ฃผ๊ณ , listCount๋ฅผ 15๊ฐœ๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฝค ๋งŽ์ด ๋ฝ‘์•„์ ธ์„œ ํ•˜๋ฃจ์— ์ด๋ ‡๊ฒŒ ๋งŽ์€ ์˜ํ™”๋“ค์ด ๊ฐœ๋ด‰ํ•˜๋Š”๊ตฌ๋‚˜! ํ•˜๊ณ  ๋„˜์–ด๊ฐˆ ๋ป” ํ–ˆ๋Š”๋ฐ ์•Œ๊ณ ๋ณด๋‹ˆ ๊ฐœ๋ด‰์ผ์ด YYYYMMDD ํฌ๋งท์ด ์•„๋‹ˆ๋ผ YYYY ๋˜๋Š” YYYYMM์ธ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๊ฒ€์ƒ‰๋˜์—ˆ๋˜ ๊ฒƒ์ด์—ˆ๋‹ค. ์ด๊ฑด ์•„์ง ๊ฐœ๋ด‰๋˜์ง€ ์•Š์€ ๊ฐœ๋ด‰ ์˜ˆ์ •์ž‘๋“ค์„ ์˜๋ฏธํ•˜๋Š”๊ฑฐ๋ผ ๋‚˜์—๊ฒ ์“ธ๋ชจ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ผ ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ•์„ ๋ฐ”๊ฟ”์•ผํ–ˆ๋‹ค.

๋‘๋ฒˆ์งธ๋กœ ์ƒ๊ฐํ•œ ๋ฐฉ๋ฒ•์€ ๊ธฐ๊ฐ„ ๊ฒ€์ƒ‰ ์ธ์ž ์ค‘ ๊ฐœ๋ด‰์ผ ์ข…๋ฃŒ ์ธ์ž์ธreleaseDte๋งŒ ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฑฐ์˜€๋‹ค. ๊ฐœ๋ด‰์ผ ์ข…๋ฃŒ ์ธ์ž๋ฅผ ์˜ค๋Š˜๋กœ ์„ค์ •ํ•˜๊ณ  ์ตœ์‹  ์ˆœ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ 15๊ฐœ์ •๋„ ๋ฝ‘์•„๋‚ด๋ฉด ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ๋  ๊ฒƒ ๊ฐ™์•˜๋‹ค.

ํ•˜์ง€๋งŒ ๋‹น์—ฐํ•˜๊ฒŒ๋„ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ ๋˜์ง€ ์•Š์•˜์Œ ใ…Ž
์ •๋ ฌ ์ธ์ž ์ค‘ '์ตœ์‹  ๊ฐœ๋ด‰์ˆœ'์ •๋ ฌ ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๋‹คใ…œใ…œ

๊ฒฐ๊ตญ ๊ทธ๋ƒฅ ๊ฐœ๋ด‰ ์‹œ์ž‘์ผ์ธ releaseDts์™€ releaseDte๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋˜ listCount๋ฅผ 50๊ฐœ์ •๋„ ๋ฝ‘์•„์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค. 50๊ฐœ์ •๋„๋ฅผ ๋ฝ‘์€ ์ด์œ ๋Š” ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์—์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋น„์ •์ƒ ๋‚ ์งœ ํฌ๋งท๊นŒ์ง€ ํ•จ๊ป˜ ๊ฒ€์ƒ‰๋˜์–ด๋ฒ„๋ ค์„œ ๊ทธ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ฑธ๋Ÿฌ์•ผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋“ค์ด ์€๊ทผ ๋งŽ์•„์„œ 50๊ฐœ์ •๋„๋Š” ๊ฐ€์ ธ์™€์•ผ์ง€ 15~20๊ฐœ ์ •๋„์˜ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋‚จ๋”๋ผ.

๊ทธ๋ฆฌ๊ณ  ์ตœ์‹  ์˜ํ™ฉ ๋ฐ์ดํ„ฐ๋„ ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ db์— ์ €์žฅํ•ด์ฃผ์—ˆ๋‹ค. ์ด๊ฑด ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ์ฒ˜๋Ÿผ ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๋ ค๊ณ  ํ•œ๊ฑด ์•„๋‹ˆ๊ณ , ์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ชจ์•„๋‘๋ฉด ์ถ”ํ›„์— ์“ธ ์ผ์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์„œ๋‹ค.


์•„ํ‚คํ…์ฒ˜

๊ด€๋ จ ํด๋”๊ตฌ์กฐ

๐Ÿ“ฆsrc
 โ”ฃ ๐Ÿ“‚api
 โ”ƒ โ”— ๐Ÿ“œfirebase.jsx 
 โ”ฃ ๐Ÿ“‚components 
 โ”ƒ โ”ฃ ๐Ÿ“œMovieCard.jsx
 โ”ƒ โ”ฃ ๐Ÿ“œMovieDetailModal.jsx
 โ”ฃ ๐Ÿ“‚pages
 โ”ƒ โ”ฃ ๐Ÿ“œHome.jsx
 โ”ƒ โ”ฃ ๐Ÿ“œMovies.jsx
 โ”ฃ ๐Ÿ“‚store
 โ”ƒ โ”ฃ ๐Ÿ“œmovie-fetch.jsx
 โ”ƒ โ”— ๐Ÿ“œmovie-store.jsx
 โ”ฃ ๐Ÿ“‚util
 โ”ƒ โ”ฃ ๐Ÿ“œdata.jsx
 โ”ƒ โ”— ๐Ÿ“œdate.jsx
 โ”— ๐Ÿ“œsetupProxy.js
  • ์ƒํƒœ ๊ด€๋ฆฌ๋Š” redux๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค

๋ผ์šฐํŒ…

path='/' element=<Home/>

๊ตฌํ˜„

firebase

// db๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ์ฐพ๊ธฐ
export const searchMovies = async ({ title, releaseDate, movieCode }) => {
  const snapshot = await get(child(dbRef, "/movies"));
  if (snapshot.exists() && snapshot.val() !== null) {
    const values = Object.values(snapshot.val());

    return values.find((movie) => {
      if (movie.title === title && movie.releaseDate === releaseDate) {
        return movie;
      } else if (movie.title === title && movie.movieCode === movieCode) {
        return movie;
      } else {
        return null;
      }
    });
  } else {
    return null;
  }
};

// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ
export const addMovie = async (movie) => {
  try {
    await set(ref(db, `/movies/${movie.id}`), movie);
  } catch (error) {
    return;
  }
};

movie-store

const { configureStore, createSlice } = require("@reduxjs/toolkit");

const moviesSlice = createSlice({
  name: "movies",
  initialState: { boxOffice: [], recent: [], myMovies: [] },
  reducers: {
    getRecentMovies: (state, action) => {
      state.recent = action.payload;
    },
    getBoxOfficeMovies: (state, action) => {
      state.boxOffice = action.payload;
    },
  },
});

export const store = configureStore({
  reducer: { movies: moviesSlice.reducer },
});

export const moviesAction = moviesSlice.actions;

movie-fetch

import axios from "axios";
import { addMovie, searchMovies } from "../api/firebase";
import { dataFormat } from "../util/data";
import { getTodayDate } from "../util/date";
import { moviesAction } from "./movie-store";

/** api ์‚ฌ์šฉ */
const moviesClient = axios.create({
  baseURL: "/search_json2.jsp",
  params: {
    collection: "kmdb_new2",
    ServiceKey: process.env.REACT_APP_MOVIES_SERVICE_KEY,
    detail: "Y",
  },
});

const boxOfficeClient = axios.create({
  baseURL: "/searchDailyBoxOfficeList.json",
  params: {
    key: process.env.REACT_APP_BOX_OFFICE_KEY,
    targetDt: getTodayDate(),
  },
});


// ๋ฆฌ๋•์Šค์— ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ ์ €์žฅ
export const getBoxOfficeMoviesFetch = () => {
  return async (dispatch) => {
    // ๋ฐ•์Šค์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ 
    const boxOfficeData = await getBoxOffice(); 
    if (boxOfficeData) {
      // ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ํ•ด๋‹น ์˜ํ™” ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค (์—†์œผ๋ฉด db์— ์ €์žฅํ•จ)
      const moviesList = await getBoxOfficeMovies(boxOfficeData); 

      // ์ฐพ์€ ์˜ํ™” ์ •๋ณด๋ฅผ ๋ฆฌ๋•์Šค์— ์—…๋ฐ์ดํŠธํ•œ๋‹ค
      dispatch(moviesAction.getBoxOfficeMovies(moviesList));
    }
  };
};

// ๋ฆฌ๋•์Šค์— ์ตœ์‹  ์˜ํ™” ๋ฐ์ดํ„ฐ ์ €์žฅ
export const getRecentMoviesFetch = () => {
  let movieList = []; //๋ฆฌ๋•์Šค์— ์—…๋ฐ์ดํŠธ ๋  ๋ฆฌ์ŠคํŠธ

  return async (dispatch) => {
    const response = await moviesClient.get("", {
      params: {
        listCount: 50,
        releaseDts: getPeriodDate(14), // ์˜ค๋Š˜๋กœ๋ถ€ํ„ฐ 14์ผ ์ด์ „๋‚ ์งœ
        releaseDte: getPeriodDate(), // ์˜ค๋Š˜๋‚ ์งœ
      },
    });

    // db์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด db์— ์ €์žฅ
    const responseData = getResponseMovieData(response);
    if (responseData) {
      const responseData = getResponseMovieData(response);
      for (const data of responseData) {
        const formattedData = changeDataFormat(data);
        // releaseDateํฌ๋งท์ด ๋น„์ •์ƒ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฑฐ๋ฅธ๋‹ค
        if (
          formattedData.releaseDate.length !== 8 ||
          formattedData.releaseDate.substring(6, 8) === "00"
        ) {
          continue;
        }

        movieList.push(formattedData);

        addMovie(formattedData);
      }
    }

    dispatch(moviesAction.getRecentMovies(movieList));
  };
};

// ๋ฐ•์Šค ์˜คํ”ผ์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋“ค๊ณ ์˜ด
const getBoxOffice = async () => {
  const response = await boxOfficeClient.get("");
  const responseData = response.data.boxOfficeResult.dailyBoxOfficeList;
  return await responseData.map((data) => ({
    movieCode: data.movieCd,
    title: data.movieNm,
    releaseDate: data.openDt.replace(/-/g, ""),
  }));
};

// ๋ฐ•์Šค์˜คํ”ผ์Šค ์˜ํ™” ์ •๋ณด ๊ฒ€์ƒ‰
export const getBoxOfficeMovies = async (boxOfficeData) => {
  let movieList = []; //๋ฐ˜ํ™˜๋  ์˜ํ™” ๋ฐ์ดํ„ฐ, redux state๊ฐ€ ๋ ๊ฑฐ์ž„

  for await (const data of boxOfficeData) {
    // db์— ํ•ด๋‹น ์˜ํ™”๊ฐ€ ์žˆ๋Š”์ง€ ๊ฒ€์ƒ‰
    const movie = await searchMovie(data);
    // db์— ์—†์œผ๋ฉด moviesClient api๋กœ ๋ฐ์ดํ„ฐ ํŒจ์นญ
    if (!movie) {
      const response = await moviesClient.get("", {
        params: {
          title: data.title,
          releaseDts: data.releaseDate,
        },
      });

      const responseData = getResponseMovieData(response);
      // ์‘๋‹ต ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด db์— ์ €์žฅํ•˜๊ณ  movieList์— ์ถ”๊ฐ€
      if (responseData && responseData.length > 0) {
        for (const data of responseData) {
          const formattedData = changeDataFormat(data);
          addMovie(formattedData);
          movieList.push(formattedData);
        }
      }
    } else { // db์— ์žˆ์œผ๋ฉด movieList์— ์ถ”๊ฐ€
      movieList.push(movie);
    }
  }
  return movieList;
};

// api response์—์„œ ์˜ํ™” ์ •๋ณด ์ถ”์ถœ
const getResponseMovieData = (response) => {
  return response.data.Data[0].Result;
};

util/data

KMDb๋Š” ํŠน์ • ์˜ํ™”๋ฅผ ์ง€์ •ํ•ด์„œ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์ œ๋ชฉ์— !HS !HE ์ด๋Ÿฐ๊ฒŒ ํฌํ•จ๋ผ์„œ ๋‚˜์˜ด. ์ •๊ทœํ‘œํ˜„์‹์„ ์ด์šฉํ•ด์„œ db์— ์ €์žฅํ• ๋•Œ๋Š” ๋ถˆํ•„์š”ํ•œ ๊ธ€์ž๋‚˜ ๊ณต๋ฐฑ์€ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

/** db์— ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๋งŒ ์ถ”์ถœํ•˜๋Š” ๋ฉ”์†Œ๋“œ */
export const dataFormat = (data) => {
  const {
    movieSeq,
    Codes: {
      Code: [{ CodeNo }],
    },
    title,
    genre,
    repRlsDate,
    prodYear,
    posters,
    plots: {
      plot: [{ plotText }],
    },
    runtime,
    rating,
    nation,
    titleEng,
    titleOrg,
    directors: {
      director: [{ directorNm }],
    },
    actors: { actor },
  } = data;

  /**์ •๊ทœํ‘œํ˜„์‹์œผ๋กœ ์ œ๋ชฉ ์ˆ˜์ • */
  let titleForamt = title
    .replace(/!HS/g, "")
    .replace(/!HE/g, "")
    .replace(/^\s+|\s+$/g, "")
    .replace(/ +/g, " ");

  return {
    id: movieSeq,
    movieCode: CodeNo,
    genre,
    title: titleForamt,
    releaseDate: repRlsDate,
    prodYear,
    poster: posters.split("|")[0],
    summary: plotText,
    runtime,
    rating,
    nation,
    titleEng,
    titleOrg,
    director: directorNm,
    actors: actor.map((it) => it.actorNm),
  };
};

util/date

/** ๋‚ ์งœ ์ •๋ณด YYYYMMDD */
export const getPeriodDate = (period = 0) => {
  //์˜ค๋Š˜ ๋‚ ์งœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ, -period ๊ธฐ๊ฐ„์˜ ๋‚ ์งœ๋ฅผ ๋ฐ˜ํ™˜
  const today = new Date();
  const dayAgo = new Date(today.setDate(today.getDate() - period));

  const date = new Date(dayAgo);
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();

  return `${year}${month < 10 ? `0${month}` : month}${
    day < 10 ? `0${day}` : day
  }`;
};

๊ตฌํ˜„๊ฒฐ๊ณผ

์˜ํ™”๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ์ •๋ณด๊ฐ€ ๋œฌ๋‹ค.


ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

1. CORS ์—๋Ÿฌ

AxiosError: Network Error
at XMLHttpRequest.handleError (http://localhost:3000/static/js/bundle.js:80954:14)

axios๋กœ API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฐœ์ƒ.
API์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์„œ๋ฒ„๊ฐ€ ๋‹ฌ๋ผ์„œ ๋ฐœ์ƒํ•จ.
์„œ๋ฒ„๋Š” ์†๋Œˆ ์ˆ˜ ์—†์–ด์„œ ํด๋ผ์ด์–ธํŠธ๋‹จ์—์„œ ํ•ด๊ฒฐํ•ด์•ผ ํ–ˆ๋Š”๋ฐ ๊ฒ€์ƒ‰ํ–ˆ์„๋•Œ ๋‚˜์˜ค๋Š” withCredentials ์˜ต์…˜ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์ „ํ˜€ ํ•ด๊ฒฐ์ด ์•ˆ๋ผ์„œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ–ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ https://xiubindev.tistory.com/115

์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ์ฒ˜๋Ÿผ http-proxy-middleware๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐํ•จ

2. map์—์„œ async/await์‚ฌ์šฉํ•˜๊ธฐ

Array.map์—์„œ async/await์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ Promise๋ฐฐ์—ด์ด ๋ฐ˜ํ™˜๋จ

[Promsie, Promsie, Promise, ...]

map์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๋ฉด Promise.all() Promise.allSettled() ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํ•œ๋‹ค. ์ฐธ๊ณ  ์ž๋ฃŒ๋ฅผ ํ†ตํ•ด์„œ ํ•ด๊ฒฐํ–ˆ์—ˆ๊ณ  ์ง€๊ธˆ์€ map ๋Œ€์‹  for in์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ”๊ฟจ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ https://velog.io/@minsangk/2019-09-06-0209-%EC%9E%91%EC%84%B1%EB%90%A8-eik06xy8mm


profile
๋” ์ด์ƒ ๋ฏธ๋ฃฐ ์ˆ˜ ์—†๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€