YOUNG-JIN.OH
웃어라. 온 세상이 너와 함께 웃을 것이다.
울어라. 너 혼자만 울게 될 것이다.

Spring Boot, YouTube API 설정

참고 사이트:

IntelliJ IDEA 에서 프로젝트 생성시 Spring Initializr, Type “Gradle”, Java Version “11” 기준으로 별도의 Dependencies 선택없이 프로젝트를 생성합니다.

build.gradle

plugins {
    id 'org.springframework.boot' version '2.1.3.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    compile group: 'com.google.apis', name: 'google-api-services-youtube', version: 'v3-rev206-1.25.0'
    compile group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.28.0'
}

YouTubeDataAPI.java

package com.example.demo;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.YouTubeScopes;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

public class YouTubeDataAPI {

    private static final String APPLICATION_NAME = "YouTube Master";
    private static final File DATA_STORE_DIR = new File(System.getProperty("user.home"), ".oauth-credentials");
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final List<String> SCOPES = Arrays.asList(YouTubeScopes.YOUTUBE_FORCE_SSL);
    private static HttpTransport HTTP_TRANSPORT;
    private static FileDataStoreFactory DATA_STORE_FACTORY;

    static {
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(1);
        }
    }

    private static Credential authorize() throws IOException {
        InputStream in = YouTubeDataAPI.class.getResourceAsStream("/client_secret.json");
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(DATA_STORE_FACTORY)
                .setAccessType("offline")
                .build();

        LocalServerReceiver localReceiver = new LocalServerReceiver.Builder()
                .setHost("localhost")
                .setPort(8080).build();

        Credential credential = new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");

        return credential;
    }

    public static YouTube getYouTubeService() throws IOException {
        Credential credential = authorize();

        return new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }
}

참고 사이트의 내용을 정리해서 소스를 구성하고 OAuth 2.0 설정시 다운받았던 client_secret_xxx.json 파일을 main – resources 에 client_secret.json 으로 저장합니다. 그리고 API를 통해 YouTube 채널정보를 조회하는 테스트 코드를 작성해서 실행해봅니다.

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    /**
     * https://developers.google.com/youtube/v3/docs/channels?hl=ko
     */
    @Test
    public void channels() throws IOException {
        var result = YouTubeDataAPI.getYouTubeService()
                .channels()
                .list("id,snippet,brandingSettings,contentDetails,invideoPromotion,statistics,topicDetails")
//                .setId("UCYfy5yVnG7l2vbTumjYYP9w")
                .setForUsername("NoCopyrightSounds")
                .execute();

        System.out.println(result);
    }
}

Please open the following address in your browser: 다음에 뜨는 링크를 누르면 구글 사용자 계정에 로그인 및 권한 동의내용이 나오게 되고 콜백(Callback) 처리가 완료되면 API 응답 결과가 JSON으로 오는 것을 확인할 수 있습니다. OAuth 2.0 콜백설정과 YouTubeDataAPI.java 에서 LocalServerReceiver 서버정보가 일치해야 콜백처리가 되니 주의합니다.

이렇게 테스트까지는 별 문제가 없는데, 샘플 소스 및 라이브러리가 오래된 버전인지 Spring Web을 위한 Dependencies 를 추가하면 버전 충돌(Conflict)이 발생합니다. 콜백처리를 위한 google-oauth-client-jetty의 servlet (2.5) 버전과 Spring Boot의 Tomcat 9 최신 버전의 Servlet 버전이 맞지 않기 때문입니다.

build.gradle 에 아래와 같이 변경합니다.

plugins {
    id 'org.springframework.boot' version '2.1.3.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    compile group: 'com.google.apis', name: 'google-api-services-youtube', version: 'v3-rev206-1.25.0'
    compile (group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.28.0') {
        exclude group: 'org.mortbay.jetty', module: 'servlet-api'
    }
}

YouTubeRestController.java

package com.example.demo;

import com.google.api.services.youtube.model.ChannelListResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class YouTubeRestController {

    @GetMapping(value = "/api/channels/{channelId}")
    public ChannelListResponse getChannels(@PathVariable("channelId") String channelId) throws IOException {

        var result = YouTubeDataAPI.getYouTubeService()
                .channels()
                .list("id,snippet,brandingSettings,contentDetails,invideoPromotion,statistics,topicDetails")
                .setId(channelId)
                .execute();

        return result;
    }
}

다시 DemoApplication.java 를 실행하면 정상적으로 구동되고 API를 호출해보면 다음과 같이 정상적으로 JSON을 돌려주는 것을 알 수 있습니다.

이제부터는 채널정보 이외에 제공하는 다양한 API를 프로젝트에 맞는 JSON 포맷으로 재구성(Mapping)하는 노가다를 진행해야 합니다.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.