[RestSharp 실전 시리즈] 1편. 기본 설정 · GET 요청 · 서버 응답 구조
실무형 RestSharp API 통신 패턴 정리
시리즈 전체 목차
1편. RestSharp 기본 설정 · GET 요청 · 서버 응답 구조 ← 현재 글
2편. POST · PUT · DELETE와 JWT 인증
3편. 에러 처리와 그리드 CRUD 저장 패턴
1. 소개
.NET WinForms나 콘솔 앱에서 REST API를 호출해야 할 때, HttpClient를 날것으로 쓰면 생각보다 코드가 꽤 길어져요. 요청 직렬화, 헤더 세팅, 응답 역직렬화... 매번 같은 보일러플레이트를 반복하다 보면 슬슬 귀찮아지죠.
RestSharp은 이 번거로움을 줄여주는 .NET용 REST 클라이언트 라이브러리예요. 쿼리 파라미터 조립, JSON Body 전송, 헤더 관리 등을 훨씬 간결하게 처리할 수 있어서 실무에서 많이 쓰여요.
이 시리즈에서는 실제 업무용 데스크탑 앱에서 사용 중인 패턴을 기반으로, "바로 가져다 쓸 수 있는" 수준의 코드를 공유할게요.
- 환경: .NET Framework 4.7.2 / RestSharp 110.x / Newtonsoft.Json
- 예제 도메인: 상품 관리 시스템 (상품 목록 조회, 등록, 수정, 삭제)
2. 기본 사용 방법
설치
Install-Package RestSharp
Install-Package Newtonsoft.Json
RestClient와 RestRequest
RestSharp의 핵심은 두 객체예요.
RestClient client = new RestClient("https://api.example.com");
RestRequest req = new RestRequest("/products", Method.Get);
RestResponse response = client.Execute(req);
| 클래스 | 역할 |
|---|---|
RestClient |
HTTP 연결 담당. 베이스 URL, 타임아웃 등 연결 설정 |
RestRequest |
개별 요청 담당. 엔드포인트, 메서드, 파라미터, Body, 헤더 |
그러니까 RestClient는 한 번 만들어두고 재사용하는 연결 설정이고, RestRequest는 요청마다 새로 만드는 개별 요청이에요.
3. 실무 적용 방법
서버 응답 구조 먼저 이해하기
실무에서는 API 응답을 공통 envelope 구조로 감싸는 경우가 많아요. 클라이언트 코드가 왜 그렇게 작성됐는지 이해하려면 이 구조를 먼저 알아야 해요.
{
"scs": true,
"code": "0",
"msg": "처리되었습니다.",
"data": { ... },
"list": [ ... ]
}
| 필드 | 타입 | 설명 |
|---|---|---|
scs |
bool | 비즈니스 성공 여부 — HTTP 200이어도 false일 수 있어요 |
code |
string | 결과 코드 (에러 시 ERR_AUTH 같은 식별 코드) |
msg |
string | 사용자에게 보여줄 메시지 |
data |
object | 단일 레코드 반환 시 사용 |
list |
array | 목록 반환 시 사용 |
HTTP 200을 받았다고 성공한 게 아니에요.
scs필드를 반드시 확인해야 진짜 성공 여부를 알 수 있어요. 이게 이 시리즈 전체에서 가장 중요한 포인트예요.
GET 요청 — 목록 조회
상품 목록을 조회하는 전체 흐름이에요.
private void SearchProducts()
{
RestClient client = new RestClient("https://api.example.com");
RestRequest req = new RestRequest("/products", Method.Get);
// 쿼리 파라미터 추가 → /products?name=노트북&category=전자 형태로 자동 조립
req.AddParameter("name", txtSearchName.Text);
req.AddParameter("category", cboCategory.SelectedValue.ToString());
RestResponse response = client.Execute(req);
if (response.IsSuccessful)
{
JObject jObject = JObject.Parse(response.Content);
if ((bool)jObject["scs"])
{
DataTable dt = (DataTable)JsonConvert.DeserializeObject(
jObject["list"].ToString(), typeof(DataTable));
dt.AcceptChanges(); // 반드시 호출! (이유는 주의사항 섹션에서 설명)
gridProduct.DataSource = dt;
}
else
{
MessageBox.Show(jObject["msg"].ToString());
}
}
}
AddParameter()를 쓰면 URL 쿼리 스트링을 직접 조립할 필요가 없어요. 파라미터만 추가하면 GET 요청에서 자동으로 붙어요.
GET 요청 — 단일 레코드 조회
그리드에서 특정 행을 선택했을 때 상세 정보를 가져오는 패턴이에요.
private void LoadProductDetail(long productId)
{
RestClient client = new RestClient("https://api.example.com");
RestRequest req = new RestRequest("/products/" + productId, Method.Get);
RestResponse response = client.Execute(req);
if (response.IsSuccessful)
{
JObject jObject = JObject.Parse(response.Content);
if ((bool)jObject["scs"])
{
// data 필드를 DTO로 역직렬화
ProductDto dto = JsonConvert.DeserializeObject<ProductDto>(
jObject["data"].ToString());
txtName.Text = dto.name;
txtPrice.Text = dto.price.ToString();
}
}
}
DTO는 JSON 필드명과 프로퍼티명을 일치시켜야 역직렬화가 자동으로 돼요.
public class ProductDto
{
public long productId { get; set; }
public string name { get; set; }
public int price { get; set; }
public string category { get; set; }
}
4. 주의사항
주의 1 — IsSuccessful만 믿으면 안 되는 경우가 있어요
response.IsSuccessful은 HTTP 상태 코드만 확인하는 게 아니에요.
// RestSharp 내부 구현
public bool IsSuccessful =>
(int)StatusCode >= 200 && (int)StatusCode <= 299
&& ResponseStatus == ResponseStatus.Completed;
ResponseStatus.Completed까지 확인하는 게 포인트예요. 타임아웃이나 네트워크 오류가 나면 HTTP 상태 코드 자체가 없는 상태(TimedOut, Error)가 되거든요. 상태 코드만 체크하면 이런 케이스를 그냥 통과시킬 수 있어요.
그래서 커스텀 확장 메서드를 만들어 두고 쓰는 방식이 더 안전해요.
public static class RestSharpExtensions
{
public static bool IsSuccessful(RestResponse response)
{
return (int)response.StatusCode >= 200
&& (int)response.StatusCode <= 399
&& response.ResponseStatus == ResponseStatus.Completed;
}
}
200~299만 성공으로 볼지, 리다이렉트(3xx)도 포함할지는 서버 설계에 맞게 기준을 정하면 돼요.
주의 2 — AcceptChanges() 빠뜨리면 저장 로직이 망가져요
이걸 모르면 나중에 진짜 당황하게 돼요.
JSON을 DataTable로 역직렬화하면 모든 행의 RowState가 Added 상태예요. 그리드에 바인딩하고 사용자가 아무것도 건드리지 않아도 "신규 추가된 행"으로 인식되는 거예요.
역직렬화 직후: 모든 행 → RowState = Added
AcceptChanges(): 모든 행 → RowState = Unchanged ← 이 상태가 되어야 정상
사용자 수정 후: 수정된 행 → RowState = Modified
3편에서 변경된 행만 골라서 저장하는 패턴을 다루는데, AcceptChanges()를 빠뜨리면 그 패턴 전체가 오동작해요.
DataTable dt = (DataTable)JsonConvert.DeserializeObject(
jObject["list"].ToString(), typeof(DataTable));
dt.AcceptChanges(); // 이 한 줄이 없으면 나중에 저장할 때 전부 Insert로 들어가요
gridProduct.DataSource = dt;
5. 성능 / 구조 팁
서버 URL은 중앙에서 관리하세요
API URL을 각 폼마다 하드코딩하면 서버 주소가 바뀔 때 전부 찾아서 고쳐야 해요. 환경 설정 파일이나 전역 상수에서 읽어오는 방식을 쓰는 게 훨씬 나아요.
; 설정 파일 (app.ini 또는 appsettings.json)
[SERVER]
URL=https://api.example.com/
// 전역에서 읽어서 사용
string baseUrl = ConfigManager.GetServerUrl(); // "https://api.example.com/"
RestClient client = new RestClient(baseUrl);
RestRequest req = new RestRequest("products", Method.Get);
타임아웃은 케이스별로 따로 설정하세요
대용량 조회나 배치 처리처럼 오래 걸릴 수 있는 요청에만 타임아웃을 늘려줘요. 전체에 길게 잡으면 진짜 오류가 났을 때 사용자가 너무 오래 기다리게 돼요.
// 일반 요청: 기본 타임아웃 사용
RestClient client = new RestClient("https://api.example.com");
// 오래 걸리는 요청: 개별로 설정
RestClientOptions options = new RestClientOptions("https://api.example.com")
{
MaxTimeout = 2 * 60 * 1000 // 2분 (밀리초 단위)
};
RestClient clientLong = new RestClient(options);
RestClient 인스턴스 전략
웹 앱이라면 RestClient(내부적으로 HttpClient 기반)를 싱글톤으로 유지하는 게 맞아요. 계속 새로 생성하면 소켓 고갈(Socket Exhaustion) 문제가 생길 수 있거든요.
반면 WinForms 데스크탑 앱처럼 동시 요청 수가 적고 각 폼이 독립적으로 동작하는 경우라면 요청마다 새로 생성해도 실용적으로는 문제없어요. 단, 성능이 중요한 상황이라면 재사용을 고려하는 게 좋아요.
6. 정리
AddParameter()를 쓰면 쿼리 스트링을 직접 조립하지 않아도 돼요- 서버 응답은 HTTP 성공 +
scs필드, 두 단계로 확인해야 해요 response.IsSuccessful은 HTTP 상태 코드와ResponseStatus.Completed를 함께 체크해요DataTable로 역직렬화 후 반드시AcceptChanges()호출해요 — 나중에 저장 로직의 기반이 돼요- 서버 URL은 설정 파일에서 중앙 관리, 타임아웃은 케이스별로 개별 설정
다음 편 예고
2편에서는 본격적으로 데이터를 쓰는 작업을 다뤄요. JWT 토큰을 발급받아서 모든 요청에 인증 헤더로 붙이는 방법, 그리고 POST · PUT · DELETE 각각의 패턴과 실무에서 자주 쓰이는 등록/수정 통합 Save 패턴까지 정리할게요.
시리즈 전체 목차
1편. RestSharp 기본 설정 · GET 요청 · 서버 응답 구조 ← 현재 글
2편. POST · PUT · DELETE와 JWT 인증
3편. 에러 처리와 그리드 CRUD 저장 패턴
'Backend > C#' 카테고리의 다른 글
| [RestSharp 실전 시리즈] 2편. POST · PUT · DELETE와 JWT 인증 (0) | 2026.06.07 |
|---|---|
| DevExpress XtraGrid - 엔터 키로 다음 셀 이동하기 (0) | 2026.05.21 |