개발노트

2. [ASP .NET Core] 간단 API 만들기(with Dapper) 본문

서버 개발/ASP .NET Core

2. [ASP .NET Core] 간단 API 만들기(with Dapper)

mroh1226 2024. 11. 10. 18:48
반응형

ASP .NET Core를 사용하여 RESTful API를 구축하고, Dapper를 사용한 SQL Server와의 데이터베이
이 API는 사용자를 생성, 조회, 수정, 삭제하는 기능을 제공합니다.
 

목표:

  • C#과 .NET을 사용하여 서버를 구축
  • Dapper를 활용한 데이터베이스 접근 (SQL Server와 연결)
  • RESTful API로 CRUD 작업을 제공하는 Users 관리 시스템 구축

주요 컴포넌트:

  1. Controller:
    • 사용자 관리 API (CRUD 작업)
    • UsersController에서 HTTP 요청을 받아 사용자 데이터를 처리하고 반환
  2. Repository:
    • Dapper를 사용하여 SQL Server에서 데이터를 조회하고 관리
    • 비동기 방식으로 데이터베이스와 통신하여 효율적으로 처리
  3. Model:
    • Users 모델을 사용하여 사용자 정보를 정의

작업 흐름:

  1. Users API:
    • POST /api/users: 새로운 사용자 생성
    • GET /api/users: 모든 사용자 조회
    • GET /api/users/{id}: 특정 사용자 조회
    • PUT /api/users/{id}: 사용자 정보 수정
    • DELETE /api/users/{id}: 사용자 삭제

서버 구성 흐름:

  1. 클라이언트가 /api/users로 HTTP 요청을 보냄
  2. UsersController가 요청을 받고, UsersRepository를 통해 데이터를 처리
  3. 클라이언트는 요청한 데이터를 받음 (JSON 형식으로 응답)

 


DB 쪽

CREATE PROCEDURE [dbo].[uSP_FindById]	
	@id int
AS
BEGIN
	SET NOCOUNT ON;
    
	SELECT * From users where id = @id
    
END
GO

SP 하나만들고 시작,
 
우선 폴더 구조를 먼저 만들어본다.

1. API 프로젝트 구조 설정

첫 번째로, 서버 프로젝트의 구조를 정의하는 것이 필요합니다. 일반적으로 API 프로젝트는 다음과 같은 기본적인 폴더 구조를 갖습니다:

  1. Controllers - API 엔드포인트를 정의하는 컨트롤러들을 저장합니다.
  2. Models - 데이터 모델을 정의하는 클래스들을 저장합니다.
  3. Repositories - 데이터베이스와의 연결 및 데이터를 처리하는 로직을 담당합니다.
  4. Startup.cs 또는 Program.cs - 서버 설정 및 의존성 주입 설정.
src/
│
├── Controllers/
│   └── UsersController.cs
├── Models/
│   └── Users.cs
├── Repositories/
│   └── UsersRepository.cs
└── Program.cs

 

appsettings.json
{
  // 로깅 관련 설정
  "Logging": {
    "LogLevel": {
      // 기본 로그 레벨을 'Information'으로 설정합니다.
      // 'Information'은 일반적인 동작이나 상태 변경을 나타내는 로그 레벨입니다.
      "Default": "Information",

      // Microsoft.AspNetCore 네임스페이스에 대한 로그 레벨을 'Warning'으로 설정합니다.
      // 'Warning'은 경고나 문제를 나타내며, 심각한 오류는 포함되지 않습니다.
      "Microsoft.AspNetCore": "Warning"
    }
  },


  "ConnectionStrings": {
    "DefaultConnection": "Server=DESKTOP-9JSRCEU;Database=sunppy;Trusted_Connection=True;"
  },

  // 허용된 호스트를 설정합니다.
  // '*'는 모든 호스트를 허용하는 설정입니다.
  // 이를 통해 어떤 호스트에서든 애플리케이션에 접근할 수 있게 됩니다.
  "AllowedHosts": "*"
}
Program.cs
using Sunppy.Repositories;

var builder = WebApplication.CreateBuilder(args);

// 서비스 컨테이너에 서비스를 추가합니다.
builder.Services.AddControllers();

// Swagger/OpenAPI 관련 설정을 추가합니다.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// UsersRepository를 서비스에 등록하여 의존성 주입을 사용합니다.
builder.Services.AddScoped<UsersRepository>();

var app = builder.Build();

// HTTP 요청 파이프라인을 구성합니다.
if (app.Environment.IsDevelopment())
{
    // Swagger 미들웨어를 등록하여 Swagger UI를 활성화합니다.
    app.UseSwagger();
    app.UseSwaggerUI();
}

// 모든 HTTP 요청에 대해 HTTPS로 리디렉션합니다. (보안 설정)
app.UseHttpsRedirection();

// Authorization 미들웨어를 사용하여 인증된 요청만 허용합니다.
app.UseAuthorization();

// API 컨트롤러를 엔드포인트에 매핑합니다.
app.MapControllers();

// 애플리케이션을 실행합니다.
app.Run();

2. 사용자 모델 (Users)

먼저 Users 모델을 정의해야 합니다. Models 폴더에 Users.cs 파일을 생성하고, 해당 테이블 구조에 맞는 클래스를 작성합니다.

namespace Sunppy.Models
{
    public class Users
    {
        public int id { get; set; }  // ID는 기본 키 (PK)
        public string name { get; set; }
        public int age { get; set; }
        public string mbti { get; set; }
    }
}

 

3. 데이터베이스 연결 설정 (Repository)

Repositories 폴더에 UsersRepository.cs를 만들고, Dapper를 사용하여 데이터베이스에서 데이터를 조회하는 메서드를 작성합니다.

UsersRepository.cs
using Dapper;
using Microsoft.Extensions.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Collections.Generic;
using Sunppy.Models;

namespace Sunppy.Repositories
{
    public class UsersRepository
    {
        private readonly string _connectionString;

        public UsersRepository(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("DefaultConnection");
        }

        // 모든 사용자 목록을 비동기적으로 가져오는 메서드
        public async Task<IEnumerable<Users>> GetUsersAsync()
        {
            using (IDbConnection db = new SqlConnection(_connectionString))
            {
                string sql = "SELECT * FROM users"; // users 테이블에서 모든 데이터 조회
                return await db.QueryAsync<Users>(sql); // Dapper를 이용해 쿼리 실행
            }
        }

        // ID로 특정 사용자를 조회하는 메서드
        public async Task<Users> GetUserByIdAsync(int id)
        {
            using (IDbConnection db = new SqlConnection(_connectionString))
            {
                string sql = "SELECT * FROM users WHERE id = @Id"; // 주어진 ID에 해당하는 사용자 조회
                return await db.QuerySingleOrDefaultAsync<Users>(sql, new { Id = id });
            }
        }

        // 새 사용자 추가
        public async Task<Users> CreateUserAsync(Users user)
        {
            using (IDbConnection db = new SqlConnection(_connectionString))
            {
                string sql = "INSERT INTO users (name, age, mbti) VALUES (@Name, @Age, @Mbti); SELECT CAST(SCOPE_IDENTITY() as int)";
                var id = await db.QuerySingleAsync<int>(sql, user);
                user.id = id; // 생성된 ID를 Users 객체에 추가
                return user;
            }
        }

        // 사용자 정보 업데이트
        public async Task<Users> UpdateUserAsync(Users user)
        {
            using (IDbConnection db = new SqlConnection(_connectionString))
            {
                string sql = "UPDATE users SET name = @Name, age = @Age, mbti = @Mbti WHERE id = @Id";
                var rowsAffected = await db.ExecuteAsync(sql, user);
                return rowsAffected > 0 ? user : null; // 업데이트 성공 시 사용자 반환, 실패 시 null
            }
        }

        // 사용자 삭제
        public async Task DeleteUserAsync(int id)
        {
            using (IDbConnection db = new SqlConnection(_connectionString))
            {
                string sql = "DELETE FROM users WHERE id = @Id";
                await db.ExecuteAsync(sql, new { Id = id });
            }
        }
        // Stored Procedure 호출 메서드
        public async Task<Users> GetUserByIdUsingStoredProcedureAsync(int id)
        {
            using (IDbConnection dbConnection = new SqlConnection(_connectionString))
            {
                // SP 호출
                var parameters = new { id }; // 파라미터 객체 생성
                var user = await dbConnection.QueryFirstOrDefaultAsync<Users>(
                    "[dbo].[uSP_FindById]",   // SP 이름
                    parameters,               // 파라미터 전달
                    commandType: CommandType.StoredProcedure // Stored Procedure임을 명시
                );

                return user; // 결과 반환
            }
        }
    }
}

 

4. 컨트롤러 (UsersController)

Controllers 폴더에 UsersController.cs를 만들고, HTTP 요청을 처리하는 엔드포인트들을 작성합니다. 각 메서드는 UsersRepository에서 제공하는 메서드를 호출하여 비즈니스 로직을 처리합니다.

UsersController.cs
using Microsoft.AspNetCore.Mvc;
using Sunppy.Models;
using Sunppy.Repositories;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Sunppy.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UsersController : ControllerBase
    {
        private readonly UsersRepository _usersRepository;

        public UsersController(UsersRepository usersRepository)
        {
            _usersRepository = usersRepository;
        }

        // GET api/users : 모든 사용자 목록 조회
        [HttpGet]
        public async Task<IEnumerable<Users>> GetUsers()
        {
            return await _usersRepository.GetUsersAsync();
        }

        // GET api/users/{id} : 특정 사용자 조회
        [HttpGet("{id}")]
        public async Task<ActionResult<Users>> GetUser(int id)
        {
            var user = await _usersRepository.GetUserByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }
            return Ok(user);
        }

        // GET api/users/sp/{id} : 스토어드 프로시저를 사용하여 특정 사용자 데이터를 조회합니다.
        [HttpGet("sp/{id}")]
        public async Task<ActionResult<Users>> GetUserByIdSP(int id)
        {
            // UsersRepository에서 제공하는 GetUserByIdUsingStoredProcedureAsync 메소드 호출
            var user = await _usersRepository.GetUserByIdUsingStoredProcedureAsync(id);

            // 사용자가 없으면 404 Not Found 반환
            if (user == null)
            {
                return NotFound();
            }

            // 사용자 정보를 정상적으로 반환
            return Ok(user);
        }

        // POST api/users : 새로운 사용자 생성
        [HttpPost]
        public async Task<ActionResult<Users>> CreateUser(Users user)
        {
            var createdUser = await _usersRepository.CreateUserAsync(user);
            return CreatedAtAction(nameof(GetUser), new { id = createdUser.id }, createdUser);
        }

        // PUT api/users/{id} : 사용자 정보 업데이트
        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateUser(int id, Users user)
        {
            if (id != user.id)
            {
                return BadRequest("User ID mismatch");
            }

            var updatedUser = await _usersRepository.UpdateUserAsync(user);
            if (updatedUser == null)
            {
                return NotFound();
            }

            return NoContent();
        }

        // DELETE api/users/{id} : 사용자 삭제
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteUser(int id)
        {
            var user = await _usersRepository.GetUserByIdAsync(id);
            if (user == null)
            {
                return NotFound();
            }

            await _usersRepository.DeleteUserAsync(id);
            return NoContent();
        }
    }
}

 
 

반응형
Comments