[Java] 使用 Scribe 操作 ImgUr API Version 3

前言

因為想要把自己四散各網站的相簿整合在一個單一的平台,所以在研究怎麼樣用 Java / Scala 操作 ImgUr API 第三版。

雖然說在 Java 的環境下已經有好用的 Scribe 來幫我們處理 OAuth 的部份,不過不幸的是原本附在 Scribe 裡面的 ImgUr API 已經過時了,不能直接使用。

幸好由於 Scribe 在設計上相當彈性,所以稍微看了一下 ImgUr 網站上的 API Version 3 的規格,也就把相關的東西實作出來了。

程式碼

新增的程式碼可以在 我在 GitHub 上的 Pull Reqeust 上看到,主要是新增兩個類別而已。

不過因為程式非常的短,而且加上 Scribe 本身的設計,他們是可以直接放在你的 Project 裡面的,所以如果現在就有需要,那只要把這兩個類別 Copy & Paste 到自己的專案中就可以了,並且參照使用範例就可以囉。

package org.scribe.builder.api;

import org.scribe.model.OAuthConfig;
import org.scribe.oauth.OAuthService;
import org.scribe.oauth.OAuthImgUr3Impl;

import org.scribe.model.Verb;
import org.scribe.extractors.JsonTokenExtractor;
import org.scribe.extractors.AccessTokenExtractor;

/**
 * ImgUr API ver3 (OAuth 2)
 *
 * @author Brian Hsu
 *
 * @see <a href="http://api.imgur.com/">ImgUr API</a>
 */
public class ImgUr3Api extends DefaultApi20 {

  private static final String authorizeURL = "https://api.imgur.com/oauth2/authorize";

  private boolean isOOB(OAuthConfig config) {
    return "oob".equals(config.getCallback());
  }

  @Override
  public Verb getAccessTokenVerb() {
    return Verb.POST;
  }

  @Override
  public AccessTokenExtractor getAccessTokenExtractor() {
    return new JsonTokenExtractor();
  }

  @Override
  public String getAccessTokenEndpoint() {
    return "https://api.imgur.com/oauth2/token";
  }

  @Override
  public String getAuthorizationUrl(OAuthConfig config) {
    String apiKey = config.getApiKey();
    if (isOOB(config)) {
      return String.format("%s?client_id=%s&response_type=pin", authorizeURL, apiKey);
    } else {
      return String.format("%s?client_id=%s&response_type=code", authorizeURL, apiKey);
    }
  }

  @Override
  public OAuthService createService(OAuthConfig config) {
    return new OAuthImgUr3Impl(this, config);
  }
}
package org.scribe.oauth;

import org.scribe.builder.api.DefaultApi20;

import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;

public class OAuthImgUr3Impl extends OAuth20ServiceImpl {

  private DefaultApi20 api;
  private OAuthConfig config;

  public OAuthImgUr3Impl(DefaultApi20 api, OAuthConfig config) {
    super(api, config);
    this.api = api;
    this.config = config;
  }

  private boolean isOOB(OAuthConfig config) {
    return "oob".equals(config.getCallback());
  }

  @Override
  public Token getAccessToken(Token requestToken, Verifier verifier) {

    OAuthRequest request = new OAuthRequest(
      api.getAccessTokenVerb(),
      api.getAccessTokenEndpoint()
    );

    String grantType = isOOB(config) ? "pin" : "authorization_code";

    // ImgUr API ver 3 using POST to get token, and we need pass
    // parameters using Body parameter, query string will not work.
    request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
    request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
    request.addBodyParameter("grant_type", grantType);
    request.addBodyParameter("pin", verifier.getValue());

    Response response = request.send();

    return api.getAccessTokenExtractor().extract(response.getBody());
  }

  @Override
  public void signRequest(Token accessToken, OAuthRequest request) {

    if (accessToken != null) {
      request.addHeader("Authorization", "Bearer " + accessToken.getToken());
    } else {
      request.addHeader("Authorization", "Client-ID " + config.getApiKey());
    }
  }

}

回響