공부/인프런 - Rookiss

Part 6-7-2. WebAPI와 REST 서비스 : WebApi #2

셩잇님 2024. 10. 13. 20:19
반응형

 

 

🌀 WebAPI와 REST 서비스

 

 지난 시간에는 Blazor가 아닌 WebApi와 REST 서비스를 통해 Blazor와 WebApi 연동, 더 나아가 Unity와 WebApi를 연동하는 첫 번째 시간을 가져보았다. 새로운 프로젝트를 .Net Core Web App로 만들어주고, 마찬가지로 공용 데이터를 저장할 프로젝트도 하나 더 만들어 주었다. 이 후 ApplicationDbContext 스크립트를 만들어 DB 연동을 위해 PM을 통해 마이그레이션을 진행을 했다. 이번 시간에서는 본격적으로 웹 API를 만들어 보는 시간을 가져보도록 한다.

 


 

🐊 WebApi #2

 

 웹 API를 사용하기 위해 프로젝트에 Controllers 폴더를 만들어주고, 해당 폴더 산하에 API 컨트롤러 - 비어있음 형태의 RankingController.cs를 새롭게 만들어주도록하자. API 컨트롤러 형태를 선택하여 만들면 아래와 같이 [Route]와 [ApiController]의 값이 붙어 있는 것을 확인할 수 있다.

 

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SharedData.Models;
using WebApi.Data;

namespace WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RankingController : ControllerBase
    {
    }
}

 

 이는 Web Api를 만들 때 라우팅을 하겠다는 의미로 나타낼 수 있으며 Route와  ApiController는 둘이 항상 세트로 넣어줘야 한다. 이제 REST에 대해서 알아보도록 하자.

 


 

 

...

namespace WebApi.Controllers
{
    // REST (Representational State Transfer)
    // 공식 효준 스펙은 아니다.
    // 원래 있던 HTTP 통신에서 기능을 '재사용'해서 데이터 송수신 규칙을 만든 것

    // CRUD

    // Create
    // POST
    // /api/ranking
    // → 아이템 생성 요청 (Body에 실제 정보 담아서 보냄)

    // Read
    // GET      
    // /api/ranking
    // → 모든 아이템 목록 요청
    // /api/ranking/1
    // → id 1번 아이템 요청

    // Update
    // PUT
    // /api/ranking (보안 문제로 웹에서는 사용하지 않음)
    // 아이템 갱신 요청 (Body에 실제 정보 담아서 보냄)

    // Delete
    // DELETE
    // /api/ranking/1 (보안 문제로 웹에서는 사용하지 않음)
    // → id 1번 아이템 삭제 요청
}

 

 REST는 Representational State Transfer의 약자로 공식 표준 스펙은 아니다. 원래 있던 HTTP 통신에서 기능을 '재사용'하여 데이터 송수신 규칙을 만든 것이다. 그렇다면 왜 HTTP 통신의 기능을 재사용하였을까? 이는 각 회사마다 데이터를 주고 받을 때의 로직을 자유롭게 만들었다가 만들고보니, 다른 회사와 협엽을 해야된다고 했을 때 우리가 만든 것과 협업하는 회사의 방식이 서로 다르면 적응하기가 굉장히 힘들기 때문이다. 따라서 이를 해결하기 위해 표준을 만든 것이 바로 REST이다.

 

 웹 서버는 CRUD가 굉장히 중요한데 REST는 이를 각각의 Create - POST, Read - GET, Update - PUT, Delte - DELETE를 통해 사용하고 있다. 따라서 Create는 REST로 이용할 때 POST 메서드를 사용한다. 이를 사용할 때에는 /api/ranking을 이용하고 주로 아이템을 생성 요청할 때 사용된다. 이 때 Body에 실제 정보를 담아서 보내어 처리한다.

 

 다음 Read는 REST를 이용할 때 GET 메서드를 사용한다. 이는 /api/ranking, /api/ranking/1과 같이 사용되는데 각각의 기능은 모든 아이템 목록 요청, 혹은 id가 1번인 아이템 요청과 같이 사용된다. Update는 REST를 이용할 때 PUT 메서드를 사용한다. 이는 /api/ranking으로 사용되지만 현재 보안 문제로 인해 웹에서 사용되지 않는다. 이는 아이템 갱신을 요청할 때 사용하며, POST와 같이 Body에 실제 정보를 담아서 보내준다. Delete는 REST를 이용할 때 DELETE 메서드를 사용한다. 이는 /api/ranking/1과 같이 사용되는데 이 또한 보안 문제로 웹에서는 사용되지 않으며, 이는 id 1번 아이템을 삭제할 때 요청한다.

 

 이제 이어서 랭킹 컨트롤러를 만들어보도록 하자. DB에서 데이터를 꺼내와야하므로 ApplicationDbContext에 접근할 수 있도록 의존성 주입을 처리한다.

 

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SharedData.Models;
using WebApi.Data;

namespace WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RankingController : ControllerBase
    {
        ApplicationDbContext _context;

        public RankingController(ApplicationDbContext context)
        {
            _context = context;
        }
    }
}

 

 이 후 생성자를 만들어주고, 본격적으로 CRUD를 만들어보도록 하자. 먼저 비교적 구현하기가 쉬운 READ를 먼저 구현하도록 하자. READ는 일전에 모든 값과, ID를 통한 값으로 나눈다고 하였으므로 2개의 함수를 구현하도록 하자.

 

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SharedData.Models;
using WebApi.Data;

namespace WebApi.Controllers
{
    // ApiController 특징
    // 1. 그냥 C# 객체를 반환해도 된다.
    // null을 반환하면 클라이언트에 204 Response (No Content)를 보낸다.
    // string → text/plain
    // 나머지(int, bool) → application/json

    [Route("api/[controller]")]
    [ApiController]
    public class RankingController : ControllerBase
    {
        ApplicationDbContext _context;

        public RankingController(ApplicationDbContext context)
        {
            _context = context;
        }

        // Read
        [HttpGet]
        public List<GameResult> GetGameResults()
        {
            List<GameResult> results = _context.GameResults
                .OrderByDescending(item => item.Score)
                .ToList();

            return results;
        }

        [HttpGet("{id}")]
        public GameResult GetGameResults(int id)
        {
            GameResult result = _context.GameResults
                .Where(item => item.Id == id)
                .FirstOrDefault();

            return result;
        }
    }
}

 

 위 함수는 모든 값을 반환하는 함수이며, 아래 함수는 id를 인자값으로 받아서 이를 반환하는 함수이다. 이 때 참고할 것이 있는데 API 컨트롤러의 특징은 그냥 C# 객체를 반환해도 되는 것이다. 예를들어 데이터가 존재하지 않아 null을 반환할 경우 클라이언트에 204 Response (데이터 없음)을 보내고, string 형태의 데이터는 text/plain 형태로, 그외 나머지 int와 bool의 형태일 경우에는 JSON 형태로 보내주는 것 또한 API 컨트롤러의 특징이다.

 

 따라서 굳이 포맷을 JSON으로 맞춰서 하는 것이 아니라, 리스트와 데이터 그 자체를 반환하더라도 자동으로 JOSN 형태로 반환이 처리되어 진행된다. 여기까지 진행했으면 이제 SQL 서버 개체 탐색기로 돌아가 GET을 통해 데이터 조회 전, 수동으로 데이터를 넣어주고 잘 작동하는지 확인하기 위해 테스트를 해보자.

 

수동으로 데이터 삽입

 

/api/ranking으로 페이지를 이동하니 DB 데이터 값이 JSON 형태로 보여진다.

 

 VS 2022에서는 별도의 작업을 해주어야하는 건지, 나같은 경우 프로그램을 실행 후 localhost의 /api/ranking으로 이동해도 데이터가 보이지 않아 루키스님의 작업을 캡처해서 표시했다. 가만보면 JOSN 형태로 데이터가 보이는데, 실질적으로 이렇게 보일거면 굳이 왜 JSON으로 보내는지 의아하므로 클라이언트 사이드에서도 데이터를 볼 수 있도록 'Postman' 툴을 설치하여 이를 확인해보자.

 

 

 Postman을 설치하고 로그인 한 후에 새로운 탭을 열고, GET 메서드를 선택한다. 이 후 웹 페이지에 나타났던 URL 주소를 입력한 후에 Send 버튼을 누를 경우 우리가 수동으로 넣어주었던 DB 데이터가 JSON 형태로 보이는 것을 확인할 수 있다. 이 데이터를 이제 파싱을 통해 클라이언트인 유니티에서 작업을 처리하면 된다. 

 

 

반응형