2022년 9월 12일 월요일

Android Graphql

Android Graphql

Android 와 GraphQL

모바일 앱 개발자라면 더 빠른 API와 더 빠른 애플리케이션의 중요성을 이해해야 합니다. 특히 데이터 트래픽이 더 비싼 국가에서는 필요한 데이터만 얻는 것이 특히 중요합니다.

그러나 API는 각기 다른 요구 사항을 가진 다양한 클라이언트를 위해 설계되었으며 대부분의 경우 이러한 API는 모바일 애플리케이션에 최적화되어 있지 않습니다. 이것이 GraphQL과 같은 새로운 기술이 도움이 될 수 있는 곳입니다.

GraphQL은 클라이언트가 필요한 데이터를 정확히 얻을 수 있도록 하는 API용 쿼리 언어입니다. 아직 GraphQL을 모르신다면 아래 링크에서 자세히 읽어보실 수 있습니다.graphql.org

GraphQL

GraphQL은 2012년 Facebook에서 내부적으로 개발한 데이터 쿼리 언어입니다. 2015년에 오픈 소스로 공개되었으며 RESTful 아키텍처의 대안을 제공하는 것을 목표로 합니다. GraphQL은 Graph+QL이라고 볼 수 있습니다. 여기서 QL은 쿼리 언어.그래서 GraphQL은 시각적(그래픽) 쿼리 언어를 의미하며, 이는 클라이언트가 서버에서 데이터를 요청하는 방법을 설명하는 API 구문입니다

기존의 API설계는 각 Endpoint와 해당메소드,파라메터를 바탕으로 작업했습니다. 이렇게 했을때 문제점은 너무 많은 각각의 Endpoint가 생성되고 새로운 디바이스등에서는 비슷한 엔드포인트를 서버에 새로 구축해야 하는 경우가 있었습니다.

GraphQL은 이를 하나의 엔드포인트로 결집하고 API 에 Query의 개념을 도입하여 데이터베이스의 쿼리처럼 원하는 데이터만 API로부터 받을수 있도록 하여 쓸데없는 트래픽을 줄여줄수있게 해줍니다.

GraphQL과 같이 등장하는 것중에 BFF(Backend For Frontend)라는 말이 등장하는데, BFF구현을 위해서 GraphQL을 도입하여 마이크로서비스로 구현된 백엔드의 각 서버에서 취합된 정보를 프론트엔드에 한번에 전달 하는 것을 가능케 합니다.

GraphQL 구성

  • sheme
    • 프로토콜, 사양 또는 인터페이스 문서로 간주 될 수 있습니다.
  • 데이터유형
    • 친숙한 JavaScript 또는 TypeScript String와 유사하게 Int(정수), Float(부동 소수점), String(문자열), Boolean(부울 유형) 및 ID(고유 식별자 유형). 동시에 날짜 유형과 같은 스칼라 유형을 사용자 정의하고 관련 직렬화, 역직렬화 및 유효성 검사 기능을 구현할 수도 있습니다
  • 3개의 메서드가 있습니다.
    • query : 데이터를 조회할때 사용합니다.
    • mutation : 데이터를 저장/가공 할때 사용합니다.
    • subscription : 데이터에 변화가 있을 때 이를 감지해서 클라이언트에 통보하여 줄때 사용합니다.
  • 이밖에 Enumeration types(열거형 유형), Union types(공집합 유형)이 있습니다. 동시에 코드를 더 잘 재사용하기 위해 (인터페이스) 기능도 제공됩니다

코드의 재사용성을 높이는 fragment

쿼리문에 작성하는 코드 부분의 재사용성을 높이기 위해 (fragment), (inline fragment) 및 (instruction) 함수 GraphQL도 제공됩니다 . 처음 두 가지는 JavaScript 의 (function) 및 (anonymous function )과 비교할 수 있으며, (instruction)은 우리가 전달하는 매개변수에 따라 특정 필드를 반환해야 하는지 여부를 결정할 수 있습니다.

Android에서 GraphQL

Android 플랫폼에서 GraphQL API를 사용하는 방법을 살펴보겠습니다. 인터넷에 네트워크 요청을 위한 많은 타사 라이브러리가 있지만 Android 플랫폼에는 아직까지 GraphQL 라이브러리가 Apollo 하나뿐입니다.

두 가지 주요 구성 요소가 있습니다.

  • Appllo Codegen : 이 구성 요소는 ButterKnife와 같은 코드를 생성하는 gradle 플러그인이며, apollo codegen은 표준 graphql 쿼리에서 컴파일 타임에 Java 모델을 생성합니다.
  • 네트워킹 및 캐싱(네트워킹/캐싱) : Apollo Android의 또 다른 구성 요소는 GraphQL API와의 모든 네트워크 통신을 담당하는 네트워크 및 캐시 부분으로, 반환된 데이터를 올바른 모델로 구문 분석하여 GraphQL 쿼리 및 응답 캐시에 동적 데이터를 전달할 수 있습니다.

Apollo 설치

Apollo는 GraphQL의 프론트엔드/백엔드 라이브러리입니다.
enter image description here

각각 Apollo Server, Apollo Client이고 제목 그대로 백엔드/프론트엔드용 프로그램입니다. brew로 설치하거나 npm 으로 도 설치가능합니다.

brew install apollo-cli

시작하기 Helloworld

1. 프로젝트에 GraphQL 라이브러리 등록

새로운 Android 프로젝트를 만듭니다.
프로젝트의 build.gradle에 classpath를 추가합니다.

com.apollographql.apollo3:apollo-gradle-plugin:3.1.0

앱의 build.gradle는

// plug ins 
plugins {
 ... 
id("com.apollographql.apollo3")
}
  
android {
    // src/main/com/sample/graphql 로 대충넣어도 됩니다.
	apollo {  
	  packageName.set("com.sample.graphql")  
	}
}  
dependencies {
  implementation("com.apollographql.apollo3:apollo-runtime:3.1.0")  
  implementation("com.apollographql.apollo3:apollo-adapters:3.1.0")  
}

2. 로컬에서 프로그래밍 할수 있도록 샘플 스키마를 가져오기

아폴로가 설치되었기 때문에 아래 명령어로 외부의 스키마를 가져올수가 있습니다. GraphQl 을 이용해서 스키마에 정의된 대로 자료를 가져오거나 넣을수있습니다.

./gradlew :app:downloadApolloSchema --endpoint=https://apollo-fullstack-tutorial.herokuapp.com/graphql --schema=`pwd`/app/src/main/graphsql/com/sample/graphql/scheme.graphqls

apollo의 샘플 데이터를 받았다면, 샘플데이터서버에 가서 스키마의 상세 스펙을 확인할수 있습니다.
enter image description here
화면의 Reference 를 눌러서 Query 목록중 launches 항목의 [>] 버튼을 눌러서 Explorer 화면으로 이동합니다.
enter image description here
Documentation과 Operation항목이 있습니다.
순서대로

  • launches : LaunchConnection +
  • Fields > cursor, hasMore, launches 선택
  • launches의 Field중 id,site 선택
    [ > Launches ] 를 선택하면 목록이 나타납니다.
    이렇게 원하는 필드를 원하는 쿼리에 추가하여 데이터를 전송받을 수 있습니다.
  • […] 메뉴의 copy operation을 선택하고
    Android Studio의 graphql폴더에 LaunchList.graphql파일을 저장합니다.
  • 안드로이드를 재빌드 하면 build/source/apollo/service/LaunchesQuesry.kt 파일이 생성되어있고 자동으로 클래스및 데이터 클래스가 생성되어 있습니다.
  • 적당한 곳에 Apollo.kt파일을 만듭니다.
import com.apollographql.apollo3.ApolloClient    
val apolloClient = ApolloClient.Builder().serverUrl(  
    serverUrl = "https://apollo-fullstack-tutorial.herokuapp.com/graphql"  
).build()
  • Fragment나 액티비티의 적당한 곳, 혹은 코루틴으로 데이터를 가져와 봅니다.
  
lifecycleScope.launchWhenCreated{  
  val response = apolloClient.query(LaunchesQuery()).execute()  
    Log.v("Launch", "${response.data}")  
  
}
/*
Data(launches=Launches(cursor=1584533760, hasMore=true, launches=[Launch(id=110, site=CCAFS SLC 40), Launch(id=110, site=KSC LC 39A), Launch(id=109, site=CCAFS SLC 40), Launch(id=108, site=VAFB SLC 4E), Launch(id=107, site=KSC LC 39A), Launch(id=106, site=CCAFS SLC 40), Launch(id=105, site=CCAFS SLC 40), Launch(id=104, site=KSC LC 39A), Launch(id=103, site=KSC LC 39A), Launch(id=102, site=KSC LC 39A), Launch(id=101, site=CCAFS SLC 40), Launch(id=100, site=CCAFS SLC 40), Launch(id=99, site=KSC LC 39A), Launch(id=98, site=CCAFS SLC 40), Launch(id=97, site=CCAFS SLC 40), Launch(id=96, site=CCAFS SLC 40), Launch(id=95, site=CCAFS SLC 40), Launch(id=94, site=KSC LC 39A), Launch(id=93, site=KSC LC 39A), Launch(id=92, site=KSC LC 39A)]))*/

.graphqlconfig 파일을 작성하여 서버로부터 스키마파일을 쉽게 가져올수 있습니다.
또한 Android Studio의 GraphQL Plugin 을 설치했다면, GraphQL판넬에서 Endpoints목록에서 해당 주소를 더블클릭하여 스키마를 다운로드 받을수 있습니다.

{  
  "name": "Untitled GraphQL Schema",  
  "schemaPath": "schema.graphqls",  
  "extensions": {  
    "endpoints": {  
      "Default GraphQL Endpoint": {  
        "url": "https://apollo-fullstack-tutorial.herokuapp.com/graphql",  
        "headers": {  
          "user-agent": "JS GraphQL"  
  },  
        "introspect": true  
  }  
    }  
  }  
}

부록

BFF (Backend For Frontend) & GraphQL

Backend For Frontend는 이름에서 알 수 있듯이 프런트 엔드 요구에 구체적으로 응답하는 서버입니다.
Backend For Frontend 는 2015/16년에 점차 주목을 받기 시작했습니다.수년간의 연습과 개발을 통해 업계는 이미 다양한 기술 스택의 솔루션과 사례를 많이 보유하고 있습니다. 개인적으로 BFF를 정확히 이해하기 위해서는 구체적인 기술적인 내용과 비즈니스 시나리오를 제쳐두고 팀워크의 관점에서 바라볼 필요가 있다.

BFF의 탄생은 서버 측 도메인의 기능 축적과 프런트 엔드의 다양한 데이터 요구 사항 간의 모순을 해결하는 것입니다. 따라서 프런트 엔드와 서버 간의 충돌을 줄이고 개발 비용을 줄이는 데 도움이 되는 모든 것이 BFF 논의 범위에 속합니다.

우리는 다음 측면에서 BFF의 적용 가능한 시나리오를 논의합니다.

  • 데이터 집계 클리핑

    일반적으로 서버 측 개발에 대한 페이지의 영향을 줄이기 위해 서버 측에서 API 계층을 분리하여 페이지 요구 사항에 구체적으로 대응합니다. 그러나 몇 가지 명확한 제약 조건과 지침이 없기 때문에 여러 가지 이유로 일부 비즈니스 로직이 API 계층에 점차 나타나게 되어 API 계층과 비즈니스 계층 간의 경계가 흐려지고 페이지 요구 사항에 대한 응답에 영향을 미칩니다.

  • SSR

    이제 SSR에 관해서는 일반적으로 NodeJS + React/Vue 기반의 서버 측 렌더링으로 이해됩니다. 사실 초창기에는 템플릿 기반의 구현도 있었는데, Apache Velocity (Java), EJS (JS) 등 이 잘 알려진 템플릿 엔진이었습니다.

  • 업로드 다운로드

    업로드 및 다운로드는 비교적 일반적인 비즈니스 시나리오이지만 기능의 일반화로 인해 비즈니스 기능으로 비즈니스 시스템에 담기는 어려운 경우가 많습니다.

  • 인터페이스 포워딩

    일부 시나리오에서는 다른 인터페이스를 집계하지 않고 페이지 요구 사항을 충족할 수 있으며 페이지 요청을 도메인 서비스로 직접 전달할 수 있습니다. 하지만 로그인, 인증 등 일련의 검증 로직이 필요하기 때문에 Nginx를 통해 직접 전달하는 것은 불가능하며, 이를 처리하기 위한 서비스 계층(위에서 언급한 API 계층 등)이 필요하다.

이러한 문제 중 일부는 서버 측 개발에서 더 나은 문제가 있고 일부는 프론트엔드 개발에서 더 나은 것을 볼 수 있습니다. 이것은 또한 BFF 자체의 위치를 ​​확인합니다.

GraphQL

위에서 BFF를 적용할 수 있는 여러 시나리오에 대해 논의했으며 그 중 데이터 집계 및 자르기가 가장 일반적이고 충돌하는 시나리오라고 할 수 있습니다. GraphQL과 그 생태계는 솔루션 세트를 제공합니다.

공식 정의에서 GraphQL은 두 가지 의미를 갖습니다.

  • API용 쿼리 언어입니다.
  • 기존 데이터를 사용하여 이러한 쿼리를 완료하는 런타임입니다.

위의 다이어그램에서 우리는 DSL을 통해 시스템의 유형을 설명합니다. 각 유형은 노드이며 여러 노드와 노드 간의 관계는 결국 그래프를 생성합니다. 모든 쿼리는 이 그래프를 기반으로 합니다. 쿼리할 때마다 그래프의 특정 노드에서 시작하여 트리를 선택한다는 것을 시각적으로 이해할 수 있습니다.

GraphQL에는 다음과 같은 특징이 있습니다.

  • 더도 말고 덜도 말고 온디맨드 방식으로 데이터를 반환하고 데이터는 매우 결정적입니다.
    • 필요한 데이터 필드, 중첩 구조 등은 끝에 설명하고 서버는 설명에 따라 반환합니다. 동시에 필드 유형과 필드가 비어 있는지 여부에 대한 명확한 규칙이 있습니다.
  • 병합 요청
    • 페이지의 여러 데이터 요청을 단일 GraphQL 쿼리로 결합할 수 있습니다. 약한 네트워크 환경에서 특히 유용합니다.
  • 잘 정립된 유형 시스템
    • 시스템의 모든 모델은 필드 유형, 모델 구조 및 모델 간의 관계를 포함하여 스키마를 통해 설명됩니다. 인트로스펙션 모드를 통해 시스템의 모든 스키마 정보를 조회할 수 있으며, 그 효과는 API 문서와 동일하다.
    • 유형 시스템 주변에서 클라이언트 측 코드 생성 도구 GraphQL 코드 생성기와 같은 많은 효율적인 도구를 개발할 수 있습니다.
  • 부드러운 API 업그레이드, 버전 없음
    • 필드를 추가해도 기존 쿼리에는 영향을 미치지 않습니다.
    • Mark Deprecated 필드는 인트로스펙션 모드에서 자동으로 표시됩니다.
  • 세밀한 필드 제어
    • 적절한 Resolver를 정의하면 시스템의 모든 모델과 필드를 세밀하게 제어할 수 있습니다. 유형 변환, 묻힌 지점 모니터링 등

0 comments:

댓글 쓰기