Logo
Droid Lab by Bonny

Android에서 Open API Generator 사용해보기 ⚙️

2022년 12월

Android에서 Open Api Generator를 연동해 Retrofit 코드를 자동 생성해보았습니다. 의도치 않게 이슈들이 많아 약 2주말을 날린 대 삽질기가 되었습니다.👷⛏

Github Code

🤔 Open API Specification

Open API Specification(OAS)는 같은 이름인 누구나 사용할 수 있도록 공개된 Open API와는 별개의 것입니다. 이 글에서 이야기 할 Open API Specification은 RESTful API를 개발하거나, 클라이언트를 연동할 때 어떤 API가 있는지 json이나 yaml 형식으로 명세를 만든 것입니다. 해당 JSON, YAML 파일을 통해 API 문서, 코드, 테스트 스펙을 생성하거나 시각화할 수 있습니다.

Open API Specification은 Swagger 사에서 시작되어 본래의 이름은 Swagger Specification 2.0 이었지만, 3.0 버전 이후부터는 Swagger Specification 3.0 또는 Open API Specification 라는 이름으로 불리고 있습니다.

{
  "openapi": "3.1.0",
  "info": {
    "title": "Simple Todo",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://simple-todo.simple-todo.workers.dev/api"
    }
  ],
  "paths": {
    "/ping": {
      "get": {
        "operationId": "ping",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}

⚙️ Open API Generator

2022 12 android open api generator1

Open API Generator는 클라이언트, 서버 코드나 문서를 생성하는 Java 기반의 도구입니다. 템플릿 기반의 확장을 제공하기 때문에, Kotlin부터 Scala, TypeScript, Python 등 다양한 환경의 클라이언트, 서버 코드를 생성할 수 있는 Generator들이 존재합니다 (참고: Open API Generator가 제공하는 생성기 목록)

Open API Generator는 기본적으로 CLI로 제공되며, 여기에서 자세한 설치 방법을 확인하실 수 있습니다.

# petstore.yaml 스펙을 이용해, Ruby 코드를 생성하기
$ openapi-generator-cli generate -i petstore.yaml -g ruby -o /tmp/test/

🔨 Android에 Open API Generator 연동하기

OAS는 정확히 작동하는 Spec을 찾기 어려워 간단한 예시를 만들어 사용했습니다. 이 Spec을 사용할 수 있는 network 모듈을 자동 생성하여 app 모듈에서 network 모듈을 코드를 사용해 볼 것입니다.

1. 빌드 세팅

Android Project를 생성하고 Project 단위 build.gradle 파일을 열어 다음 코드들을 입력합니다.

buildScript {
    repositories {
        ...
        maven { url "https://repo1.maven.org/maven2" }
    }
    dependencies {
        ...
        classpath('org.openapitools:openapi-generator-gradle-plugin:6.2.1') {
            exclude group: 'com.google.guava'
        }
    }
}
...
plugins {
    ...
    id 'de.undercouch.download' version '4.1.1'
}
apply plugin: 'org.openapi.generator'

configurations {
    compile.exclude module: 'guava-jdk5'
}

def basePackage = "com.example"
def targetDir = "$rootDir/network"
def targetFileName = "spec.json"

task downloadFile(type: Download) {
    doFirst {
        delete(file(targetDir))
        project.mkdir(targetDir)
    }
    src "https://simple-todo.simple-todo.workers.dev/api/$targetFileName"
    dest rootDir
    onlyIfModified true
    useETag true
}

openApiGenerate {
    generatorName = "kotlin"
    inputSpec = "$rootDir/$targetFileName"
    outputDir = targetDir
    apiPackage = basePackage.concat(".api")
    modelPackage = basePackage.concat(".model")
    configOptions = [
        dateLibrary: "java8",
        library: "jvm-retrofit2",
        omitGradleWrapper: "true",
        sourceFolder: "src/main/java"
    ]
}

tasks.openApiGenerate.dependsOn tasks.downloadFile

위 코드에서 추가한 코드는 아래와 같습니다.

  1. openapi.generator dependency 추가
  2. dependency 충돌 부분 수정 (guava)
  3. 링크된 OAS 로부터 spec.json 을 다운받아 openapi generate 작업 수행 (openApiGenerate)
  4. 3 작업을 수행하기 전에 이전 3 작업물 제거 (downloadFile Task)

3번에 대한 자세한 내용은 링크에 있습니다. 간략히는 OAS 스펙에서 다운받은 spec.json 파일을 inputSpec으로 명시해주고 outputDir 을 통해 네트워크 모듈 생성 위치를 잡아줍니다. 자동 생성되는 api, model package의 위치를 apiPackage, modelPackage로 잡아주고 configOptions를 통해 retrofit 코드를 생성합니다.

위와 같이 설정하면 프로젝트 root에서 아래 명령어로 openApiGenerate를 실행할 수 있습니다.

./gradlew openApiGenerate

위 명령어를 통해 network 모듈이 생성됩니다. 아래와 같은 코드가 생성되었습니다.

2022 12 android open api generator2

retrofit client를 생성하는 ApiClient.kt 파일, ping api 명세를 담고 있는 DefaultApi.kt, 여기에서 사용한 Ping 응답의 response인 Ping200Response.kt 가 생성되었습니다.

❗️ 안타깝게도 arcticfox 버전의 안드로이드 스튜디오를 사용할경우 network 모듈 내부 build.gradle 파일 안에 빌드 에러가 생기는 구문도 함께 생성되는데요. 아래 block을 지워줍니다.

...
repositories {
    maven { url "https://repo1.maven.org/maven2" }
}

이 이슈를 해결하면 실제 프로젝트에서 사용하기 좋을 것 같습니다. 이 이슈는 더 파보지 않아서 해결방법을 아시는 분은 알려주세요!

2. app 모듈에서 network 모듈 사용하기

settings.gradle 파일에 network 모듈을 include 합니다.

...
include ':network'

app module 단위 build.gradle에서 network 모듈 dependency를 추가합니다.

dependencies {
    implementation project(":network")
    ...
}

위와 같이 추가하고 gradle sync를 하면 app 모듈 내에서 아래와 같이 network모듈을 사용할 수 있습니다.

ApiClient()
    .createService(DefaultApi::class.java)
    .ping().enqueue(object: Callback<Ping200Response> {
        override fun onResponse(
        call: retrofit2.Call<Ping200Response>,
        response: Response<Ping200Response>
        ) {
            Log.d("Bonny", "${response.body().toString()}")
        }

        override fun onFailure(call: retrofit2.Call<Ping200Response>, t: Throwable) {
            Log.d("Bonny", "fail ${t.message}")
        }
    })

👿 연동 이슈

1. 자동생성된 build.gradle에 있는 코드가 빌드 에러 나는 이슈

위에 과정 중에 있던 것처럼 아래 코드를 수동으로 지워주어야 하는데요. 이 이슈만 해결하면 retrofit 사용은 문제 없을 것 같습니다.

...
repositories {
    maven { url "https://repo1.maven.org/maven2" }
}

2. ktor 생성 이슈

우선 ktor configOptions는 아래와 같이 설정하였습니다.

configOptions = [
    dateLibrary: "java8",
    library: "jvm-ktor",
    omitGradleWrapper: "true",
    sourceFolder: "src/main/java",
    serializationLibrary: "gson"
]

위 설정으로는 dependency conflict가 생기는데요. 이 부분도 좀 더 파보아야 할 것 같습니다.

✍️ 결론

아직 실제 프로덕션 코드에서 사용하긴 어려울 것 같습니다. 아직 기여할 부분이 많아 함께 고쳐나가면 더 좋은 생태계가 될 수 있을 것 같습니다.

추천
클린 아키텍쳐를 지향해야하는 이유
클린 아키텍쳐를 지향해야하는 이유
2024년 1월
MVC, MVP, MVVM, MVI 아키텍쳐 안드로이드 코드로 알아보기 - 1
MVC, MVP, MVVM, MVI 아키텍쳐 안드로이드 코드로 알아보기 - 1
2023년 11월
Compose Side Effect에서 내가 잘 못 이해한 것들 🙅‍♀️
Compose Side Effect에서 내가 잘 못 이해한 것들 🙅‍♀️
2023년 4월
안드로이드에서 graphql 시작하기🛫
안드로이드에서 graphql 시작하기🛫
2023년 2월
목록으로 돌아가기
Loading script...
Designed by Tony / Written by Bonny