Android/이론 학습

[Android/GraphQL] Apollo Kotlin (시작 ~ 쿼리실행)

노소래 2022. 3. 8. 12:30

[목차]

- 도입

- 용어 정리

- 프로젝트에 Apollo 추가하기

- Schema 추가하기

- 쿼리 추가하기

- 쿼리 실행하기

- 마무리

 

[도입]

  이름과 대략적인 내용만 들어보고 써보진 않았다. 최근에 쓰게될 일이 생겨서 그 전에 테스트 겸 셀프 실습을 진행해본다. 모킹 서버를 어디서 찾을까 하다가 Rick and morty (예전에 즐겨본 애니메이션) api 가 눈에 들어왔고 Apollo, GraphQL 공식문서를 참고하여 적용하려 한다. 설레는 마음으로 시작!

릭앤모티 api

 

Documentation

This documentation will help you get familiar with the resources of the Rick and Morty API and show you how to make different queries.

rickandmortyapi.com

Apollo 공식문서 tutorial

 

0. Introduction

Next 1. Configure your project

www.apollographql.com

 

GraphQL 공식문서 Introduction

 

Introduction to GraphQL | GraphQL

Introduction to GraphQL Learn about GraphQL, how it works, and how to use it. Looking for documentation on how to build a GraphQL service? There are libraries to help you implement GraphQL in many different languages. For an in-depth learning experience wi

graphql.org

 

[용어 정리]

<Graphql>

REST API 처러 정해진 모든 양의 데이터가 아닌 원하는 정보만 가져올 수 있다. 

여러 depth 의 정보를 한 번의 요청으로 받아올 수 있다.

여러 플랫폼의 여러 각 상황마다 가져와야할 데이터가 다를 때 매우 유용하다. (서버에서 각 상황에 맞는 api 를 만들필요가 없기 때문)

받아야할 항목들이 많고 여러 플랫폼의 각 상황에서 받아야할 정보가 통일되어있다면 REST API 를 사용하고 그렇지 않다면 Graphql 방식을 사용할 것 같다.

(물론 REST API, Graphql 둘 다 만들어놓을 수 있다.)

 

<Apollo>

Apollo Kotlin 은 GraphQL 쿼리들로 부터 Kotlin, Java 모델들을 생성해주는 GraphQL client 이다. 

GraphQL server 로 부터 query 와 mutation 을 실행해주고 쿼리에 명시해놓은 결과를 반환해준다. 

JSON 파싱이나 타입 같은 우리가 수동으로 해야할 일을 자동으로 해준다. 

 

 

[프로젝트에 Apollo 추가하기]

아래 세 가지 모두 app/build.gradle.kts 에 더해준다.

id("com.apollographql.apollo3").version("3.2.0")

⬆️위 플러그인이 프로젝트 빌드할 때, 내 쿼리로부터 모델을 생성하는 컴파일러를 포함하고 있다.

implementation("com.apollographql.apollo3:apollo-runtime:3.2.0") 

⬆️dependency 추가

apollo {
    packageName.set("com.nosorae.labs")
}

⬆️플러그인이 생성되는 코틀린 파일들을어느 패키지에 넣을지 설정하기 위한 작업 (나 같은 경우는 패키지 네임 통일)

 

 

[Schema 추가하기]

schema 는 서버가 어떤 Graphql 오퍼레이션을 수행할 수 있는지 정의해놓은 것이다.

Apollo Kotlin 은 우리의 쿼리로 부터 type-safe model 과 코드를 생성하기 위해 schema 를 필요로 한다. 

아래와 같은 형식으로 플러그인에의해 생성된 apolloDownloadSchema 라는 Gradle task 를 사용해서 받아올 수 있다. (물로 스키마 받아오는 다른 다양한 방법이 있음 이번에 사용하는 rick and morty api 같은 경우는 json or sdl 형식으로 다운 받을 수 있게 해주더라. 근데 그 방법으로 ) 

app/src/main 패키지 안에 (java 패키지와 동일한 레벨에) graphql 패키지를 만들자 그리고 schema 를 추가해준다.

.graphqls 로 받아온다.

./gradlew :app:downloadApolloSchema --endpoint='https://rickandmortyapi.com/graphql' --schema=app/src/main/graphql/com/nosorae/labs/schema.graphql

좌측 사진처럼 파란띠가 뜨면 install 을 클릭하자 그럼 우측 사진처럼 *.graphqls 를 인식한다. (우측 사진 query 추가된 건 무시)
또는 File > Settings > Plugin 에서 JS GraphQL 을 설치하자

 

[쿼리 추가하기]

이제 아무 쿼리를 추가해보자.

(참고한 다른 블로그에서는 Chraracters 로 하길래 나는 Locations 로 해보았다)

릭앤모티 api Playground 로 가서 DOCS 나 SCHEMA를 활용해서 기본적인 쿼리를 작성해보자

쿼리 테스트

이제 위 쿼리를 프로젝트 파일로 만들어보자

쿼리 파일은 스키마와 같은 패키지 안에 그리고 같은 패키지 레벨에 있게 해야한다.

Locations.graphql 로 추가해준다.

 

여기서 주의할 점은 쿼리는 graphql, 스키마는 graphqls 여야한다는 것이다.

(아직 왜인지는 모르겠으나 공식문서 튜토리얼에서 그렇게 하고 있다. 둘 다 graphqls 로 시도해봤는데 excutable definition 을 찾을 수 없다는 아래와 같은에러가 발생한다.)

(참고로 스키마를 .graphql 로 만들면 아래와 같은 에러가 발생한다.)

 

쿼리를 추가했다면 이제 빌드해서 코드 생성을 마치어보자

빌드하면 Apollo Kotlin plugin 이 model 을 생성해준다.

(참고로 이 태스크의 이름은 generateApolloSources 이다.)

아래 사진과 같이 확인해도 되고

shift 연타해서 클래스를 검색해서 확인할 수도 있다.

생성된 코드

여기까지가 쿼리 코드 생성이다.

 

[쿼리 실행하기]

매우 간단하다. 

먼저 ApolloClient 객체를 Builder 패턴으로 생성해준다.

그리고 분리된 코루틴에서 쿼리를 날려주면된다.

MVVM 패턴을 적용할 예정이긴 하지만 이 글에서 그것까지 다루는 것은 비효율적이라고 생각해서 

여기서는 바로 Activity 에서 불러와서 실행하는 코드를 실행해보았다.

class ApolloTestActivity : AppCompatActivity() {
    val apolloClient = ApolloClient.Builder()
        .serverUrl("https://rickandmortyapi.com/graphql")
        .build()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_apollo_test)

        lifecycleScope.launch {
            val response = apolloClient.query(LocationsQuery()).execute()
            Log.d("LocationsQuery", "Success ${response.data}")
        }
    }
}

-> 결과

D/LocationsQuery: Success Data(locations=Locations(info=Info(count=126), results=[Result(id=1, name=Earth (C-137), type=Planet), Result(id=2, name=Abadango, type=Cluster), Result(id=3, name=Citadel of Ricks, type=Space station), Result(id=4, name=Worldender's lair, type=Planet), Result(id=5, name=Anatomy Park, type=Microverse), Result(id=6, name=Interdimensional Cable, type=TV), Result(id=7, name=Immortality Field Resort, type=Resort), Result(id=8, name=Post-Apocalyptic Earth, type=Planet), Result(id=9, name=Purge Planet, type=Planet), Result(id=10, name=Venzenulon 7, type=Planet), Result(id=11, name=Bepis 9, type=Planet), Result(id=12, name=Cronenberg Earth, type=Planet), Result(id=13, name=Nuptia 4, type=Planet), Result(id=14, name=Giant's Town, type=Fantasy town), Result(id=15, name=Bird World, type=Planet), Result(id=16, name=St. Gloopy Noops Hospital, type=Space station), Result(id=17, name=Earth (5-126), type=Planet), Result(id=18, name=Mr. Goldenfold's dream, type=Dream), Result(id=19, name=Gromflom Prime, type=Planet), Result(id=20, name=Earth (Replacement Dimension), type=Planet)]))

 

 

[마무리]

이제야 Apollo, Graphql 과의 인사를 마쳤다. 새로운 기술을 배우는 것은 항상 설레는 것 같다.  

과거 진행했던 프로젝트들을 떠올려보니 REST API 보다 GraphQL 이 더 적절했던 때가 보인다. 같은 회원정보라 할지라도 플랫폼이나 화면마다 필요한 정보의 범위 (프로퍼티의 개수) 가 다른데, REST 로는 네트워크 통신량을 줄이자니 API 를 여러개 만들어야하는 번거로움이 있고 하나의 API 로 통일해서 쓰자니 불필요한 정보까지 받아온다는 문제점이 있었던 때가 떠올랐다.

앞으로는 실제 프로젝트에 적용해보며 상황에 맞는 다양한 기능을 적용해볼 것 같다. 그 때마다 블로그에 글을 정리할 예정이다. (빨리 프로젝트에 투입되고 싶다..!)