Cheondi
개발 · API

Unity 화면에 API를 붙이면 끝인 줄 알았다

Unity에서 API 응답을 화면 상태로 연결하며 요청 이후의 흐름을 처음 제대로 따라가 본 기록입니다.

  • #unity
  • #api
  • #data-flow

회사 코드가 조금 익숙해질 무렵 Unity 화면에 서버 데이터를 연결하는 일을 맡았다. 처음에는 버튼을 누르면 요청하고 응답을 텍스트에 넣으면 끝이라고 생각했다. 막상 해보니 요청을 보내는 부분은 전체 작업의 시작에 가까웠다. 서버에서는 값이 왔는데 화면이 그대로이거나, 다른 탭으로 이동한 뒤 늦게 도착한 응답이 이전 화면을 다시 바꾸기도 했다.

문제가 API인지 Unity인지 구분하는 것부터 어려웠다. 그래서 주소, 응답 변환, 화면 갱신을 한꺼번에 보지 않고 경계를 나눠 확인하기 시작했다.

요청이 성공했다는 것과 화면이 유효하다는 건 달랐다

예를 들어 목록 API가 정상적으로 200을 반환해도 사용자가 이미 화면을 닫았을 수 있다. 요청 당시 선택한 계좌와 응답 시점의 계좌가 다를 수도 있었다. 응답 성공만 확인하고 바로 UI를 바꾸면 오래된 결과가 최신 화면을 덮었다.

int requestedAccountId = selectedAccountId;
var response = await api.GetAsync($"https://api.example.com/accounts/{requestedAccountId}/orders");

if (!isActiveAndEnabled || requestedAccountId != selectedAccountId)
    return;

Render(response.items);

실제 코드의 취소 방식은 달랐지만, 응답을 적용하기 전에 지금도 같은 화면과 조건인지 확인해야 한다는 의미였다.

서버 응답을 바로 UI에 넣지 않았다

응답 필드 이름과 화면에서 필요한 값은 꼭 같지 않았다. 금액은 자릿수 규칙이 필요했고 null이나 빈 배열은 별도 상태로 보여야 했다. API 모델을 곧바로 Text 컴포넌트에 흩어 넣으면 같은 가공 코드가 여러 화면에 생겼다.

OrderRow ToRow(OrderDto dto)
{
    return new OrderRow(
        dto.symbol ?? "-",
        FormatAmount(dto.amount),
        ParseServerTime(dto.createdAt));
}

화면은 표시용 모델만 받아 그리는 쪽으로 읽으니 데이터 변환과 UI 문제를 따로 볼 수 있었다.

성공, 빈 결과, 실패를 나눴다

처음에는 목록이 없을 때도 실패처럼 보였고, 요청이 실패했을 때는 이전 목록이 남아 있었다. 로딩 중, 성공 목록, 정상적인 빈 결과, 재시도 가능한 오류를 각각 상태로 두니 화면 조건이 훨씬 분명해졌다.

Loading -> Success(items)
        -> Empty
        -> Error(message, retry)

로그도 요청 URL만 남기지 않고 요청 식별값, 선택 조건, 응답 개수, 화면 적용 여부를 함께 봤다. 실제 도메인과 계정 값은 기록에 남기지 않고 재현에 필요한 문맥만 사용했다.

API 연결은 경계를 잇는 작업이었다

처음에는 서버 데이터가 도착하면 일이 끝난다고 생각했다. 실제로는 외부 응답을 앱이 이해하는 데이터로 바꾸고, 현재 화면에 적용해도 되는지 확인하고, 사용자에게 상태를 설명하는 과정까지 포함됐다.

이 작업 이후 API 관련 문제를 볼 때 주소부터 고치려 하지 않는다. 누가 요청했고 어떤 조건으로 기다렸는지, 응답이 어디에서 변환되고 어느 시점에 화면에 들어가는지를 순서대로 본다. 아직 기존 구조를 따라가며 배운 단계였지만 화면 밖의 데이터 흐름을 보기 시작한 중요한 경험이었다.