ํ”ผ๋“œ๋กœ ๋Œ์•„๊ฐ€๊ธฐ
I built a real-time Air Quality Index monitor from scratch โ€” AtmoPulse ๐ŸŒ
Dev.toDev.to
Frontend

Multi-source API Normalization ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ AQI ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•

I built a real-time Air Quality Index monitor from scratch โ€” AtmoPulse ๐ŸŒ

Ayush Kunkulol2026๋…„ 6์›” 14์ผ3๋ถ„beginner

Context

WAQI์™€ OpenAQ๋ผ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ํฌ๋งท์„ ๊ฐ€์ง„ ์™ธ๋ถ€ API๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ์ „ ์„ธ๊ณ„ ๊ณต๊ธฐ์งˆ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ. ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ์ธํ•ด ์ผ๊ด€๋œ UI ๋ Œ๋”๋ง๊ณผ ๋งต ๋งˆ์ปค ํ‘œ์‹œ ์‹œ ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ ํ™•๋ณด๊ฐ€ ํ•ต์‹ฌ ๊ณผ์ œ๋กœ ์ž‘์šฉ.

Technical Solution

  • ์„œ๋กœ ๋‹ค๋ฅธ API ์‘๋‹ต ๊ทœ๊ฒฉ์„ ๋‹จ์ผ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Normalization Layer ์„ค๊ณ„๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ํ™•๋ณด
  • React์˜ Component Lifecycle๊ณผ Leaflet.js์˜ DOM ์กฐ์ž‘ ์ถฉ๋Œ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด useRef ๊ธฐ๋ฐ˜์˜ Map Instance ๊ด€๋ฆฌ ์ „๋žต ์ฑ„ํƒ
  • Firebase Authentication์˜ onAuthStateChanged๋ฅผ ํ™œ์šฉํ•œ ์ƒํƒœ ์œ ์ง€ ๋ฐ ๊ถŒํ•œ๋ณ„ ๊ธฐ๋Šฅ ์ ‘๊ทผ ์ œ์–ด ๋กœ์ง ๊ตฌํ˜„
  • TypeScript์˜ ์—„๊ฒฉํ•œ Typing์„ ํ†ตํ•œ API Response ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜๋กœ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ์—๋Ÿฌ ๋ฐฉ์ง€ ๋ฐ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ
  • API ๊ณผ๋„ํ•œ ํ˜ธ์ถœ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ Cooldown Timer ๋„์ž…์œผ๋กœ Rate Limit ์ œ์–ด ๋ฐ ๋ฆฌ์†Œ์Šค ์ตœ์ ํ™” ๊ตฌํ˜„

1. ๋‹ค์ˆ˜ ์™ธ๋ถ€ API ํ†ตํ•ฉ ์‹œ ๊ฐœ๋ณ„ API ์˜์กด์„ฑ์„ ๋ถ„๋ฆฌํ•˜๋Š” ์ถ”์ƒํ™” ๊ณ„์ธต(Normalization Layer)์„ ๊ตฌ์ถ•ํ–ˆ๋Š”๊ฐ€

2. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Vanilla JS)์˜ ์ƒํƒœ๋ฅผ React Lifecycle ๋‚ด์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด useRef๋ฅผ ์ ์ ˆํžˆ ํ™œ์šฉํ–ˆ๋Š”๊ฐ€

3. API ์‘๋‹ต ๋ฐ์ดํ„ฐ์˜ ๋ถˆํ™•์‹ค์„ฑ์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด TypeScript Interface๋ฅผ ํ†ตํ•ด ์Šคํ‚ค๋งˆ๋ฅผ ๋ช…ํ™•ํžˆ ์ •์˜ํ–ˆ๋Š”๊ฐ€

4. ์ธ์ฆ ์ƒํƒœ ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ UI ์—…๋ฐ์ดํŠธ ์‹œ ๋น„๋™๊ธฐ ์ƒํƒœ ๋™๊ธฐํ™” ์ „๋žต์ด ์ˆ˜๋ฆฝ๋˜์—ˆ๋Š”๊ฐ€

์›๋ฌธ ์ฝ๊ธฐ