2025๋…„ 10์›” 03์ผยท5๋ถ„ ์ฝ๊ธฐ

๊ด€๋ฆฌ์ž ํ™”๋ฉด API๋ฅผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“œ๋Š”: ์ปค์„œ vs ์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜

์ •๋ ฌ, ํ•„ํ„ฐ, ์ด๊ณ„์— ๋Œ€ํ•ด ์ผ๊ด€๋œ API ๊ณ„์•ฝ์„ ์‚ฌ์šฉํ•ด ์›น๊ณผ ๋ชจ๋ฐ”์ผ ๊ด€๋ฆฌ์ž ํ™”๋ฉด์˜ ์‘๋‹ต์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์ปค์„œ vs ์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ํ•™์Šตํ•˜์„ธ์š”.

๊ด€๋ฆฌ์ž ํ™”๋ฉด API๋ฅผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“œ๋Š”: ์ปค์„œ vs ์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜

๊ด€๋ฆฌ์ž ํ™”๋ฉด์ด ๋А๋ฆฌ๊ฒŒ ๋А๊ปด์ง€๋Š” ์ด์œ 

๊ด€๋ฆฌ์ž ํ™”๋ฉด์€ ํ”ํžˆ ๊ฐ„๋‹จํ•œ ํ…Œ์ด๋ธ”์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค: ์ฒ˜์Œ 25๊ฐœ ํ–‰์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ๊ฒ€์ƒ‰ ์ƒ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋. ๋ช‡๋ฐฑ ๊ฑด์ผ ๋• ์ฆ‰๊ฐ์ ์œผ๋กœ ๋А๊ปด์ง‘๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ์…‹์ด ์ปค์ง€๋ฉด ๋™์ผํ•œ ํ™”๋ฉด์ด ๋ฒ„๋ฒ…๊ฑฐ๋ฆฌ๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ๋ณดํ†ต UI๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. API๊ฐ€ ์ •๋ ฌ๊ณผ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•œ ์ฑ„๋กœ 12ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”์ด ์ปค์งˆ์ˆ˜๋ก ๋ฐฑ์—”๋“œ๋Š” ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์„ ์ฐพ๊ณ , ๊ฐœ์ˆ˜๋ฅผ ์„ธ๊ณ , ์•ž์ชฝ ๊ฒฐ๊ณผ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋А๋ผ ๋” ๋งŽ์€ ์‹œ๊ฐ„์„ ์”๋‹ˆ๋‹ค. ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค ๋” ๋ฌด๊ฑฐ์šด ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ํ™”๋ฉด์€ ๋ฐ˜์‘ํ•˜๋Š” ๋Œ€์‹  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋А๊ปด์ง‘๋‹ˆ๋‹ค.

๋น„์Šทํ•œ ์ฆ์ƒ์€ ์–ธ์ œ๋‚˜ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค: ํŽ˜์ด์ง€ ์ „ํ™˜์ด ์ ์  ๋А๋ ค์ง€๊ณ , ์ •๋ ฌ์ด ๋‘”ํ•ด์ง€๊ณ , ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ํŽ˜์ด์ง€๋งˆ๋‹ค ์ผ๊ด€๋˜์ง€ ์•Š์œผ๋ฉฐ, ๋ฌดํ•œ ์Šคํฌ๋กค์€ ๋น ๋ฅด๊ฒŒ ๋กœ๋“œ๋˜๋‹ค ๊ฐ‘์ž๊ธฐ ๋А๋ ค์ง‘๋‹ˆ๋‹ค. ํ™œ๋ฐœํ•œ ์‹œ์Šคํ…œ์—์„œ๋Š” ์š”์ฒญ ์‚ฌ์ด์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ ์ค‘๋ณต์ด๋‚˜ ๋ˆ„๋ฝ๋œ ํ–‰์ด ๋ณด์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์›น๊ณผ ๋ชจ๋ฐ”์ผ UI๋Š” ํŽ˜์ด์ง€๋„ค์ด์…˜์— ์„œ๋กœ ๋‹ค๋ฅธ ์š”๊ตฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. ์›น ๊ด€๋ฆฌ์šฉ ํ…Œ์ด๋ธ”์€ ํŠน์ • ํŽ˜์ด์ง€๋กœ ๊ฑด๋„ˆ๋›ฐ๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์—ด๋กœ ์ •๋ ฌํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ฐ”์ผ ํ™”๋ฉด์€ ๋ณดํ†ต ๋‹ค์Œ ์ฒญํฌ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฌดํ•œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ฐ ํ’€ ๋™์ž‘์ด ๋™์ผํ•˜๊ฒŒ ๋น ๋ฅด๊ธธ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. API๊ฐ€ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜์œผ๋กœ๋งŒ ์„ค๊ณ„๋˜๋ฉด ๋ชจ๋ฐ”์ผ์ด ๊ณ ํ†ต๋ฐ›๊ณ , next/after ๊ธฐ๋ฐ˜์œผ๋กœ๋งŒ ์„ค๊ณ„๋˜๋ฉด ์›น ํ…Œ์ด๋ธ”์ด ์ œํ•œ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชฉํ‘œ๋Š” ๋‹จ์ˆœํžˆ 25๊ฐœ ํ•ญ๋ชฉ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์ปค์ ธ๋„ ๋น ๋ฅด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง•, ํ…Œ์ด๋ธ”๊ณผ ๋ฌดํ•œ ๋ฆฌ์ŠคํŠธ ๋ชจ๋‘์— ์ ์šฉ๋˜๋Š” ๊ทœ์น™์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

UI๊ฐ€ ์˜์กดํ•˜๋Š” ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ธฐ๋ณธ

ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๊ธด ๋ชฉ๋ก์„ ์ž‘์€ ๋ฉ์–ด๋ฆฌ๋กœ ๋‚˜๋ˆ„์–ด ํ™”๋ฉด์ด ๋น ๋ฅด๊ฒŒ ๋กœ๋“œํ•˜๊ณ  ๋ Œ๋”๋งํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. UI๋Š” ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ์š”์ฒญํ•˜๋Š” ๋Œ€์‹  ๋‹ค์Œ ๊ฒฐ๊ณผ ์กฐ๊ฐ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ œ์–ด๋Š” ํŽ˜์ด์ง€ ํฌ๊ธฐ(์ข…์ข… limit)์ž…๋‹ˆ๋‹ค. ์ž‘์€ ํŽ˜์ด์ง€๋Š” ์„œ๋ฒ„๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ž‘์—…์ด ์ ๊ณ  ์•ฑ์ด ๋ Œ๋”๋งํ•  ํ–‰๋„ ์ ์œผ๋ฏ€๋กœ ๋ณดํ†ต ๋” ๋น ๋ฅด๊ฒŒ ๋А๊ปด์ง‘๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ์ž‘์€ ํŽ˜์ด์ง€๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋” ์ž์ฃผ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์Šคํฌ๋กคํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ถˆํŽธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ๊ด€๋ฆฌ์ž ํ…Œ์ด๋ธ”์—์„œ๋Š” 25~100๊ฐœ๊ฐ€ ์‹ค์šฉ์  ๋ฒ”์œ„์ด๋ฉฐ, ๋ชจ๋ฐ”์ผ์€ ๋ณดํ†ต ๋‚ฎ์€ ์ชฝ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์•ˆ์ •์ ์ธ ์ •๋ ฌ ์ˆœ์„œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ํŒ€์ด ์˜ˆ์ƒํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ์‚ฌ์ด์— ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์‚ฌ์šฉ์ž๋Š” ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ธฐ๋ฉฐ ์ค‘๋ณต ๋˜๋Š” ๋ˆ„๋ฝ์„ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•ˆ์ •์ ์ธ ์ •๋ ฌ์€ ๋ณดํ†ต created_at ๊ฐ™์€ ๊ธฐ๋ณธ ํ•„๋“œ์™€ id ๊ฐ™์€ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์˜คํ”„์…‹์ด๋“  ์ปค์„œ๋“  ๋ชจ๋‘ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ๊ด€์ ์—์„œ ํŽ˜์ด์ง€ํ™”๋œ ์‘๋‹ต์€ ํ•ญ๋ชฉ, ๋‹ค์Œ ํŽ˜์ด์ง€ ํžŒํŠธ(ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋‚˜ ์ปค์„œ ํ† ํฐ), ๊ทธ๋ฆฌ๊ณ  UI๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์นด์šดํŠธ๋งŒ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ํ™”๋ฉด์€ โ€œ1-50 of 12,340โ€ ๊ฐ™์€ ์ •ํ™•ํ•œ ์ด๊ณ„๋ฅผ ํ•„์š”๋กœ ํ•˜๊ณ , ๋‹ค๋ฅธ ํ™”๋ฉด์€ has_more๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜: ์ž‘๋™ ๋ฐฉ์‹๊ณผ ๋ฌธ์ œ์ 

์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๊ณ ์ „์ ์ธ ํŽ˜์ด์ง€ N ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ๊ณ ์ •๋œ ํ–‰ ์ˆ˜๋ฅผ ์š”์ฒญํ•˜๊ณ  ์ฒ˜์Œ์— ๊ฑด๋„ˆ๋›ธ ํ–‰ ์ˆ˜๋ฅผ API์— ์•Œ๋ ค์ค๋‹ˆ๋‹ค. limit๊ณผ offset์œผ๋กœ ๋ณด์ด๊ฑฐ๋‚˜ ์„œ๋ฒ„๊ฐ€ ์˜คํ”„์…‹์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” page์™€ pageSize๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์š”์ฒญ ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • GET /tickets?limit=50\u0026offset=950
  • โ€œ์ฒ˜์Œ 950๊ฐœ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  ํ‹ฐ์ผ“ 50๊ฐœ๋ฅผ ์ฃผ์„ธ์š”.โ€

ํŽ˜์ด์ง€ 20์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ฑฐ๋‚˜ ์˜ค๋ž˜๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ํฐ ๋ชฉ๋ก์„ ์ฒญํฌ๋กœ ๋‚ด๋ณด๋‚ผ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ๋„ ์„ค๋ช…ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค: โ€œํŽ˜์ด์ง€ 3์„ ๋ณด์„ธ์š”.โ€

๋ฌธ์ œ๋Š” ๊นŠ์€ ํŽ˜์ด์ง€์—์„œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ํŠนํžˆ ์ •๋ ฌ ์ˆœ์„œ์— ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์—†์„ ๋•Œ ๊ฑด๋„ˆ๋›ด ํ–‰์„ ์ง€๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ 1์€ ๋น ๋ฅด์ง€๋งŒ ํŽ˜์ด์ง€ 200์€ ๋ˆˆ์— ๋„๊ฒŒ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กคํ•˜๊ฑฐ๋‚˜ ๊ฑด๋„ˆ๋›ธ ๋•Œ ๊ด€๋ฆฌ์ž ํ™”๋ฉด์ด ์ง€์—ฐ๋˜๋Š” ์ด์œ ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ์˜ ์ผ๊ด€์„ฑ์ž…๋‹ˆ๋‹ค. ์ง€์› ๋งค๋‹ˆ์ €๊ฐ€ ์ตœ์‹ ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ํ‹ฐ์ผ“์˜ 5ํŽ˜์ด์ง€๋ฅผ ์—ด์–ด๋ณธ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์„ธ์š”. ๋ณด๋Š” ์‚ฌ์ด์— ์ƒˆ ํ‹ฐ์ผ“์ด ๋“ค์–ด์˜ค๊ฑฐ๋‚˜ ์˜ค๋ž˜๋œ ํ‹ฐ์ผ“์ด ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ์‚ฝ์ž…์€ ํ•ญ๋ชฉ์„ ์•ž์œผ๋กœ ๋ฐ€์–ด ์ค‘๋ณต์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ์‚ญ์ œ๋Š” ํ•ญ๋ชฉ์ด ์‚ฌ๋ผ์ง€๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์ž‘์€ ํ…Œ์ด๋ธ”, ์•ˆ์ •๋œ ๋ฐ์ดํ„ฐ์…‹, ๋˜๋Š” ์ผํšŒ์„ฑ ๋‚ด๋ณด๋‚ด๊ธฐ์—๋Š” ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํฐ ๊ทœ๋ชจ์˜ ํ™œ๋ฐœํ•œ ํ…Œ์ด๋ธ”์—์„œ๋Š” ๊ณง ๋ฌธ์ œ์ ์ด ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค.

์ปค์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜: ์ž‘๋™ ๋ฐฉ์‹๊ณผ ์•ˆ์ •์„ฑ

์ปค์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋ถ๋งˆํฌ๋กœ์„œ ์ปค์„œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. โ€œ7ํŽ˜์ด์ง€๋ฅผ ๋‹ฌ๋ผโ€๊ฐ€ ์•„๋‹ˆ๋ผ โ€œ์ด ํ•ญ๋ชฉ ๋’ค๋ถ€ํ„ฐ ๊ณ„์†ํ•ด ๋‹ฌ๋ผโ€๊ณ  ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋งํ•ฉ๋‹ˆ๋‹ค. ์ปค์„œ๋Š” ๋ณดํ†ต ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์˜ ์ •๋ ฌ ๊ฐ’(created_at, id ๋“ฑ)์„ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์„œ๋ฒ„๊ฐ€ ์ •ํ™•ํ•œ ์œ„์น˜์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ์€ ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • limit: ๋ฐ˜ํ™˜ํ•  ํ•ญ๋ชฉ ์ˆ˜
  • cursor: ์ด์ „ ์‘๋‹ต์—์„œ ๋ฐ›์€ ๋ถˆํˆฌ๋ช… ํ† ํฐ(์ข…์ข… after๋ผ๊ณ  ๋ถˆ๋ฆผ)

์‘๋‹ต์€ ํ•ญ๋ชฉ๊ณผ ๊ทธ ์กฐ๊ฐ์˜ ๋์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ƒˆ ์ปค์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋ฌด ์ฐจ์ด๋Š” ์ปค์„œ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํ–‰์„ ์„ธ๊ณ  ๊ฑด๋„ˆ๋›ฐ๋ผ๊ณ  ์š”์ฒญํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  ์•Œ๋ ค์ง„ ์œ„์น˜์—์„œ ์‹œ์ž‘ํ•˜๋ผ๊ณ  ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

์ด ๋•Œ๋ฌธ์— ์ปค์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์•ž์œผ๋กœ ์Šคํฌ๋กคํ•˜๋Š” ๋ฆฌ์ŠคํŠธ์—์„œ ๋น ๋ฅด๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” โ€œX ์ดํ›„ ํ•ญ๋ชฉโ€์œผ๋กœ ๋ฐ”๋กœ ๊ฑด๋„ˆ๋›ด ๋‹ค์Œ limit๋งŒํผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ์˜คํ”„์…‹์€ ์˜คํ”„์…‹์ด ์ปค์งˆ์ˆ˜๋ก ๋” ๋งŽ์€ ํ–‰์„ ์Šค์บ”ํ•˜๊ฑฐ๋‚˜ ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•  ๋•Œ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

UI ๊ด€์ ์—์„œ ์ปค์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ โ€œ๋‹ค์Œโ€์ด ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค: ๋ฐ˜ํ™˜๋œ ์ปค์„œ๋ฅผ ๋‹ค์Œ ์š”์ฒญ์— ๊ทธ๋Œ€๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค. โ€œ์ด์ „โ€์€ ์„ ํƒ ์‚ฌํ•ญ์ด๊ณ  ๋” ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ API๋Š” before ์ปค์„œ๋ฅผ ์ง€์›ํ•˜๊ณ , ๋‹ค๋ฅธ API๋Š” ์—ญ์ˆœ์œผ๋กœ ๊ฐ€์ ธ์™€ ๊ฒฐ๊ณผ๋ฅผ ๋’ค์ง‘์Šต๋‹ˆ๋‹ค.

์–ธ์ œ ์ปค์„œ, ์˜คํ”„์…‹, ํ•˜์ด๋ธŒ๋ฆฌ๋“œ๋ฅผ ์„ ํƒํ• ๊นŒ

Fix pagination edge cases
Design filters, sorting rules, and guardrails so your UI stops seeing duplicates.
Open Builder

์„ ํƒ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ชฉ๋ก์„ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ปค์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์ฃผ๋กœ ์•ž์œผ๋กœ ์ด๋™ํ•˜๊ณ  ์†๋„๊ฐ€ ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค: ํ™œ๋™ ๋กœ๊ทธ, ์ฑ„ํŒ…, ์ฃผ๋ฌธ, ํ‹ฐ์ผ“, ๊ฐ์‚ฌ ๊ธฐ๋ก, ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋ฐ”์ผ ๋ฌดํ•œ ์Šคํฌ๋กค. ์ƒˆ ํ–‰์ด ์‚ฝ์ž…๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋  ๋•Œ์—๋„ ๋” ์ž˜ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์ฃผ ์ด๋ฆฌ์ €๋ฆฌ ๊ฑด๋„ˆ๋›ฐ๋Š” ํด๋ž˜์‹ํ•œ ๊ด€๋ฆฌ์ž ํ…Œ์ด๋ธ”(ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ํŠน์ • ํŽ˜์ด์ง€๋กœ ๊ฐ€๊ธฐ)์ด ์žˆ์„ ๋•Œ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ค๋ช…ํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ ํฐ ๋ฐ์ดํ„ฐ์…‹์—์„œ๋Š” ๋А๋ ค์ง€๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•˜๋ฉด ๋œ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ํŒ๋‹จ ๊ธฐ์ค€:

  • ์ฃผ๋œ ๋™์ž‘์ด โ€œ๋‹ค์Œ, ๋‹ค์Œ, ๋‹ค์Œโ€์ด๋ฉด ์ปค์„œ๋ฅผ ์„ ํƒํ•˜์„ธ์š”.
  • โ€œNํŽ˜์ด์ง€๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐโ€๊ฐ€ ์‹ค์ œ ์š”๊ตฌ์‚ฌํ•ญ์ด๋ผ๋ฉด ์˜คํ”„์…‹์„ ์„ ํƒํ•˜์„ธ์š”.
  • ์ด๊ณ„๋Š” ์„ ํƒ ์‚ฌํ•ญ์œผ๋กœ ๊ฐ„์ฃผํ•˜์„ธ์š”. ํฐ ํ…Œ์ด๋ธ”์—์„œ๋Š” ์ •ํ™•ํ•œ ์ด๊ณ„๊ฐ€ ๋น„์šฉ์ด ๋งŽ์ด ๋“ญ๋‹ˆ๋‹ค.

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ๋Š” ํ”ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ์ ‘๊ทผ๋ฒ•์€ ์†๋„๋ฅผ ์œ„ํ•ด ์ปค์„œ ๊ธฐ๋ฐ˜ next/prev๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์˜คํ”„์…‹์ด ์—ฌ์ „ํžˆ ๋น ๋ฅธ ์ž‘์€ ํ•„ํ„ฐ๋œ ๋ถ€๋ถ„์ง‘ํ•ฉ์— ๋Œ€ํ•ด ์„ ํƒ์  ํŽ˜์ด์ง€ ์ ํ”„ ๋ชจ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ์บ์‹œ๋œ ์Šค๋ƒ…์ƒท์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ปค์„œ ๊ฒ€์ƒ‰์œผ๋กœ, ํ…Œ์ด๋ธ”์ด ์นœ์ˆ™ํ•˜๊ฒŒ ๋А๊ปด์ง€๊ฒŒ ํ•˜๋ฉด์„œ ๋ชจ๋“  ์š”์ฒญ์„ ๋ฌด๊ฒ๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์›น๊ณผ ๋ชจ๋ฐ”์ผ์—์„œ ์ž‘๋™ํ•˜๋Š” ์ผ๊ด€๋œ API ๊ณ„์•ฝ

๊ด€๋ฆฌ์ž UI๋Š” ๋ชจ๋“  ๋ชฉ๋ก ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•  ๋•Œ ๋” ๋น ๋ฅด๊ฒŒ ๋А๊ปด์ง‘๋‹ˆ๋‹ค. UI๊ฐ€ ๋ฐ”๋€Œ์–ด๋„(API๊ฐ€ ํ…Œ์ด๋ธ”์ธ์ง€ ๋ฌดํ•œ ์Šคํฌ๋กค์ธ์ง€), API ๊ณ„์•ฝ์€ ๋™์ผํ•ด์•ผ ๊ฐ ํ™”๋ฉด๋งˆ๋‹ค ๋ณ„๋„์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ทœ์น™์„ ๋ฐฐ์šธ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ๊ณ„์•ฝ์€ ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค: ํ–‰(items), ํŽ˜์ด์ง• ์ƒํƒœ(paging state), ์„ ํƒ์  ์ด๊ณ„(totals). ์—”๋“œํฌ์ธํŠธ ๊ฐ„ ์ด๋ฆ„์„ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”(tickets, users, orders ๋“ฑ). ๋‚ด๋ถ€ ํŽ˜์ด์ง• ๋ชจ๋“œ๊ฐ€ ๋‹ฌ๋ผ๋„ ์ด๋ฆ„์€ ๊ฐ™๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์›น๊ณผ ๋ชจ๋ฐ”์ผ ๋ชจ๋‘์— ์ž˜ ๋งž๋Š” ์‘๋‹ต ํ˜•ํƒœ ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{
  "data": [ { "id": "...", "createdAt": "..." } ],
  "page": {
    "mode": "cursor",
    "limit": 50,
    "nextCursor": "...",
    "prevCursor": null,
    "hasNext": true,
    "hasPrev": false
  },
  "totals": {
    "count": 12345,
    "filteredCount": 120
  }
}

๋‹ค์Œ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ์žฌ์‚ฌ์šฉ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค:

  • page.mode๋Š” ์„œ๋ฒ„๊ฐ€ ์–ด๋–ค ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์–ด ํ•„๋“œ ์ด๋ฆ„์„ ๋ฐ”๊พธ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.
  • limit์€ ํ•ญ์ƒ ์š”์ฒญํ•œ ํŽ˜์ด์ง€ ํฌ๊ธฐ์ž…๋‹ˆ๋‹ค.
  • nextCursor์™€ prevCursor๋Š” ํ•˜๋‚˜๊ฐ€ null์ด๋ผ๋„ ํ•ญ์ƒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • totals๋Š” ์„ ํƒ์ ์ž…๋‹ˆ๋‹ค. ๋น„์šฉ์ด ํฌ๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•  ๋•Œ๋งŒ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

์›น ํ…Œ์ด๋ธ”์€ ์ž์ฒด์ ์œผ๋กœ โ€œํŽ˜์ด์ง€ 3โ€์„ ๊ณ„์‚ฐํ•ด API๋ฅผ ๋ฐ˜๋ณต ํ˜ธ์ถœํ•˜์—ฌ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๊ณ , ๋ชจ๋ฐ”์ผ ๋ฆฌ์ŠคํŠธ๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๋‹จ์ˆœํžˆ ๋‹ค์Œ ์ฒญํฌ๋ฅผ ์š”์ฒญํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

AppMaster๋กœ ์›น๊ณผ ๋ชจ๋ฐ”์ผ ๊ด€๋ฆฌ์ž UI๋ฅผ ๋ชจ๋‘ ๋นŒ๋“œํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์ด๋Ÿฐ ์•ˆ์ •๋œ ๊ณ„์•ฝ์€ ๋น ๋ฅด๊ฒŒ ํšจ๊ณผ๋ฅผ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ๋ชฉ๋ก ๋™์ž‘์„ ์—ฌ๋Ÿฌ ํ™”๋ฉด์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ์—”๋“œํฌ์ธํŠธ๋งˆ๋‹ค ๋ณ„๋„์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋กœ์ง์„ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์•ˆ์ •ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ์ •๋ ฌ ๊ทœ์น™

One API for web and mobile
Use one pagination contract across web and native mobile screens.
Create App

์ •๋ ฌ์€ ๋ณดํ†ต ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊นจ๋œจ๋ฆฌ๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค. ์š”์ฒญ ์‚ฌ์ด์— ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์‚ฌ์šฉ์ž๋Š” ์ค‘๋ณต, ๊ฐ„๊ฒฉ, ๋˜๋Š” โ€œ์—†๋Š”โ€ ํ–‰์„ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ •๋ ฌ์„ ์ œ์•ˆ์ด ์•„๋‹ˆ๋ผ ๊ณ„์•ฝ์œผ๋กœ ๋งŒ๋“œ์„ธ์š”. ํ—ˆ์šฉ๋œ ์ •๋ ฌ ํ•„๋“œ์™€ ๋ฐฉํ–ฅ์„ ๊ณต๊ฐœํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ์š”์ฒญ์€ ๊ฑฐ๋ถ€ํ•˜์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์˜€๋˜ ๋А๋ฆฐ ์ •๋ ฌ ์š”์ฒญ์„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์•ˆ์ •์ ์ธ ์ •๋ ฌ์€ ๊ณ ์œ ํ•œ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด created_at์œผ๋กœ ์ •๋ ฌํ•  ๋•Œ ๋‘ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋™์ผํ•œ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋งˆ์ง€๋ง‰ ์ •๋ ฌ ํ‚ค๋กœ id(๋˜๋Š” ๋‹ค๋ฅธ ๊ณ ์œ  ์ปฌ๋Ÿผ)๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๋™์ผํ•œ ๊ฐ’์— ๋Œ€ํ•ด ์ž„์˜์˜ ์ˆœ์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ๊ทœ์น™:

  • ์ธ๋ฑ์Šค๋œ, ์ž˜ ์ •์˜๋œ ํ•„๋“œ๋งŒ ์ •๋ ฌ์„ ํ—ˆ์šฉํ•˜์„ธ์š”(์˜ˆ: created_at, updated_at, status, priority).
  • ๋งˆ์ง€๋ง‰ ํ‚ค๋กœ ํ•ญ์ƒ ๊ณ ์œ  ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋ฅผ ํฌํ•จํ•˜์„ธ์š”(์˜ˆ: id ASC).
  • ๊ธฐ๋ณธ ์ •๋ ฌ์„ ์ •์˜ํ•˜๊ณ (์˜ˆ: created_at DESC, id DESC) ํด๋ผ์ด์–ธํŠธ ์ „๋ฐ˜์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”.
  • null ์ •๋ ฌ ๋ฐฉ์‹(์˜ˆ: ๋‚ ์งœ์™€ ์ˆซ์ž์— ๋Œ€ํ•ด โ€œnulls lastโ€)์„ ๋ฌธ์„œํ™”ํ•˜์„ธ์š”.

์ •๋ ฌ์€ ๋˜ํ•œ ์ปค์„œ ์ƒ์„ฑ์— ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค. ์ปค์„œ๋Š” ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์˜ ์ •๋ ฌ ๊ฐ’์„ ์ˆœ์„œ๋Œ€๋กœ ์ธ์ฝ”๋”ฉํ•ด์•ผ ํ•˜๋ฉฐ, ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋„ ํฌํ•จ๋˜์–ด์•ผ ๋‹ค์Œ ํŽ˜์ด์ง€์—์„œ ๊ทธ ํŠœํ”Œ ์ดํ›„๋ฅผ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •๋ ฌ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ด์ „ ์ปค์„œ๋Š” ๋ฌดํšจ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ •๋ ฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ปค์„œ ๊ณ„์•ฝ์˜ ์ผ๋ถ€๋กœ ์ทจ๊ธ‰ํ•˜์„ธ์š”.

๊ณ„์•ฝ์„ ๊นจ์ง€ ์•Š๋Š” ํ•„ํ„ฐ์™€ ์ด๊ณ„ ์ฒ˜๋ฆฌ

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

๊ฐ„๋‹จํ•œ ๊ทœ์น™: ํ•„ํ„ฐ๋Š” ํ‰๋ฌธ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์—(๋˜๋Š” POST์˜ ๊ฒฝ์šฐ ์š”์ฒญ ๋ณธ๋ฌธ์—) ๋‘๊ณ , ์ปค์„œ๋Š” ํ•ด๋‹น ์ •ํ™•ํ•œ ํ•„ํ„ฐ+์ •๋ ฌ ์กฐํ•ฉ์—๋งŒ ์œ ํšจํ•œ ๋ถˆํˆฌ๋ช…ํ•œ ํ† ํฐ์œผ๋กœ ํ•˜์„ธ์š”. ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ํ•„ํ„ฐ(์˜ˆ: status, ๋‚ ์งœ ๋ฒ”์œ„, ๋‹ด๋‹น์ž)๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ์ด์ „ ์ปค์„œ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ—ˆ์šฉ๋˜๋Š” ํ•„ํ„ฐ๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ํ•˜์„ธ์š”. ์„ฑ๋Šฅ์„ ๋ณดํ˜ธํ•˜๊ณ  ๋™์ž‘์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค:

  • ์•Œ ์ˆ˜ ์—†๋Š” ํ•„ํ„ฐ ํ•„๋“œ๋Š” ๊ฑฐ๋ถ€ํ•˜์„ธ์š”(์กฐ์šฉํžˆ ๋ฌด์‹œํ•˜์ง€ ๋งˆ์„ธ์š”).
  • ํƒ€์ž…๊ณผ ๋ฒ”์œ„๋ฅผ ๊ฒ€์ฆํ•˜์„ธ์š”(๋‚ ์งœ, ์—ด๊ฑฐํ˜•, ID ๋“ฑ).
  • ๋„“์€ ํ•„ํ„ฐ๋Š” ์ œํ•œํ•˜์„ธ์š”(์˜ˆ: IN ๋ชฉ๋ก์— ์ตœ๋Œ€ 50๊ฐœ์˜ ID).
  • ๋ฐ์ดํ„ฐ์™€ ์ด๊ณ„์— ๊ฐ™์€ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜์„ธ์š”(์ˆซ์ž๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๊ฒŒ ํ•˜์ง€ ๋งˆ์„ธ์š”).

์ด๊ณ„๋Š” ๋งŽ์€ API๋ฅผ ๋А๋ฆฌ๊ฒŒ ๋งŒ๋“œ๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ์นด์šดํŠธ๋Š” ํŠนํžˆ ์—ฌ๋Ÿฌ ํ•„ํ„ฐ๊ฐ€ ์žˆ๋Š” ํฐ ํ…Œ์ด๋ธ”์—์„œ ๋น„์šฉ์ด ํฝ๋‹ˆ๋‹ค. ๋ณดํ†ต ์„ธ ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค: ์ •ํ™•ํ•œ ๊ฐ’, ์ถ”์ •๊ฐ’, ๋˜๋Š” ์—†์Œ. ์ •ํ™•ํ•œ ๊ฐ’์€ ์ž‘์€ ๋ฐ์ดํ„ฐ์…‹์ด๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ์ด๊ณ„๋ฅผ ํ•„์š”๋กœ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ถ”์ •์€ ๊ด€๋ฆฌ์ž ํ™”๋ฉด์— ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ํ•„์š” ์—†๋‹ค๋ฉด ์ƒ๋žตํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์š”์ฒญ์„ ๋А๋ฆฌ๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ์ด๊ณ„๋ฅผ ์„ ํƒ์‚ฌํ•ญ์œผ๋กœ ๋งŒ๋“œ์„ธ์š”: ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•  ๋•Œ๋งŒ ๊ณ„์‚ฐ(includeTotal=true ๊ฐ™์€ ํ”Œ๋ž˜๊ทธ๋กœ), ํ•„ํ„ฐ ์ง‘ํ•ฉ๋ณ„๋กœ ์ž ์‹œ ์บ์‹œํ•˜๊ฑฐ๋‚˜ ์ฒซ ํŽ˜์ด์ง€์—์„œ๋งŒ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

๋‹จ๊ณ„๋ณ„: ์—”๋“œํฌ์ธํŠธ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

Cursor paging without complexity
Implement cursor pagination logic visually with drag-and-drop business processes.
Try Now

๊ธฐ๋ณธ๊ฐ’๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”. ๋ชฉ๋ก ์—”๋“œํฌ์ธํŠธ๋Š” ์•ˆ์ •์ ์ธ ์ •๋ ฌ ์ˆœ์„œ์™€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„ ํ–‰์„ ์œ„ํ•œ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: createdAt DESC, id DESC. ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค(id)๋Š” ์ƒˆ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ ์ค‘๋ณต๊ณผ ๊ฐ„๊ฒฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ ํ˜•์‹์„ ํ•˜๋‚˜๋กœ ์ •์˜ํ•˜๊ณ  ์ง€๋ฃจํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”. ์ผ๋ฐ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” limit, cursor(๋˜๋Š” offset), sort, filters์ž…๋‹ˆ๋‹ค. ๋‘ ๋ชจ๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๋ฉด ์ƒํ˜ธ ๋ฐฐํƒ€์ ์œผ๋กœ ๋งŒ๋“œ์„ธ์š”: ํด๋ผ์ด์–ธํŠธ๋Š” cursor๋ฅผ ๋ณด๋‚ด๊ฑฐ๋‚˜ offset์„ ๋ณด๋‚ด์ง€๋งŒ ๋‘˜ ๋‹ค ๋ณด๋‚ด๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์‘๋‹ต ๊ณ„์•ฝ์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•ด ์›น๊ณผ ๋ชจ๋ฐ”์ผ UI๊ฐ€ ๊ฐ™์€ ๋ชฉ๋ก ๋กœ์ง์„ ๊ณต์œ ํ•˜๋„๋ก ํ•˜์„ธ์š”:

  • items: ๋ ˆ์ฝ”๋“œ ํŽ˜์ด์ง€
  • nextCursor: ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ปค์„œ(๋˜๋Š” null)
  • hasMore: UI๊ฐ€ โ€œ๋” ๋ถˆ๋Ÿฌ์˜ค๊ธฐโ€๋ฅผ ํ‘œ์‹œํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ถˆ๋ฆฌ์–ธ
  • total: ์ „์ฒด ์ผ์น˜ ๋ ˆ์ฝ”๋“œ ์ˆ˜(null, ์นด์šดํŒ…์ด ๋น„์‹ธ๋ฉด ์š”์ฒญ ์‹œ์—๋งŒ)

๊ตฌํ˜„์€ ๋‘ ์ ‘๊ทผ๋ฒ•์ด ๊ฐˆ๋ฆฌ๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค.

์˜คํ”„์…‹ ์ฟผ๋ฆฌ๋Š” ๋ณดํ†ต ORDER BY ... LIMIT ... OFFSET ...์ด๊ณ  ํฐ ํ…Œ์ด๋ธ”์—์„œ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์„œ ์ฟผ๋ฆฌ๋Š” ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์„ ๊ธฐ์ค€์œผ๋กœ ํƒ์ƒ‰ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค: โ€œ(createdAt, id) ์ด ๋งˆ์ง€๋ง‰ (createdAt, id)๋ณด๋‹ค ์ž‘์€ ํ•ญ๋ชฉ์„ ์ค˜โ€. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•ด ์„ฑ๋Šฅ์„ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถœ์‹œ ์ „์— ๋‹ค์Œ ๊ฐ€๋“œ๋ ˆ์ผ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

  • limit์„ ์ œํ•œํ•˜์„ธ์š”(์˜ˆ: ์ตœ๋Œ€ 100) ๋ฐ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •.
  • sort๋ฅผ ํ—ˆ์šฉ ๋ชฉ๋ก์œผ๋กœ ๊ฒ€์ฆํ•˜์„ธ์š”.
  • ํ•„ํ„ฐ๋ฅผ ํƒ€์ž…๋ณ„๋กœ ๊ฒ€์ฆํ•˜๊ณ  ์•Œ ์ˆ˜ ์—†๋Š” ํ‚ค๋Š” ๊ฑฐ๋ถ€ํ•˜์„ธ์š”.
  • cursor๋Š” ๋ถˆํˆฌ๋ช…ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์ž˜๋ชป๋œ ์ปค์„œ๋Š” ๊ฑฐ๋ถ€ํ•˜์„ธ์š”.
  • total์ด ์–ด๋–ป๊ฒŒ ์š”์ฒญ๋˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜์„ธ์š”.

๋ฐ์ดํ„ฐ๊ฐ€ ์š”์ฒญ ์‚ฌ์ด์— ๋ณ€๊ฒฝ๋˜๋Š” ์ƒํ™ฉ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”. ์š”์ฒญ ์‚ฌ์ด์— ๋ ˆ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ญ์ œํ•˜๊ณ  ์ •๋ ฌ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ํ•„๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด ์ค‘๋ณต์ด๋‚˜ ๋ˆ„๋ฝ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

์˜ˆ์‹œ: ์›น๊ณผ ๋ชจ๋ฐ”์ผ์—์„œ ๋น ๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š” ํ‹ฐ์ผ“ ๋ชฉ๋ก

Ship the backend first
Model data in PostgreSQL and generate a production-ready backend in Go.
Build Backend

์ง€์› ํŒ€์ด ์ตœ์‹  ํ‹ฐ์ผ“์„ ๊ฒ€ํ† ํ•˜๋ ค๊ณ  ๊ด€๋ฆฌ์ž ํ™”๋ฉด์„ ์—ฝ๋‹ˆ๋‹ค. ์ƒˆ ํ‹ฐ์ผ“์ด ๋“ค์–ด์˜ค๊ณ  ์—์ด์ „ํŠธ๊ฐ€ ์˜ค๋ž˜๋œ ํ‹ฐ์ผ“์„ ์—…๋ฐ์ดํŠธํ•ด๋„ ๋ชฉ๋ก์ด ์ฆ‰๊ฐ์ ์œผ๋กœ ๋А๊ปด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์›น์—์„œ๋Š” UI๊ฐ€ ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ •๋ ฌ์€ updated_at(์ตœ์‹  ์ˆœ)์ด๊ณ  ํŒ€์€ ๋ณดํ†ต Open ๋˜๋Š” Pending์œผ๋กœ ํ•„ํ„ฐํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์•ˆ์ •์ ์ธ ์ •๋ ฌ๊ณผ ์ปค์„œ ํ† ํฐ์œผ๋กœ ๋‘ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

GET /tickets?status=open\u0026sort=-updated_at\u0026limit=50\u0026cursor=eyJ1cGRhdGVkX2F0IjoiMjAyNi0wMS0yNVQxMTo0NTo0MloiLCJpZCI6IjE2OTMifQ==

์‘๋‹ต์€ UI์— ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๋‚จ์Šต๋‹ˆ๋‹ค:

{
  "items": [{"id": 1693, "subject": "Login issue", "status": "open", "updated_at": "2026-01-25T11:45:42Z"}],
  "page": {"next_cursor": "...", "has_more": true},
  "meta": {"total": 128}
}

๋ชจ๋ฐ”์ผ์—์„œ๋Š” ๊ฐ™์€ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋ฌดํ•œ ์Šคํฌ๋กค์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์•ฑ์€ ํ•œ ๋ฒˆ์— 20๊ฐœ์˜ ํ‹ฐ์ผ“์„ ๋กœ๋“œํ•˜๊ณ , ๋‹ค์Œ ๋ฐฐ์น˜๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด next_cursor๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋กœ์ง์ด ์—†๊ณ , ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋ณ€ํ•ด๋„ ์ด๋ฏธ ์Šคํฌ๋กคํ•œ ๋ถ€๋ถ„์—์„œ ๋†€๋ผ์šด ์ผ์ด ์ ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ์€ ์ปค์„œ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณธ ์œ„์น˜(์˜ˆ: updated_at๊ณผ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋กœ์„œ id)๋ฅผ ์ธ์ฝ”๋”ฉํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ํ‹ฐ์ผ“์ด ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กคํ•˜๋Š” ๋™์•ˆ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ๋‹ค์Œ ์ƒˆ๋กœ๊ณ ์นจ์—์„œ ์œ„๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋ฏธ ์Šคํฌ๋กคํ•œ ํ”ผ๋“œ์—์„œ ์ค‘๋ณต์ด๋‚˜ ๊ฐ„๊ฒฉ์„ ๋งŒ๋“ค์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ณ„๋Š” ์œ ์šฉํ•˜์ง€๋งŒ ํฐ ๋ฐ์ดํ„ฐ์…‹์—์„œ๋Š” ๋น„์šฉ์ด ํฝ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ๊ทœ์น™์€ ์‚ฌ์šฉ์ž๊ฐ€ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ–ˆ๊ฑฐ๋‚˜ ๋ช…์‹œ์ ์œผ๋กœ ์š”์ฒญํ–ˆ์„ ๋•Œ๋งŒ meta.total์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(status=open ๊ฐ™์€ ๊ฒฝ์šฐ).

์ค‘๋ณต, ๊ฐ„๊ฒฉ, ์ง€์—ฐ์„ ์œ ๋ฐœํ•˜๋Š” ์ผ๋ฐ˜์  ์‹ค์ˆ˜

๋Œ€๋ถ€๋ถ„์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฒ„๊ทธ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ์‚ฌ์†Œํ•œ API ๊ฒฐ์ •์—์„œ ์˜ต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์—์„œ๋Š” ๊ดœ์ฐฎ์•„ ๋ณด์ด๋˜ ๊ฒƒ์ด ์š”์ฒญ ์‚ฌ์ด์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ฌด๋„ˆ์ง‘๋‹ˆ๋‹ค.

๊ฐ€์žฅ ํ”ํ•œ ์ค‘๋ณต(๋˜๋Š” ๋ˆ„๋ฝ) ์›์ธ์€ ๊ณ ์œ ํ•˜์ง€ ์•Š์€ ํ•„๋“œ๋กœ ์ •๋ ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. created_at์œผ๋กœ ์ •๋ ฌํ•  ๋•Œ ๋‘ ํ•ญ๋ชฉ์ด ๊ฐ™์€ ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๊ฐ€์ง€๋ฉด ์š”์ฒญ ์‚ฌ์ด์— ์ˆœ์„œ๊ฐ€ ๋’ค๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค: ํ•ญ์ƒ ๊ธฐ๋ณธ ํ‚ค ๊ฐ™์€ ์•ˆ์ •์ ์ธ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ •๋ ฌ์„ (created_at desc, id desc) ๊ฐ™์€ ์Œ์œผ๋กœ ์ทจ๊ธ‰ํ•˜์„ธ์š”.

๋˜ ๋‹ค๋ฅธ ํ”ํ•œ ๋ฌธ์ œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ํŽ˜์ด์ง€ ํฌ๊ธฐ๋“  ์š”์ฒญํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํฐ ์š”์ฒญ ํ•˜๋‚˜๊ฐ€ CPU, ๋ฉ”๋ชจ๋ฆฌ, ์‘๋‹ต ์‹œ๊ฐ„์„ ๊ธ‰์ฆ์‹œ์ผœ ๋ชจ๋“  ๊ด€๋ฆฌ์ž ํ™”๋ฉด์„ ๋А๋ ค์ง€๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ํ•ฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ’๊ณผ ๊ฐ•์ œ ์ตœ๋Œ€๊ฐ’์„ ์ •ํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋” ๋งŽ์ด ์š”์ฒญํ•˜๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

์ด๊ณ„๋„ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”์ฒญ์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ํ–‰์„ ์„ธ๋Š” ๊ฒƒ์€ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•„ํ„ฐ๊ฐ€ ์žˆ์„์ˆ˜๋ก ์ตœ์•…์ž…๋‹ˆ๋‹ค. UI๊ฐ€ ์ด๊ณ„๋ฅผ ํ•„์š”๋กœ ํ•œ๋‹ค๋ฉด ์š”์ฒญํ•  ๋•Œ๋งŒ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜(๋˜๋Š” ์ถ”์ •๊ฐ’ ๋ฐ˜ํ™˜) ์ „์ฒด ์นด์šดํŠธ์— UI๋ฅผ ๋ธ”๋กœํ‚นํ•˜์ง€ ๋งˆ์„ธ์š”.

๊ฐ€์žฅ ์ž์ฃผ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“œ๋Š” ์‹ค์ˆ˜:

  • ๊ณ ์œ  ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค ์—†๋Š” ์ •๋ ฌ(๋ถˆ์•ˆ์ •ํ•œ ์ˆœ์„œ)
  • ๋ฌด์ œํ•œ ํŽ˜์ด์ง€ ํฌ๊ธฐ(์„œ๋ฒ„ ๊ณผ๋ถ€ํ•˜)
  • ๋งค๋ฒˆ ์ด๊ณ„ ๋ฐ˜ํ™˜(๋А๋ฆฐ ์ฟผ๋ฆฌ)
  • ํ•˜๋‚˜์˜ ์—”๋“œํฌ์ธํŠธ์—์„œ ์˜คํ”„์…‹๊ณผ ์ปค์„œ ๊ทœ์น™์„ ํ˜ผํ•ฉ(ํด๋ผ์ด์–ธํŠธ ํ˜ผ๋ž€)
  • ํ•„ํ„ฐ๋‚˜ ์ •๋ ฌ์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ๊ฐ™์€ ์ปค์„œ ์žฌ์‚ฌ์šฉ(์ž˜๋ชป๋œ ๊ฒฐ๊ณผ)

ํ•„ํ„ฐ๋‚˜ ์ •๋ ฌ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๋ฆฌ์…‹ํ•˜์„ธ์š”. ์ƒˆ๋กœ์šด ํ•„ํ„ฐ๋Š” ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์œผ๋กœ ์ทจ๊ธ‰ํ•ด ์ปค์„œ/์˜คํ”„์…‹์„ ์ง€์šฐ๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”.

์ถœ์‹œ ์ „ ๋น ๋ฅธ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

Optimize mobile lists
Power smooth infinite scroll with fast, predictable paging from the same backend.
Create Mobile

API์™€ UI๋ฅผ ๋‚˜๋ž€ํžˆ ๋†“๊ณ  ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•ด ๋ณด์„ธ์š”. ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋Š” ๋ชฉ๋ก ํ™”๋ฉด๊ณผ ์„œ๋ฒ„ ๊ฐ„ ๊ณ„์•ฝ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  • ๊ธฐ๋ณธ ์ •๋ ฌ์ด ์•ˆ์ •์ ์ด๊ณ  ๊ณ ์œ  ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค๋ฅผ ํฌํ•จํ•˜๋Š”์ง€(์˜ˆ: created_at DESC, id DESC).
  • ์ •๋ ฌ ํ•„๋“œ์™€ ๋ฐฉํ–ฅ์ด ํ—ˆ์šฉ ๋ชฉ๋ก์— ์žˆ๋Š”์ง€.
  • ํ•ฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ’๊ณผ ์ตœ๋Œ€ ํŽ˜์ด์ง€ ํฌ๊ธฐ(์ตœ๋Œ€ limit)๊ฐ€ ๊ฐ•์ œ๋˜๋Š”์ง€.
  • ์ปค์„œ ํ† ํฐ์ด ๋ถˆํˆฌ๋ช…ํ•˜๊ณ  ์ž˜๋ชป๋œ ์ปค์„œ๋Š” ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋ฐฉ์‹์œผ๋กœ ์‹คํŒจํ•˜๋Š”์ง€.
  • ํ•„ํ„ฐ๋‚˜ ์ •๋ ฌ ๋ณ€๊ฒฝ ์‹œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ƒํƒœ๊ฐ€ ๋ฆฌ์…‹๋˜๋Š”์ง€.
  • ์ด๊ณ„ ๋™์ž‘์ด ๋ช…์‹œ์ ์ธ์ง€: ์ •ํ™•, ์ถ”์ • ๋˜๋Š” ์ƒ๋žต.
  • ๋™์ผํ•œ ๊ณ„์•ฝ์ด ํ…Œ์ด๋ธ”๊ณผ ๋ฌดํ•œ ์Šคํฌ๋กค์„ ํŠน์ˆ˜ ์ฒ˜๋ฆฌ ์—†์ด ๋ชจ๋‘ ์ง€์›ํ•˜๋Š”์ง€.

๋‹ค์Œ ๋‹จ๊ณ„: ๋ชฉ๋ก ํ‘œ์ค€ํ™” ๋ฐ ์ผ๊ด€์„ฑ ์œ ์ง€

์‚ฌ๋žŒ๋“ค์ด ๋งค์ผ ์‚ฌ์šฉํ•˜๋Š” ๊ด€๋ฆฌ์ž ๋ชฉ๋ก ํ•˜๋‚˜๋ฅผ ๊ณจ๋ผ ๊ทธ๊ฒƒ์„ ๊ณจ๋“œ ์Šคํƒ ๋”๋“œ๋กœ ๋งŒ๋“œ์„ธ์š”. Tickets, Orders, Users ๊ฐ™์€ ๋ฐ”์œ ํ…Œ์ด๋ธ”์ด ์ข‹์€ ์ถœ๋ฐœ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋น ๋ฅด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•ด์ง€๋ฉด ๋™์ผํ•œ ๊ณ„์•ฝ์„ ๋‹ค๋ฅธ ๊ด€๋ฆฌ์ž ํ™”๋ฉด๋“ค๋กœ ๋ณต์‚ฌํ•˜์„ธ์š”.

๊ณ„์•ฝ์„ ๋ฌธ์„œ๋กœ ๋‚จ๊ธฐ์„ธ์š”, ๊ฐ„๋‹จํ•˜๋”๋ผ๋„ ์ข‹์Šต๋‹ˆ๋‹ค. API๊ฐ€ ์ˆ˜๋ฝํ•˜๋Š” ๊ฒƒ๊ณผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•˜๋ฉด UI ํŒ€์ด ์ถ”์ธกํ•˜์ง€ ์•Š์•„ ์—”๋“œํฌ์ธํŠธ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ทœ์น™์„ ์‹ค์ˆ˜๋กœ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ๋ชฉ๋ก ์—”๋“œํฌ์ธํŠธ์— ์ ์šฉํ•  ๊ฐ„๋‹จํ•œ ํ‘œ์ค€:

  • ํ—ˆ์šฉ ์ •๋ ฌ: ์ •ํ™•ํ•œ ํ•„๋“œ ์ด๋ฆ„, ๋ฐฉํ–ฅ, ๋ช…ํ™•ํ•œ ๊ธฐ๋ณธ๊ฐ’(๊ทธ๋ฆฌ๊ณ  id ๊ฐ™์€ ํƒ€์ด๋ธŒ๋ ˆ์ด์ปค)
  • ํ—ˆ์šฉ ํ•„ํ„ฐ: ์–ด๋–ค ํ•„๋“œ๋ฅผ ํ•„ํ„ฐํ•  ์ˆ˜ ์žˆ๋Š”์ง€, ๊ฐ’ ํฌ๋งท, ์ž˜๋ชป๋œ ํ•„ํ„ฐ์— ๋Œ€ํ•œ ๋™์ž‘
  • ์ด๊ณ„ ๋™์ž‘: ์–ธ์ œ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€, ์–ธ์ œ โ€œunknownโ€์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€, ์–ธ์ œ ์ƒ๋žตํ•˜๋Š”์ง€
  • ์‘๋‹ต ํ˜•ํƒœ: ์ผ๊ด€๋œ ํ‚ค(items, ํŽ˜์ด์ง• ์ •๋ณด, ์ ์šฉ๋œ ์ •๋ ฌ/ํ•„ํ„ฐ, totals)
  • ์˜ค๋ฅ˜ ๊ทœ์น™: ์ผ๊ด€๋œ ์ƒํƒœ ์ฝ”๋“œ์™€ ์ฝ๊ธฐ ์‰ฌ์šด ๊ฒ€์ฆ ๋ฉ”์‹œ์ง€

AppMaster๋กœ ์ด๋Ÿฌํ•œ ๊ด€๋ฆฌ์ž ํ™”๋ฉด์„ ๋นŒ๋“œํ•œ๋‹ค๋ฉด(์˜ˆ: appmaster.io), ์ผ์ฐ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ณ„์•ฝ์„ ํ‘œ์ค€ํ™”ํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ๋ชฉ๋ก ๋™์ž‘์„ ์›น ์•ฑ๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋ฐ”์ผ ์•ฑ ์ „๋ฐ˜์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋‚˜์ค‘์— ํŽ˜์ด์ง€๋„ค์ด์…˜ ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ์ซ“์•„๋‹ค๋‹ˆ๋Š” ๋ฐ ๋“œ๋Š” ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ

Whatโ€™s the real difference between offset and cursor pagination?

Offset pagination uses limit plus offset (or page/pageSize) to skip rows, so deeper pages often get slower as the database has to walk past more records. Cursor pagination uses an after token based on the last itemโ€™s sort values, so it can jump to a known position and stay fast as you keep moving forward.

Why does my admin table feel slower the more pages I go through?

Because page 1 is usually cheap, but page 200 forces the database to skip a large number of rows before it can return anything. If you also sort and filter, the work grows, so each click feels more like a new heavy query than a quick fetch.

How do I prevent duplicates or missing rows when users paginate?

Always use a stable sort with a unique tie-breaker, such as created_at DESC, id DESC or updated_at DESC, id DESC. Without the tie-breaker, records with the same timestamp can swap order between requests, which is a common cause of duplicates and โ€œmissingโ€ rows.

When should I prefer cursor pagination?

Use cursor pagination for lists where people mostly move forward and speed matters, like activity logs, tickets, orders, and mobile infinite scroll. It stays consistent when new rows are inserted or deleted, because the cursor anchors the next page to an exact last-seen position.

When does offset pagination still make sense?

Offset pagination fits best when โ€œjump to page Nโ€ is a real UI feature and users regularly bounce around. Itโ€™s also convenient for small tables or stable datasets, where deep-page slowdown and shifting results are unlikely to matter.

What should a consistent pagination API response include?

Keep one response shape across endpoints and include the items, paging state, and optional totals. A practical default is returning items, a page object (with limit, nextCursor/prevCursor or offset), and a lightweight flag like hasNext so both web tables and mobile lists can reuse the same client logic.

Why can totals make pagination slow, and whatโ€™s a safer default?

Because exact COUNT(*) on large, filtered datasets can become the slowest part of the request and make every page change feel laggy. A good default is to make totals optional, return them only when requested, or return has_more when the UI only needs โ€œLoad more.โ€

What should happen to the cursor when filters or sorting changes?

Treat filters as part of the dataset, and treat the cursor as valid only for that exact filter and sort combination. If a user changes any filter or sort, reset pagination and start from the first page; reusing an old cursor after changes is a common way to get empty pages or confusing results.

How do I make sorting fast and predictable for pagination?

Whitelist allowed sort fields and directions, and reject anything else so clients canโ€™t accidentally request slow or unstable ordering. Prefer sorting on indexed fields and always append a unique tie-breaker like id to keep the order deterministic across requests.

What guardrails should I add before shipping a pagination endpoint?

Enforce a maximum limit, validate filters and sort parameters, and make cursor tokens opaque and strictly validated. If youโ€™re building admin screens in AppMaster, keeping these rules consistent across all list endpoints makes it easier to reuse the same table and infinite-scroll behavior without custom pagination fixes per screen.

์‰ฌ์šด ์‹œ์ž‘
๋ฉ‹์ง„๋งŒ๋“ค๊ธฐ

๋ฌด๋ฃŒ ์š”๊ธˆ์ œ๋กœ AppMaster๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.
์ค€๋น„๊ฐ€ ๋˜๋ฉด ์ ์ ˆํ•œ ๊ตฌ๋…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ํ•˜๋‹ค
๊ด€๋ฆฌ์ž ํ™”๋ฉด API๋ฅผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“œ๋Š”: ์ปค์„œ vs ์˜คํ”„์…‹ ํŽ˜์ด์ง€๋„ค์ด์…˜ | AppMaster