골치아픈 REST API에서 벗어나 효율적인 모바일 네트워크를 구성하는 방법

REST 혹은 RESTful API는 최근 웹에서 높은 비중을 차지하고 있습니다. RESTful API는 일관적인 HTTP 언어를 사용해서 엔티티 읽기, 업데이트, 삭제 등 서버와의 상호 작용을 표현합니다.

REST API의 장점

HTTP에서 사용하는 동사, GET, POST, PUT, DELETE는 서버가 하는 일을 대부분 설명할 수 있습니다. 서버에서부터 데이터를 가져와서 일부를 업데이트하는 기본 데이터 중심 API의 경우에는 이로써 충분할 겁니다.

만약 데이터를 쿼리하기 위한 단순한 API를 사용하고 비즈니스 로직이 없다면 엔티티를 직접 작업해도 됩니다. 많은 공개적인 API가 이 기능을 제공하며, 고객이 어떤 비즈니스 로직을 구현하는지는 상관하지 않습니다.

예를 들어 사용자에게 “지금 내 주변”의 정보를 제공하는 모바일 앱은 여러 서버에 여러 번 REST 호출을 할 수 있습니다. 현재 위치를 통해 현재 날짜를 한 서버에서 가져오고, 뉴스 아이템 리스트를 다른 서버에서, 가까운 음식점을 또 다른 서버에서 가져올 수도 있죠. 마지막으로 이런 정보를 함께 묶어 사용자에게 보여줄 겁니다.

An app might make REST calls to several servers

위 예제에서는 앱이 두뇌의 역할을 맡고, API는 단순히 데이터를 제공할 뿐입니다. 하지만 앱과 독립적으로 서버에서 비즈니스 로직을 제공하는 형태의 모바일 앱이라면 CRUD 측면에서 둘 사이의 통신이 문제가 될 수 있습니다.

RESTful API를 통해 서버와 통신하는 동안 발생할 수 있는 문제점을 간략하게 살펴 볼까요?

RESTful API의 문제점

REST는 그 단순성과 유연성뿐만 아니라 인기 높은 HTTP 프로토콜을 기본 언어로 사용하기 때문에 널리 사용되고 있습니다. 하지만 동시에 이런 이유 때문에 RESTful API를 설계하고 구현해서 사용하기가 어렵기도 합니다.

스키마나 타입 유효성의 부재

각 RESTful API가 작동하는 엔티티에 따라 설계되므로, 유효성을 검증하는 스키마나 예상되는 데이터 유형이 없고 두 통신 주체 간에 규약을 작성하는 다른 방법을 제공할 수 있는 일반적인 방법도 없습니다.

이런 개발 뉴스를 더 만나보세요

예를 들어 서버에 사용 가능한 모든 계정(GET /accounts)을 요청할 수는 있지만, 이런 엔드포인트가 있으라는 보장은 없습니다. 예전 API 버전에는 있었지만 현재 버전에는 없는 경우도 있죠.

서버에서 모든 계정을 가져왔다면, GET /accounts/145와 같은 형태로 특정 계정의 상세 정보를 읽을 차례겠죠? 이런 항목이 있을까요? 네, GET /accounts 호출이 145라는 id를 돌려줄 수도 있겠죠. 하지만 이 엔티티가 아직 존재하는 걸까요? 상황에 따라 다를 겁니다. 계정 목록을 요청한 이후에 다른 클라이언트가 이를 수정하거나 서버에서 삭제할 수도 있으니까요.

이제 스키마가 부족해서 발생할 수 있는 다른 문제점을 더 살펴보겠습니다. 데이터의 타입이 따로 없다는 것이죠. 개별 엔드포인트는 데이터 모델의 관계 덕분에 동일한 데이터를 반환할 수 있지만, 해당 엔드포인트를 구현한 사람이 누구인지에 따라 응답에서 작은 차이가 생길 수 있습니다.

The same data can be sent as different data types

위 두 응답의 차이점은 ‘amount’가 한 곳에서는 문자열이고 다른 곳에서는 숫자라는 것인데, 이런 차이 때문에 모바일 앱이 작동을 멈출 수도 있습니다.

진행 중인 데이터 변환

복잡한 모바일 애플리케이션에서 데이터 타입을 처리해야 하는 작업은 성가실 뿐만 아니라 버그의 원인이 됩니다. RESTful API로 통신하기 위해서는 다음과 같은 설정이 필요합니다.

Transforming your data multiple times to work with REST APIs

이렇게 네트워크를 통해 전송되는 데이터는 여러 변형을 거칩니다.

  1. 네이티브 데이터 모델 정의
    • 네이티브 코드로 데이터 모델을 정의합니다.
  2. 데이터를 JSON으로 시리얼라이즈
    • 문자열, 숫자, 리스트, 딕셔너리 등만을 사용해서 네이티브 객체들을 JSON에 호환되는 표현으로 변환합니다.
    • 네이티브 데이터 엔티티를 REST 엔드포인트가 요구하는 구조로 바꿔줍니다.
  3. HTTP를 통해 전송
    • 데이터를 JSON 문자열로 인코딩하고 이 JSON 문자열을 multipart HTTP 형태 데이터로 인코딩해서 POST 요청을 보냅니다.
  4. 서버에서 데이터를 디코딩
    • POST 데이터를 디코딩한 뒤, JSON 문자열을 디코딩합니다.
  5. SQL 데이터베이스에 데이터를 저장합니다.
    • 요청 아이템을 Cherry-pick하고 서버 저장소에 매핑되는 객체를 생성합니다.
    • 가시 객체를 SQL 데이터베이스에 저장할 수 있는 데이터를 변환합니다.

네트워크를 통해 전송하는 데이터는 형식과 사용 가능한 데이터 타입이 여러 번 변경됨에 따라 지속해서 변형됩니다. 그리고 이런 변환이 스키마 또는 규약이 부족한 경우와 합해지면 요청이나 응답에 상대편이 기대하지 않았거나, 검증할 수 없거나 이해할 수 없는 데이터가 포함될 수 있습니다.

전송 측면에서 비즈니스 로직 래핑하기

마지막으로 반복적으로 데이터를 변환하고 코드를 변환하는 과정뿐만 아니라, 실제로 원하는 것을 설명하기 위해 언어를 변경해야 합니다.

Your APIs, constrained to REST capabilities

앱의 코드에서는 앱의 비즈니스 도메인 언어를 사용합니다. 이는 제품의 목표에 맞출 수 있고, 구현하고 있는 비즈니스 로직을 구체적으로 처리하도록 설계된 다양한 표현식 API이죠. 사용 중인 프로그래밍 언어의 최신 기능을 사용하도록 앱의 API를 설계한다면 모델을 가장 잘 설명하는 방향으로 데이터 엔티티를 설계할 수 있습니다.

이 잘 설계된 시스템을 갖춘 이후, 다시 CRUD 작업 집합으로 표현할 수 있도록 모든 것을 다시 사용해야만 합니다. 요구사항을 가장 잘 표현할 수 있도록 사용자가 설계한 데이터 엔티티를 가지고 다시 쪼개서 JSON 구조를 만들어야 하죠.

이에 따라 잘 만들어둔 API의 표현력과 모델의 풍부함을 잃고, 단지 RESTful API의 단순성과 유연성만을 중심으로 비즈니스 로직을 래핑하게 됩니다.

항상 실패 가능성이 있는 네트워크 요청

The many, many ways REST APIs can fail

네트워크 요청은 연결이 일시적으로 끊어지거나 웹 서버에서 문제가 발생하거나 서버 애플리케이션에서 오류가 발생한다거나 하는 여러 가지 이유로 실패할 수 있습니다.

모바일 앱 단과 서버 단에서 모두 완벽한 통신 로직 코드를 구현하려면 모든 에러 핸들링을 직접 처리해야만 합니다. 데이터를 보내고 받는 것은 단지 빙산의 일각에 불과하죠. 견고한 API를 만들려면 해야 할 일이 아주 많습니다.

언뜻 보면 위의 흐름은 그다지 복잡해 보이지 않을지도 모릅니다. 제한된 수의 실패 지점이 있는 것처럼 보이죠. 하지만 RESTful API를 사용하면 여러 번의 종속적인 요청을 연이어서 필요한 만큼 계속 만들어야 합니다. 처음 요청이 엔티티를 만들어서 응답으로 가져오면, 다음 요청이 이 데이터를 사용하는 식으로 계속됩니다.

이제 모든 종속 요청을 위한 빙산의 모든 부분을 다 더하면 얼마나 복잡한지 보고, 연이은 요청의 맨 마지막 요청이 실패하는 상황을 고려해 보겠습니다.

회복하려면 어떤 전략을 사용해야 할까요?

  • 마지막 요청이 성공할 때까지 계속 시도할까요?
  • 실패를 무시할까요?
  • 이전의 요청 중 성공한 것으로 롤백할까요?

아쉽게도 RESTful API에는 단일 에러 전략이 없습니다. 그렇기 때문에 RESTful API를 사용해서 모바일 앱을 프로토타이핑하는 것은 간단하지만, 출시할 수 있는 품질의 제품을 만드는 작업이 까다롭습니다.

RESTful API로 모든 것이 손실됐다면?

REST는 모바일 앱과 서버 간의 통신 방법이므로 서버와 모바일 앱 양측 모두에서 위 문제에 대한 솔루션이 많이 구현돼 있습니다.

마이크로 서비스나 데이터 기반 API는 REST를 통해 뛰어난 자동화 기능을 제공하므로 데이터 변환, 발견 가능성 등과 같이 반복적인 작업을 구현하는 부담을 줄여줍니다.

트랜잭션을 래핑하기 위해 잘 설계된 엔드포인트는 단일한 액션을 위해 많은 수의 요청을 해야하는 것과 같은 문제를 푸는 데 도움이 됩니다. 또한 GET 매개 변수를 추가하거나 POST JSON 페이로드를 커스텀하는 등 REST 요청을 보다 지능적으로 만든 작업들이 있습니다.

하지만 여전히 많은 이슈들이 남아있고 “어쩔 수 없는 위험 요소”로 간주되고 있습니다.

  • 응답의 구조와 유형을 검증해야 합니다.
  • 서버로 데이터를 보내기 위해 여러번 변형해야 합니다.
  • CRUD 작업 측면에서 비즈니스 로직을 표현해야 합니다.
  • 마지막으로 네트워킹은 비동기식이어야 하므로 오류가 발생하기 쉽습니다.

완벽한 세상은 어떤 모습일까요? 👼

잠깐 숨을 돌리고 무엇이든 가능한 세상을 한번 생각해 봅시다. 이런 세상에서 앱은 어떤 모습일까요?

데이터를 액세스하고 수정하는 동일한 구조와 방법으로 각 장치 간에 동일한 데이터 엔티티를 공유할 수 있을 겁니다. 항상 최신이고 연결된 모든 장치에서 완벽한 단일 데이터를 나타낼 수 있겠죠.

물론 Swift, Java 혹은 다른 언어이든 원하는 언어를 쓸 수도 있을 겁니다. 모든 비즈니스 로직을 해당 언어로 구현하고, 해당 언어의 기능을 사용해서 API를 디자인하고, 데이터를 전송하는데 괴로워하는 악순환에서 자유로워져서 사용자를 행복하게 하는 데 집중할 수 있을 테죠.

마지막으로, 네트워크 레이어와 모델에서 절대로 에러가 나지 않을 겁니다. “데이터를 저장할 수 없습니다”라던가 “다른 유형이 필요합니다”라던가 하는 에러는 영영 사라질 테죠. 단지 로직을 구현하고 성능과 전체 제품의 안정성을 향상하는 데 집중하기만 하면 될 겁니다.

Realm 모바일 플랫폼

The Realm Platform

Realm 모바일 플랫폼은 현재 API가 가지고 있는 많은 문제점을 해결하려고 노력하고 있습니다.

우선 Realm 모바일 플랫폼은 사용자 장치의 로컬 데이터베이스와 서버의 로컬 데이터베이스를 매끄럽게 연결함으로써 전송 문제를 완전히 해결합니다. 두 위치 사이의 모든 변경 사항은 자동으로 동기화되며, 개발자는 항상 바로 옆에 있는 것처럼 로컬 데이터베이스를 사용하기만 하면 됩니다.

  • 앱은 자동으로 오프라인-우선 기능이 됩니다. 로컬 데이터베이스에서 작업하면 네트워크에 연결될 때마다 서버와 자동으로 동기화됩니다.
  • 전송 레이어에 제한이 없기 때문에 사용하던 네이티브 프로그래밍 언어 를 사용해서 데이터 엔티티와 비즈니스 로직을 정의할 수 있습니다! 즉, 비즈니스 도메인을 네트워킹 레이어에서 사용할 수 있는 형태로 제한할 필요가 없습니다.
  • Realm 모바일 플랫폼은 모바일 기기에 있건 서버에 있건 전송 중이건 상관없이 업계 표준 암호화 를 데이터 처리에 구현할 수 있습니다. 또한, 서버에서 바로 사용자 인증을 제공합니다.
  • Realm 모바일 플랫폼은 서버에 업데이트가 생기는 즉시 로컬 데이터를 업데이트하기 때문에 앱 캐싱 전략이 필요하지 않습니다.
  • 마지막으로 중요한 것은 사람들이 여러 플랫폼에서 공동 작업할 수 있는 멋진 반응형 앱 을 만들 수 있다는 점입니다. 사용자가 안드로이드 폰에서 인벤토리 항목을 삭제할 때마다 iOS 앱에서 정밀한 알림을 받아서 화면에서 정확한 테이블의 행이 삭제되도록 할 수 있습니다.

Cross-platform collaboration with the Realm Platform

결론적으로 여태껏 사용해 왔듯이 로컬 Realm 데이터베이스를 사용하기만 하면 Realm 모바일 플랫폼이 네트워크 작업을 자동으로 처리해줍니다. 이 내용이 흥미롭다면 Realm 모바일 플랫폼 개발자 에디션을 무료로 사용해 보세요.

무료 사용하기

가장 좋은 방법은 무엇일까요?

네트워킹과 캐싱은 까다롭습니다. (물론 네이밍도 어렵지만 아직 저희가 이는 해결하지 못했습니다.) 또한 비즈니스 도메인에서 사용하는 언어를 전송 프로토콜에서 허용하는 것으로 변경해야 했습니다.

성공적인 앱 네트워킹 레이어는 연결, 데이터 변환, 요청과 응답 유효성 검사, 데이터 모델과의 통신 등 많은 작업의 균형을 유지합니다. 이 중 하나라도 간과하면 갑자기 랜덤하게 크래시가 발생할 수도 있습니다. 서버 애플리케이션의 관련이 없는 영역에서 서버 팀이 변경한 내용 때문에 사용자가 받는 응답이 변경되고 모바일 애플리케이션의 작업이 멈춰버릴 수도 있습니다.

물론 네트워킹 및 데이터 동기화를 편리하게 자동화해주는 훌륭한 라이브러리가 많이 있습니다. 일부 앱의 문제점을 해결하거나 일부 앱의 복잡성을 줄이는데 도움이 되곤 하죠.

한편 Realm 모바일 플랫폼은 이런 문제를 해결할 수 있는 완전히 새로운 방법을 제공합니다. 모든 REST API를 제거하고 모바일 애플리케이션에 네트워크 레이어를 커스텀으로 구현할 필요도 없으므로, RESTful이나 다른 서버 API에 통신할 때의 모든 어려움을 전부 해결할 수 있습니다.

지금 바로 Realm 모바일 플랫폼을 시작해 보세요.

이 글에서 네트워크와 관련된 머리 아픈 문제를 모두 잊어버릴 수 있다는 것을 알려드릴 수 있어서 정말 즐거웠습니다. 간단한 데이터 동기화 기능을 이용해서 여러분은 어떤 앱을 구현하실 건가요?

개발 시작하기

다음: Realm 이해하기 #4: Realm 내부 구조와 동작 원리 자세히 살펴보기

General link arrow white

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Marin Todorov

Marin Todorov는 iOS 컨설턴트이자 퍼블리셔입니다. “iOS Animations by Tutorials”의 저자이며 iOS Animations by Emails” 뉴스레터를 운행하고 있습니다. 20년 넘게 Apple 관련 개발을 했으며 Monster Technologies와 Native Instruments 등의 회사에서 일하면서 4개 이상의 나라에서 거주했습니다. 또한 raywenderlich.com 튜토리얼 팀의 설립 멤버이기도 하죠. 코드 개발 이외에는 블로그 게재와 책 저술, 교육과 강연에 관심이 많으며, 코드를 오픈 소스화 하기도 합니다. Santiago 순례 경험도 있습니다.

4 design patterns for a RESTless mobile integration »

close