REST API ๊ฐœ๋ฐœ: C#๊ณผ ASP.NET Core Web API ๐Ÿš€

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - REST API ๊ฐœ๋ฐœ: C#๊ณผ ASP.NET Core Web API ๐Ÿš€

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐœ๋ฐœ์ž ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ ํ˜„๋Œ€ ์›น ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ ์š”์†Œ์ธ REST API ๊ฐœ๋ฐœ์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ C#๊ณผ ASP.NET Core Web API๋ฅผ ํ™œ์šฉํ•œ REST API ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ƒ์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ถ„์€ REST API์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ œ ๊ตฌํ˜„๊นŒ์ง€ ๋ชจ๋“  ๊ณผ์ •์„ ๋ฐฐ์šฐ์‹ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐ŸŒŸ

ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ REST API๋Š” ํ•„์ˆ˜์ ์ธ ์š”์†Œ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ํšจ์œจ์ ์ธ ํ†ต์‹ ์„ ์œ„ํ•ด, ๊ทธ๋ฆฌ๊ณ  ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด REST API๋Š” ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์ฃ . C#๊ณผ ASP.NET Core๋Š” ์ด๋Ÿฌํ•œ REST API๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ์žˆ์–ด ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” REST API์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ, C#๊ณผ ASP.NET Core Web API๋ฅผ ์‚ฌ์šฉํ•œ ์‹ค์ œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•, ๋ณด์•ˆ ๋ฐ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๊นŒ์ง€ ํญ๋„“๊ฒŒ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๊ทธ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•๋„ ํ•จ๊ป˜ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์ด ์ด ๊ธ€์„ ์ฝ๊ณ  ๋‚˜๋ฉด, REST API ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ๊นŠ์ด ์žˆ๋Š” ์ดํ•ด์™€ ํ•จ๊ป˜ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์šฉ์ ์ธ ์ง€์‹์„ ์–ป๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ง€๊ธˆ๋ถ€ํ„ฐ REST API์˜ ์„ธ๊ณ„๋กœ ํ•จ๊ป˜ ๋– ๋‚˜๋ณผ๊นŒ์š”? ๐ŸŒˆ

1. REST API์˜ ๊ธฐ๋ณธ ๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ ๐Ÿ“š

REST API๋ฅผ ์ œ๋Œ€๋กœ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € ๊ทธ ๊ธฐ๋ณธ ๊ฐœ๋…์„ ํ™•์‹คํžˆ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. REST(Representational State Transfer)๋Š” ์›น ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ๋กœ, ๋ฆฌ์†Œ์Šค ์ค‘์‹ฌ์˜ ์„ค๊ณ„ ์ฒ ํ•™์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

1.1 REST์˜ ํ•ต์‹ฌ ์›์น™

  • ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๊ตฌ์กฐ: ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฌด์ƒํƒœ์„ฑ(Stateless): ๊ฐ ์š”์ฒญ์€ ๋…๋ฆฝ์ ์ด๋ฉฐ, ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์บ์‹œ ๊ฐ€๋Šฅ์„ฑ: ์‘๋‹ต์€ ์บ์‹œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ณ„์ธตํ™” ์‹œ์Šคํ…œ: ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์™€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€ ์ค‘๊ฐ„ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๊ท ์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค: ๋ฆฌ์†Œ์Šค ์‹๋ณ„, ํ‘œํ˜„์„ ํ†ตํ•œ ๋ฆฌ์†Œ์Šค ์กฐ์ž‘, ์ž๊ธฐ ์„œ์ˆ ์  ๋ฉ”์‹œ์ง€, HATEOAS๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

1.2 REST API์˜ ์ฃผ์š” ํŠน์ง•

REST API๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์š” ํŠน์ง•์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค:

  • ๋ฆฌ์†Œ์Šค ์ค‘์‹ฌ: ๋ชจ๋“  ๊ฒƒ์„ ๋ฆฌ์†Œ์Šค(์ž์›)๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • HTTP ๋ฉ”์„œ๋“œ ํ™œ์šฉ: GET, POST, PUT, DELETE ๋“ฑ์˜ HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค๋ฅผ ์กฐ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • URI๋ฅผ ํ†ตํ•œ ๋ฆฌ์†Œ์Šค ์‹๋ณ„: ๊ฐ ๋ฆฌ์†Œ์Šค๋Š” ๊ณ ์œ ํ•œ URI๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
  • ํ‘œํ˜„์˜ ๋‹ค์–‘์„ฑ: JSON, XML ๋“ฑ ๋‹ค์–‘ํ•œ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1.3 REST API ์„ค๊ณ„ ์›์น™

ํšจ๊ณผ์ ์ธ REST API ์„ค๊ณ„๋ฅผ ์œ„ํ•ด ๋‹ค์Œ ์›์น™์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค:

  • URI๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๋‚˜ํƒ€๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: ์˜ˆ) /users, /products
  • ํ–‰์œ„๋Š” HTTP ๋ฉ”์„œ๋“œ๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค: GET(์กฐํšŒ), POST(์ƒ์„ฑ), PUT(์ˆ˜์ •), DELETE(์‚ญ์ œ)
  • ๋ณต์ˆ˜ํ˜• ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค: /users ๋Œ€์‹  /user
  • ์ผ๊ด€์„ฑ ์žˆ๋Š” ๋Œ€์†Œ๋ฌธ์ž ์‚ฌ์šฉ: ๋ณดํ†ต ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ํ•˜์ดํ”ˆ(-)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค: /user-profiles
REST API ๊ตฌ์กฐ REST API ๊ตฌ์กฐ ํด๋ผ์ด์–ธํŠธ ์„œ๋ฒ„ HTTP ์š”์ฒญ HTTP ์‘๋‹ต GET, POST, PUT, DELETE ๋“ฑ์˜ HTTP ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ JSON, XML ๋“ฑ์˜ ๋ฐ์ดํ„ฐ ํ˜•์‹

์ด๋Ÿฌํ•œ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ์›์น™์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ํšจ๊ณผ์ ์ธ REST API ๊ฐœ๋ฐœ์˜ ์ฒซ ๊ฑธ์Œ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ C#๊ณผ ASP.NET Core Web API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

REST API์˜ ๊ฐœ๋…์„ ์ดํ•ดํ–ˆ๋‹ค๋ฉด, ์ด์ œ C#๊ณผ ASP.NET Core Web API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€ ์•Œ์•„๋ณผ ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ๊ธฐ๋ณธ์ ์ธ API ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ› ๏ธ

2. C#๊ณผ ASP.NET Core Web API ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • ๐Ÿ–ฅ๏ธ

REST API๋ฅผ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•œ ์ฒซ ๋‹จ๊ณ„๋Š” ์ ์ ˆํ•œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. C#๊ณผ ASP.NET Core Web API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋„๊ตฌ๋“ค์„ ์„ค์น˜ํ•˜๊ณ  ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2.1 ํ•„์š”ํ•œ ๋„๊ตฌ ์„ค์น˜

  • .NET SDK: ASP.NET Core ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • Visual Studio ๋˜๋Š” Visual Studio Code: ์ฝ”๋“œ ํŽธ์ง‘๊ณผ ๋””๋ฒ„๊น…์„ ์œ„ํ•œ IDE์ž…๋‹ˆ๋‹ค.
  • Git: ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Postman ๋˜๋Š” Insomnia: API ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

2.2 .NET SDK ์„ค์น˜

1. Microsoft .NET ์›น์‚ฌ์ดํŠธ์—์„œ ์ตœ์‹  ๋ฒ„์ „์˜ .NET SDK๋ฅผ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

2. ๋‹ค์šด๋กœ๋“œํ•œ ์„ค์น˜ ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๊ณ  ์ง€์‹œ์— ๋”ฐ๋ผ ์„ค์น˜๋ฅผ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

3. ์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์„ค์น˜๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค:

dotnet --version

2.3 Visual Studio ์„ค์น˜ (์„ ํƒ์‚ฌํ•ญ)

1. Visual Studio ์›น์‚ฌ์ดํŠธ์—์„œ Community ๋ฒ„์ „์„ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

2. ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๊ณ  "ASP.NET ๋ฐ ์›น ๊ฐœ๋ฐœ" ์›Œํฌ๋กœ๋“œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

3. ์„ค์น˜๋ฅผ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

2.4 Visual Studio Code ์„ค์น˜ (์„ ํƒ์‚ฌํ•ญ)

1. Visual Studio Code ์›น์‚ฌ์ดํŠธ์—์„œ ์„ค์น˜ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

2. ์„ค์น˜ ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๊ณ  ์ง€์‹œ์— ๋”ฐ๋ผ ์„ค์น˜๋ฅผ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

3. VS Code๋ฅผ ์‹คํ–‰ํ•˜๊ณ  C# ํ™•์žฅ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

2.5 ์ƒˆ ASP.NET Core Web API ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

dotnet new webapi -n MyRestApi

์ด ๋ช…๋ น์–ด๋Š” 'MyRestApi'๋ผ๋Š” ์ด๋ฆ„์˜ ์ƒˆ๋กœ์šด ASP.NET Core Web API ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

2.6 ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์‚ดํŽด๋ณด๊ธฐ

์ƒ์„ฑ๋œ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • Program.cs: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง„์ž…์ ์ž…๋‹ˆ๋‹ค.
  • Startup.cs: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ์„ฑ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • Controllers/: API ์ปจํŠธ๋กค๋Ÿฌ๋“ค์ด ์œ„์น˜ํ•˜๋Š” ํด๋”์ž…๋‹ˆ๋‹ค.
  • appsettings.json: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ • ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.
ASP.NET Core Web API ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ASP.NET Core Web API ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ MyRestApi (ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ) Program.cs Startup.cs appsettings.json Controllers/ WeatherForecast.cs Models/ Services/

์ด์ œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์ œ REST API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. C#๊ณผ ASP.NET Core Web API์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ํšจ์œจ์ ์ด๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ API๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿš€

๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •์€ ํ”„๋กœ์ ํŠธ์˜ ์„ฑ๊ณต์„ ์œ„ํ•œ ์ค‘์š”ํ•œ ์ฒซ ๊ฑธ์Œ์ž…๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ์–ด๋ ค์›€์„ ๊ฒช์œผ์‹ ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)๊ณผ ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ๊ฒฝํ—˜ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ๊ป˜ ๋ฐฐ์šฐ๊ณ  ์„ฑ์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐœ๋ฐœ์˜ ์ฆ๊ฑฐ์›€์ด๋‹ˆ๊นŒ์š”! ๐Ÿ˜Š

์ž, ์ด์ œ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์‹ค์ œ๋กœ REST API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. C#์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ๊ณผ ASP.NET Core์˜ ์œ ์—ฐ์„ฑ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์–ด๋–ป๊ฒŒ ํšจ์œจ์ ์ธ API๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”์ง€ ํ•จ๊ป˜ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ค€๋น„๋˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ์š”! ๐Ÿš€

3. REST API ๊ตฌํ˜„ํ•˜๊ธฐ: ๊ธฐ๋ณธ CRUD ์ž‘์—… ๐Ÿ› ๏ธ

์ด์ œ ์‹ค์ œ๋กœ REST API๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ CRUD(Create, Read, Update, Delete) ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” API๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๋ฉด์„œ C#๊ณผ ASP.NET Core Web API์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋“ค์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

3.1 ๋ชจ๋ธ ์ •์˜ํ•˜๊ธฐ

๋จผ์ €, ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฃฐ ๋ฐ์ดํ„ฐ์˜ ๋ชจ๋ธ์„ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐ„๋‹จํ•œ ์ฑ…(Book) ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


// Models/Book.cs
public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public int PublicationYear { get; set; }
}

3.2 ์ปจํŠธ๋กค๋Ÿฌ ์ƒ์„ฑํ•˜๊ธฐ

์ด์ œ Book ๋ชจ๋ธ์„ ๋‹ค๋ฃจ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


// Controllers/BooksController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private static List<Book> _books = new List<Book>();
    private static int _nextId = 1;

    [HttpGet]
    public ActionResult<IEnumerable<Book>> GetAllBooks()
    {
        return Ok(_books);
    }

    [HttpGet("{id}")]
    public ActionResult<Book> GetBook(int id)
    {
        var book = _books.FirstOrDefault(b => b.Id == id);
        if (book == null)
            return NotFound();
        return Ok(book);
    }

    [HttpPost]
    public ActionResult<Book> CreateBook(Book book)
    {
        book.Id = _nextId++;
        _books.Add(book);
        return CreatedAtAction(nameof(GetBook), new { id = book.Id }, book);
    }

    [HttpPut("{id}")]
    public IActionResult UpdateBook(int id, Book book)
    {
        var existingBook = _books.FirstOrDefault(b => b.Id == id);
        if (existingBook == null)
            return NotFound();

        existingBook.Title = book.Title;
        existingBook.Author = book.Author;
        existingBook.PublicationYear = book.PublicationYear;

        return NoContent();
    }

    [HttpDelete("{id}")]
    public IActionResult DeleteBook(int id)
    {
        var book = _books.FirstOrDefault(b => b.Id == id);
        if (book == null)
            return NotFound();

        _books.Remove(book);
        return NoContent();
    }
}

3.3 API ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…

  • GET /api/books: ๋ชจ๋“  ์ฑ… ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • GET /api/books/{id}: ํŠน์ • ID์˜ ์ฑ… ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • POST /api/books: ์ƒˆ๋กœ์šด ์ฑ…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • PUT /api/books/{id}: ํŠน์ • ID์˜ ์ฑ… ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  • DELETE /api/books/{id}: ํŠน์ • ID์˜ ์ฑ…์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

3.4 API ํ…Œ์ŠคํŠธํ•˜๊ธฐ

์ด์ œ Postman์ด๋‚˜ curl์„ ์‚ฌ์šฉํ•˜์—ฌ API๋ฅผ ํ…Œ์ŠคํŠธํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ƒˆ๋กœ์šด ์ฑ…์„ ์ถ”๊ฐ€ํ•˜๋Š” POST ์š”์ฒญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:


POST http://localhost:5000/api/books
Content-Type: application/json

{
    "title": "1984",
    "author": "George Orwell",
    "publicationYear": 1949
}
REST API CRUD ์ž‘์—… ํ๋ฆ„ REST API CRUD ์ž‘์—… ํ๋ฆ„ ํด๋ผ์ด์–ธํŠธ API ์ปจํŠธ๋กค๋Ÿฌ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ ์กฐ์ž‘ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ HTTP ์‘๋‹ต GET (Read) POST (Create) PUT (Update) DELETE (Delete)

์ด๋ ‡๊ฒŒ ๊ธฐ๋ณธ์ ์ธ CRUD ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” REST API๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋” ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ๊ฐ€์ง„ API๋ฅผ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

REST API ๊ฐœ๋ฐœ์€ ํ˜„๋Œ€ ์›น ๊ฐœ๋ฐœ์—์„œ ๋งค์šฐ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ์ˆ ์„ ์ตํžˆ๊ณ  ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๋กœ์„œ์˜ ๊ฐ€์น˜๋ฅผ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด ๊ณผ์ •์—์„œ ์–ด๋ ค์›€์„ ๊ฒช๊ฑฐ๋‚˜ ๋” ๊นŠ์ด ์žˆ๋Š” ์ง€์‹์„ ์–ป๊ณ  ์‹ถ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)๊ณผ ๊ฐ™์€ ํ”Œ๋žซํผ์„ ํ†ตํ•ด ๊ฒฝํ—˜ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ๊ป˜ ๋ฐฐ์šฐ๊ณ  ์„ฑ์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐœ๋ฐœ์˜ ์ฆ๊ฑฐ์›€์ด๋‹ˆ๊นŒ์š”! ๐Ÿ˜Š

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด ๊ธฐ๋ณธ์ ์ธ API๋ฅผ ๋”์šฑ ๋ฐœ์ „์‹œ์ผœ, ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์˜ API๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™, ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ, ๋กœ๊น…, ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋“ฑ ๋” ๊ณ ๊ธ‰ ์ฃผ์ œ๋“ค์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ํ•จ๊ป˜ ๋ฐฐ์›Œ๋‚˜๊ฐ€ ๋ด…์‹œ๋‹ค! ๐Ÿš€

4. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™: Entity Framework Core ์‚ฌ์šฉํ•˜๊ธฐ ๐Ÿ’พ

์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Entity Framework Core๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

4.1 Entity Framework Core ์„ค์น˜

๋จผ์ €, ๋„ค, ๊ณ„์†ํ•ด์„œ Entity Framework Core๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™์— ๋Œ€ํ•ด ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

4.1 Entity Framework Core ์„ค์น˜

๋จผ์ €, ํ”„๋กœ์ ํŠธ์— Entity Framework Core๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

4.2 DbContext ํด๋ž˜์Šค ์ƒ์„ฑ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌํ•  DbContext ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:


// Data/BookContext.cs
using Microsoft.EntityFrameworkCore;

public class BookContext : DbContext
{
    public BookContext(DbContextOptions<bookcontext> options) : base(options)
    {
    }

    public DbSet<book> Books { get; set; }
}
</book></bookcontext>

4.3 Startup.cs ์ˆ˜์ •

Startup.cs ํŒŒ์ผ์—์„œ DbContext๋ฅผ ์„œ๋น„์Šค๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค:


public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<bookcontext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddControllers();
}
</bookcontext>

4.4 appsettings.json์— ์—ฐ๊ฒฐ ๋ฌธ์ž์—ด ์ถ”๊ฐ€


{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=BookApiDb;Trusted_Connection=True;"
  },
  // ๊ธฐํƒ€ ์„ค์ •...
}

4.5 ์ปจํŠธ๋กค๋Ÿฌ ์ˆ˜์ •

์ด์ œ BooksController๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค:


[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BookContext _context;

    public BooksController(BookContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task<actionresult>>> GetAllBooks()
    {
        return await _context.Books.ToListAsync();
    }

    [HttpGet("{id}")]
    public async Task<actionresult>> GetBook(int id)
    {
        var book = await _context.Books.FindAsync(id);
        if (book == null)
            return NotFound();
        return book;
    }

    [HttpPost]
    public async Task<actionresult>> CreateBook(Book book)
    {
        _context.Books.Add(book);
        await _context.SaveChangesAsync();
        return CreatedAtAction(nameof(GetBook), new { id = book.Id }, book);
    }

    [HttpPut("{id}")]
    public async Task<iactionresult> UpdateBook(int id, Book book)
    {
        if (id != book.Id)
            return BadRequest();

        _context.Entry(book).State = EntityState.Modified;
        
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!BookExists(id))
                return NotFound();
            else
                throw;
        }

        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<iactionresult> DeleteBook(int id)
    {
        var book = await _context.Books.FindAsync(id);
        if (book == null)
            return NotFound();

        _context.Books.Remove(book);
        await _context.SaveChangesAsync();
        return NoContent();
    }

    private bool BookExists(int id)
    {
        return _context.Books.Any(e => e.Id == id);
    }
}
</iactionresult></iactionresult></actionresult></actionresult></actionresult>

4.6 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ƒ์„ฑ ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—…๋ฐ์ดํŠธ

๋งˆ์ง€๋ง‰์œผ๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

dotnet ef migrations add InitialCreate
dotnet ef database update
Entity Framework Core ๋ฐ์ดํ„ฐ ํ๋ฆ„ Entity Framework Core ๋ฐ์ดํ„ฐ ํ๋ฆ„ API ์ปจํŠธ๋กค๋Ÿฌ DbContext ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค LINQ ์ฟผ๋ฆฌ SQL ์ฟผ๋ฆฌ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด Entity Framework Core๊ฐ€ LINQ๋ฅผ SQL๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋กœ ๋งคํ•‘

์ด์ œ ์šฐ๋ฆฌ์˜ REST API๋Š” ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๋™๋˜์–ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. Entity Framework Core๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ถ”์ƒํ™”ํ•˜๊ณ , ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™์€ ๋Œ€๋ถ€๋ถ„์˜ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„์ˆ˜์ ์ธ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. Entity Framework Core๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” API์˜ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. REST API๋ฅผ ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณด์•ˆ์ด ๋งค์šฐ ์ค‘์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ํ•จ๊ป˜ ๋ฐฐ์›Œ๋‚˜๊ฐ€ ๋ด…์‹œ๋‹ค! ๐Ÿ”’

5. API ๋ณด์•ˆ: ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ ๐Ÿ”

API์˜ ๋ณด์•ˆ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ์„น์…˜์—์„œ๋Š” JWT(JSON Web Tokens)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

5.1 ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์น˜

๋จผ์ €, JWT ๊ด€๋ จ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

5.2 JWT ์„ค์ • ์ถ”๊ฐ€

appsettings.json์— JWT ์„ค์ •์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:


{
  "Jwt": {
    "Key": "ThisIsMySecretKey",
    "Issuer": "https://myapi.com",
    "Audience": "https://myapi.com"
  },
  // ๊ธฐํƒ€ ์„ค์ •...
}

5.3 JWT ์ธ์ฆ ์„œ๋น„์Šค ๋“ฑ๋ก

Startup.cs์˜ ConfigureServices ๋ฉ”์„œ๋“œ์— JWT ์ธ์ฆ ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค:


public void ConfigureServices(IServiceCollection services)
{
    // ๊ธฐ์กด ์„œ๋น„์Šค ๋“ฑ๋ก...

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
        });
}

๊ทธ๋ฆฌ๊ณ  Configure ๋ฉ”์„œ๋“œ์— ์ธ์ฆ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ๊ธฐ์กด ๋ฏธ๋“ค์›จ์–ด...

    app.UseAuthentication();
    app.UseAuthorization();

    // ๊ธฐํƒ€ ๋ฏธ๋“ค์›จ์–ด...
}

5.4 ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ ์ƒ์„ฑ

์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์œ„ํ•œ ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค:


[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginModel login)
    {
        // ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ์ž ํ™•์ธ
        if (login.Username == "admin" && login.Password == "password")
        {
            var token = GenerateJwtToken(login.Username);
            return Ok(new { token });
        }

        return Unauthorized();
    }

    private string GenerateJwtToken(string username)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _configuration["Jwt:Issuer"],
            audience: _configuration["Jwt:Audience"],
            claims: new[] { new Claim(ClaimTypes.Name, username) },
            expires: DateTime.Now.AddMinutes(120),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

public class LoginModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

5.5 API ์—”๋“œํฌ์ธํŠธ ๋ณดํ˜ธ

์ด์ œ BooksController์— [Authorize] ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค:


[Authorize]
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    // ๊ธฐ์กด ์ฝ”๋“œ...
}

5.6 API ์‚ฌ์šฉ ์˜ˆ์‹œ

์ด์ œ API๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  1. ๋กœ๊ทธ์ธํ•˜์—ฌ JWT ํ† ํฐ ๋ฐ›๊ธฐ:
    
    POST /api/auth/login
    Content-Type: application/json
    
    {
        "username": "admin",
        "password": "password"
    }
    
  2. ๋ฐ›์€ ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ API ํ˜ธ์ถœ:
    
    GET /api/books
    Authorization: Bearer [์—ฌ๊ธฐ์—_๋ฐ›์€_ํ† ํฐ]
    
JWT ์ธ์ฆ ํ๋ฆ„ JWT ์ธ์ฆ ํ๋ฆ„ ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ ์„œ๋ฒ„ API ์„œ๋ฒ„ 1. ๋กœ๊ทธ์ธ ์š”์ฒญ 3. API ์š”์ฒญ + JWT 2. JWT ๋ฐ˜ํ™˜ 4. ์‘๋‹ต JWT๋ฅผ ์‚ฌ์šฉํ•œ ์ธ์ฆ์œผ๋กœ ์•ˆ์ „ํ•œ API ์•ก์„ธ์Šค ๋ณด์žฅ

์ด๋ ‡๊ฒŒ JWT๋ฅผ ์‚ฌ์šฉํ•œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ API์˜ ๋ณด์•ˆ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋” ๋ณต์žกํ•œ ์ธ์ฆ ๋กœ์ง๊ณผ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ์˜ˆ์ œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ™•์žฅํ•ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

API ๋ณด์•ˆ์€ ๋Š์ž„์—†์ด ๋ฐœ์ „ํ•˜๋Š” ๋ถ„์•ผ์ž…๋‹ˆ๋‹ค. ์ตœ์‹  ๋ณด์•ˆ ๋™ํ–ฅ์„ ๋”ฐ๋ผ๊ฐ€๊ณ  ์ง€์†์ ์œผ๋กœ ์‹œ์Šคํ…œ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, HTTPS ์‚ฌ์šฉ, ์ ์ ˆํ•œ CORS ์„ค์ •, ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋“ฑ ๋‹ค๋ฅธ ๋ณด์•ˆ ์ธก๋ฉด๋„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” API์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํšจ์œจ์ ์ด๊ณ  ์•ˆ์ „ํ•œ API๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ์—ฌ์ •์„ ๊ณ„์† ์ด์–ด๊ฐ€ ๋ด…์‹œ๋‹ค! ๐Ÿš€

6. API ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฐ ์Šค์ผ€์ผ๋ง ๐Ÿš€

API์˜ ์„ฑ๋Šฅ๊ณผ ํ™•์žฅ์„ฑ์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊ณผ ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ์„น์…˜์—์„œ๋Š” C#๊ณผ ASP.NET Core๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

6.1 ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

ASP.NET Core์—์„œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉํ•˜๋ฉด ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ async/await ํŒจํ„ด์œผ๋กœ ๋ณ€๊ฒฝํ•ด๋ด…์‹œ๋‹ค:


[HttpGet]
public async Task<actionresult>>> GetAllBooks()
{
    return await _context.Books.ToListAsync();
}
</actionresult>

6.2 ์บ์‹ฑ ๊ตฌํ˜„

์ž์ฃผ ์š”์ฒญ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ASP.NET Core์˜ ์ธ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•ด๋ด…์‹œ๋‹ค:


public void ConfigureServices(IServiceCollection services)
{
    // ๊ธฐ์กด ์„œ๋น„์Šค ๋“ฑ๋ก...
    services.AddMemoryCache();
}

[HttpGet]
public async Task<actionresult>>> GetAllBooks([FromServices] IMemoryCache cache)
{
    if (!cache.TryGetValue("AllBooks", out List<book> books))
    {
        books = await _context.Books.ToListAsync();
        var cacheEntryOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(5));
        cache.Set("AllBooks", books, cacheEntryOptions);
    }
    return books;
}
</book></actionresult>

6.3 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์ตœ์ ํ™”

Entity Framework Core์—์„œ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…์‹œ๋‹ค:


// ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์„ ํƒ
var books = await _context.Books
    .Select(b => new { b.Id, b.Title, b.Author })
    .ToListAsync();

// ํŽ˜์ด์ง• ๊ตฌํ˜„
var pageSize = 10;
var pageNumber = 1;
var books = await _context.Books
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();

// ์ธ๋ฑ์Šค ์‚ฌ์šฉ
// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ํ–ฅ์ƒ

6.4 ์••์ถ• ์‚ฌ์šฉ

์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์••์ถ•ํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ๋Œ€์—ญํญ์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:


public void ConfigureServices(IServiceCollection services)
{
    // ๊ธฐ์กด ์„œ๋น„์Šค ๋“ฑ๋ก...
    services.AddResponseCompression();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ๊ธฐ์กด ๋ฏธ๋“ค์›จ์–ด...
    app.UseResponseCompression();
    // ๊ธฐํƒ€ ๋ฏธ๋“ค์›จ์–ด...
}

6.5 ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ

์—ฌ๋Ÿฌ ์„œ๋ฒ„ ์ธ์Šคํ„ด์Šค์— ํŠธ๋ž˜ํ”ฝ์„ ๋ถ„์‚ฐ์‹œ์ผœ ์‹œ์Šคํ…œ์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Azure App Service๋‚˜ AWS Elastic Beanstalk ๊ฐ™์€ ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

6.6 ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๋กœ๊น…

Application Insights๋‚˜ Serilog์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API์˜ ์„ฑ๋Šฅ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  ๋กœ๊ทธ๋ฅผ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค:


public void ConfigureServices(IServiceCollection services)
{
    // ๊ธฐ์กด ์„œ๋น„์Šค ๋“ฑ๋ก...
    services.AddApplicationInsightsTelemetry();
}
API ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ „๋žต API ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ „๋žต ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์บ์‹ฑ ์ฟผ๋ฆฌ ์ตœ์ ํ™” ์••์ถ• ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๋กœ๊น… ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค ํ™œ์šฉ ์ตœ์ ํ™”๋œ ์„ฑ๋Šฅ๊ณผ ํ™•์žฅ์„ฑ์„ ๊ฐ–์ถ˜ REST API

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

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

์ด๋กœ์จ C#๊ณผ ASP.NET Core๋ฅผ ์‚ฌ์šฉํ•œ REST API ๊ฐœ๋ฐœ์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ๋‚ด์šฉ์„ ๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ CRUD ์ž‘์—…๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™, ๋ณด์•ˆ, ์„ฑ๋Šฅ ์ตœ์ ํ™”๊นŒ์ง€, API ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ ์š”์†Œ๋“ค์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด ์ง€์‹์„ ๋ฐ”ํƒ•์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์€ ์ด์ œ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ REST API๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

API ๊ฐœ๋ฐœ์€ ๊ณ„์†ํ•ด์„œ ๋ฐœ์ „ํ•˜๋Š” ๋ถ„์•ผ์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ๊ณผ ํŒจํ„ด์„ ํ•™์Šตํ•˜๊ณ , ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด ๋ณด๋ฉด์„œ ๊ฒฝํ—˜์„ ์Œ“์•„๊ฐ€๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ API ๊ฐœ๋ฐœ ์—ฌ์ •์— ํ–‰์šด์ด ํ•จ๊ป˜ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค! ๐ŸŒŸ