コマンドライン上でOAuth APIを通じてリソースを利用してみる

OAuthとは、リソースオーナーがクライアントに対してリソースサーバが保有する自身のリソースの利用を認可する仕様であり、本来リソースオーナーが直接利用するものではありません(自身のリソースを使うなら認可は要らないはず)。

f:id:mmorita44:20170717145637p:plain

OAuth - Wikipedia

リソースオーナーがリソースを利用する場合はBasic認証APIを用いればよいのですが、Basic認証APIをサポートしないサービスが散見されます。この場合にはOAuth APIを利用するしかありません。

というわけで、今回はコマンドライン上でOAuth APIを通じてリソースを利用する方法について説明します。以降の手順では、Basic認証APIをサポートしないサービスの代表格であるPocket APIを例として用いています。

手前味噌ながらPython3専用のPocket APIライブラリ「py3pocket」も以下の手順を元に作成したものです。良かったら使ってみてください。

手順

手順へ入る前に、PocketのOAuthフローについて確認しましょう。

ここでのユーザはOAuthの定義から言うところのリソースオーナー且つクライアントであり、PocketのWebサーバ(以降Pocketサーバと省略)はリソースサーバ且つ認可サーバとなります。図で表すと下図のような感じでしょうか。

f:id:mmorita44:20170717162942p:plain

PocketのOAuthフロー

なお、Pocketでは認可グランドはPocketサーバから発行されるリクエストークンが該当し、ユーザへの認可はその後に行ないます。

1. 先ずは認可を済ませる

コマンドライン上からOAuth APIを利用するには、そのユーザに対して予めリソース利用を認可しておく必要があります。Pocketではリクエストークンを取得した後に 認可ページを表示します。認可を終えた後、認可継続のため指定URLへリダイレクトします。これでOKです。

f:id:mmorita44:20170717162517p:plain

認可ページ

ちなみに、py3pocketではauthorize関数がこの処理に該当します。

2. セッションを予め取得する

「4. 認可処理継続のためのリダイレクトを回避する」で後述するように、リダイレクトを回避するためにPocketサーバからセッションを取得しておきます。

3. リクエストークンを取得する

リクエストークンはPocketで用いられる認証グランドの形態で、Pocketサーバへ認可要求することにより取得します。ユーザを認可ページへ誘導させる際に併せて送付することになります。

4. 認可処理継続のためのリダイレクトを回避する

通常はユーザを認可ページへ誘導し、認可をもらい、その後認可処理継続のために指定URLへリダイレクトします。しかし、「1. 先ずは認可を済ませる」及び「2. セッションを予め取得する」を予め行っていれば、このリダイレクトを回避してもそのまま認可処理は継続できます。そのため、ここではユーザを認可ページへ誘導するリクエストだけ投げておきます。

逆に言うと、ここでリダイレクトが発生せずに認可ページが表示される場合は認可が済んでいないということになります。そうなった場合には、「1. 先ずは認可を済ませる」もしくは「2. セッションを予め取得する」が済んでいるかどうか確認してください。

5. リクエストークンをアクセストークンへ変換する

Pocketサーバを通じてリクエストークンをアクセストークンへ変換します。

6. OAuth APIを通じてリソースを利用する

OAuth APIを通じてPocketサーバへリクエストを投げることで、リソースを利用することができます。リクエストの際には、コンシューマキーとアクセストークンをPOSTパラメータとして設定する必要があるためお忘れなく。

最後に

上記の手順はPocketのOAuth APIを利用することを前提としていますが、他のサービスでも活用できるかと思います。ぜひ試してみてください。

JavaScriptフレームワーク導入のためVue.jsを使ってみた

2009年当時でのWebアプリではJavaScriptフレームワークがあまり一般的で無く、目下JavaScriptライブラリであるProtoTypeやjQueryを使ってゴリゴリとコーディングを行っていました。ここ最近で久々にWebアプリ開発に戻りましたが、近年では非同期通信の一般化やフロントエンドのリッチ化により、JavaScriptフレームワークを使わないとコーディングが辛くなってきました。そこで、JavaScriptフレームワークを採用するために検証を行うにしました。

Vuejsを選んだ理由

トレンド

栄枯盛衰の激しいIT業界ではどの技術を選定するのか正直悩みどころです。しかも、JavaScriptフレームワークは現時点で確立されたものは存在せず、今だにしのぎを削っています。そこで、Googleトレンドを利用して比較を行い、優劣を測ることにしました。。結果としてはVue.jsは人気の伸びが凄まじく、現時点では他者を圧倒しています。これがVue.jsを選定する大きな要因となりました。

圧倒的じゃないか、Vue.jsは

ドキュメントやサンプル、そして事例の多さ

Vue.jsが既にバージョン2へ改訂されていたこともあってか、既に日本語のドキュメントサンプル、そして事例が揃っていました。やはりトレンドの伸びが凄まじいだけはあります。実際に実装で悩んだ際にも豊富なサンプルと事例を確認することで対応できました。

テンプレート構文

HTMLにVueシンタックスを埋め込むだけで実現できるというシンプルさに感銘しました。将来的な課題であるWEBデザイナーとの共同作業も行えそうです。VueシンタックスについてはAngularJSの思想を強く受け継いだ点のようですが、今回はAngularJSに触れませんでした。

Vue.jsを利用してみた所感

まだまだ小規模開発での検証ではあったのですが、予想外に良く、大いに可能性を感じました。まず気に入った点は双方向データバインディングです。データやイベントとの相互連携もVueシンタックスを利用してシンプルに記述でき、処理ロジックについてもdataオブジェクトとmethodsオブジェクトへ記載するだけなので学習コストもそこまで要求しません。更にコンポーネントを用いれば大規模な開発でも使えそうです。Vueインスタンスを生成することで、スコープ外からデータを変更したりイベントを実行したりするといった柔軟性も備えています。そして何より触っていて楽しく、もっとシンプルな記述で実装できないかと探求したくなるようなフレームワークです。

最後に

個人的にはかなり好みなのですが、本格的に採用するには宣教用や教育用のスライドなど準備が必要です。

Sublime TextのConfluenceプラグインを試してみた

私はSublime Text愛好者です。特にお気に入りはEvernoteプラグインで、ローカルでノートを編集してはクラウドにアップロードするのが日常業務となっています。このプラグインのためだけにSublime Textを利用しているといっても過言ではありません。

さて、社内ではConfluenceを利用していることもあり、何とかSublime Text上で編集できないかどうか思案してところ、Confluenceプラグインなるものを見つけました。どのくらい使えるかどうか、早速試してみました。

ちなみに検証バージョンは1.0.5で、評価は専らEvernoteプラグインとの比較するという形で行っています。

メリット

Sublime Text上で作業できる

最大のメリットはSublime Text上で作成及び編集ができる、ただそれだけに尽きます。実際のところ、Evernoteプラグインの方が使い勝手が良すぎで、色々と足らないところばかり出てきました。

削除ができる

機能的な優位性としては削除できることが挙げられます(Evernoteプラグインは削除機能ありません)。ただ、Sublime Textで頻繁に行うのはページの作成と編集ぐらいなものなので、この機能について個人的な需要はそこまでありません。

デメリット

処理状況が分からない

これは致命的な問題です。ステータスバーに処理状況が表示されないので、処理中なのか完了なのか把握できません。更に問題なのが、作成時には後述するようにメタデータを記述する必要があるのですが、記述内容に誤りがあったとしてもアラートが表示されません。この場合、コンソールで確認しない限り結果を把握する手段はなく、その仕様を知らないユーザから不良品としてのレッテルを貼られてしまいます。

f:id:mmorita44:20170623165315p:plain

コンソールを確認して、初めてエラーに気づく

作成時にはMarkdown Syntaxを設定しなければいけない

作成時にはタブをMarkdown Syntaxで設定しないとエラーとなります。Markdownテキストを扱うからという理屈は分かるのですが、敢えてタブをMarkdown Syntaxで設定する必要はないかと思います。なぜなら、Markdown Syntaxを設定してもMarkdown規則に準拠しない記述も有り得るからです。

ちなみに、EvernoteプラグインではどんなSyntaxでも作成できます。とても親切ですね。

f:id:mmorita44:20170623165512p:plain

Markdown Syntaxでなければエラーアラート、シンセツダナー(棒

作成時にはメタデータを設定しなければいけない

ページ作成時には以下のようなメタデータ必ず記述しなければいけません。記述しなければエラーとなりますが、上述のようにアラートが表示されないため、何故か動作しないと困惑する羽目になります。

<!--
Space: Engineering
Ancestor Title: Home
Title: Post markup to Confluence
-->

また、記述したとしても記述内容に不備がある(例えば記載されたスペースが存在しない)場合はエラーとなります。

ちなみに、Evernoteプラグインではタイトルを入力するフォームとノートブックの選択欄を順に表示してくれます。とても親切ですね。

検索時にスペース名を指定しなければいけない

これは製品仕様かと思いきや、Confluenceの機能の一つであるConfluence Query Language (略してCQL)はスペース名無しでの問合せにも対応します。なので、現状プラグインではそこまで柔軟に検索できない仕様のようです。

ちなみに、Evernoteプラグインではタイトル名のみで検索してくれます。賛否分かれるところですが、私は直近で変更したページを頻繁に編集するため、この仕様は有り難いです。

タイトル名不指定での検索ができない

先ほど出したCQLはタイトル名不指定で直近更新したページを出力してくれるので、現状プラグインではそこまで柔軟に検索できない仕様のようです。

ちなみに、Evernoteプラグインではタイトル名不指定で検索すれば直近更新したページを一覧表示してくれます。とても親切ですね。

取得時はHTMLで出力される

Markdownで作成しても取得時はHTMLで出力されます。これは製品仕様なので仕方がありませんが、それならhtml2textの様なHTMLからMarkdownへの変換器を搭載しても良かったのではないかと思います。どうせMarkdownpython-markdown2を利用してHTMLに変換しているのですから。

f:id:mmorita44:20170623165332p:plain

取得はHTML出力のみ

最後に

ここまで不満ばかりでしたが、エンジニアたるもの文句だけで終えず、改善に努めていきたいです。このプラグインに対しては個人的な需要もありますので、できればフォークして手を加えていきたいと思います。

特選汎用的Javaライブラリ

汎用的なJavaライブラリを特選するならという観点でまとめてみました。

joda-time:joda-time

便利な独自日時型を提供するライブラリ。Java8からはJRE標準ライブラリで同等な機能を持つjava.lang.LocalDateとLocalDateTimeが提供されてますが、 java.lang.Date型への変換が容易なために重宝します。特にHibernateActiveObjectsなどの主要なORMライブラリではjava.lang.Date型を必ず利用するため一緒に用いることが多いです。

org.projectlombok:lombok

Java特有の冗長的な記述をアノテーションを用いることで自動保管してくれるライブラリ。コンパイル時にアノテーションからJavaコードへ変換してくれるため、デプロイするアプリケーションサーバへライブラリを設置する手間や懸念を必要としません。

com.google.guava:guava

Javaの便利な型が揃うライブラリ。Collection系は総じて使用頻度が高いです。

com.google.code.gson:gson

Jsonデータを扱う上で便利なライブラリ。その特性上HTTP通信で用いられるため、HttpClientと一緒に利用します。

org.apache.httpcomponents:httpclient

HTTP通信を行う上で便利なライブラリ。Jsonデータでのやり取りならGsonと一緒に使えば幸せになれます。ちなみに以下はサンプルコード。

    public static void main( String[] args ) {
        try (val httpClient = HttpClients.createDefault()) {
            val request = new HttpPost("<url>");

            List<NameValuePair> postParams = Lists.newArrayList();
            postParams.add(new BasicNameValuePair("name", "any name");
            request.setEntity(new UrlEncodedFormEntity(postParams));

            val response = httpClient.execute(request);
            val content = new Gson().fromJson(EntityUtils.toString(response.getEntity()), Content.class);
        } catch (Exception e) {
            // Error procudure
    }

    /**
     * A content of response
     */
    @AllArgsConstructor
    public class Content {
        public String create_user;
        public String message;
        public String result;
        public String name;
    }

最後に

HTTP通信用のライブラリが汎用化どうかは議論の余地がありますが、WebアプリケーションでもAndroidでもHTTP通信は行うため汎用に含めました。Apache Commonsも使うには使いますが、意識的に使っているのはorg.apache.commons.lang3.tuple.Pairとorg.apache.commons.lang3.StringUtilsぐらいでしょうか。

最近のJava API仕様書生成について

最近のJava API仕様書生成という見地からまとめてみました。

なんでAPI仕様書なのか?

オブジェクト指向にはカプセル化という概念があり、クラスメソッドを呼んでやれば期待する値が返ってくる構造になっています。ただし、引数として何を渡せば良いのか、どのような値が返ってくるのか、異常時にどの様な例外処理が発生するのか等々を事前に把握しておかないと、場当たり的にコードを書き散らすことになります。そこで、きちんとAPIを定義しておき、利用者が無駄なく安心してクラスメソッドを利用できるようにしておくワケです。そのためAPI仕様書が必要なのです。

JavaDocの利用

ここからは現在プロジェクトで利用しているAPI仕様書の生成手順について説明しましょう。

まずは皆さんご存知のJavaDocです。JavaDocフォーマットのコメント元にAPI仕様書を生成します。プロジェクトではからMavenを利用しているため、mvnコマンドから生成するようにしています。

pom.xmlより一部抜粋

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-javadoc-plugin</artifactId>
            <configuration>
                <defaultVersion>${project.version}</defaultVersion>
                <sourcepath>target/generated-sources/delombok</sourcepath>
            </configuration>
        </plugin>
    </plugins>
</build>

API仕様書生成のmvnコマンドは以下の通り。

$ mvn javadoc:javadoc

処理終了後にtarget\site\apidocsへHTMLファイル群が生成されます。sourcepathにてソースコード場所をしている理由については次の文章をご覧ください。

Lombokへの対応

プロジェクトではBeanやDI等の定型記述の簡略化のためにLombokを利用しています。コンパイル時にLombok記述をJavaコードへ変換してくれるため、ビルド先のアプリケーションサーバへLombokライブラリを持っていく手間がかかりません。Javaの開発では必須とも言えるツールです。

ただし、JavaDocで仕様書を生成する場合には、Lombok記述はAPI仕様書の対象とはなりません。そこで、一旦Lombok記述からJavaコードへ変換する処理が必要になります(これを公式ではdelombokと呼ぶ)。そのdelombok済みソースコードJavaDocソースコード場所と指定することで漏れのない正確なAPI仕様書が生成できます。mvnコマンドでコンパイルすれば自動的にdelombokしてくれます。

pom.xmlより一部抜粋

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>delombok</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <addOutputDirectory>false</addOutputDirectory>
                <sourceDirectory>src/main/java</sourceDirectory>
            </configuration>
        </plugin>
    </plugins>
</build>

delombok実行のmvnコマンドは以下の通り。

$ mvn compile

コンパイル終了後にtarget/generate-sources/delombokへdelombok済みソースコードが生成されます。

Swaggerの利用

昨今のWEBアプリケーションでは非同期通信によるサーバサイド処理がメジャーになりました。当然ながらREST APIを設ける場合も多くなり、このような状況から考えてもREST API仕様書を作成しておく方が望ましいです。現在プロジェクトではSwaggerを取り入れています。SwaggaerはAmazon API GatewayやAzure API Managementで採用されているため、ほぼデファクトスタンダードへ成りつつあります。現時点でSwaggerを採用することは無難な手でしょう。有志により公開されたMavenのSwaggerプラグインを用いてREST API仕様書を生成します。

pom.xmlより一部抜粋

<dependencies>
    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-annotations</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>com.github.kongchen</groupId>
            <artifactId>swagger-maven-plugin</artifactId>
            <configuration>
                <apiSources>
                    <apiSource>
                        <springmvc>false</springmvc>
                        <locations>com.shdsd.plugin.label.printer.rest</locations>
                        <info>
                            <title>${project.name} API</title>
                            <version>${project.version}</version>
                        </info>
                        <templatePath>${project.basedir}/src/test/resources/strapdown.html.hbs</templatePath>
                        <outputPath>${project.basedir}/target/generated/document.html</outputPath>
                        <swaggerDirectory>${project.basedir}/target/swagger-ui</swaggerDirectory>
                    </apiSource>
                </apiSources>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

delombok実行のmvnコマンドは以下の通り。

$ mvn compile

コンパイル終了後にtarget/generated/document.htmlが生成されます。templatePathへ配置するファイル群はapi-doc-template/v3.0から取得してください。

最後に

IT技術の流行り廃れが激しいので、ここに記載した内容もしばらく経ったら更新されるかもしれません。

JIRAプラグイン開発方針のまとめ

業務上JIRAプラグイン開発をやっているので、その所感を開発方針という形でまとめてみました。

開発の課題と方針

Atlassianはプラグイン開発についてサポートしないし、公式のドキュメントも充実していない。おまけに、コミュニティも当てにならず、Stack Overflowでお目当てのソリューションを探すこともままならない。そのため、MarketPlaceに上がっているようなリッチなプラグインを開発しようと思えば、独自にフレームワークの解析を行う必要がありかなりの研究コストがかかってくる。おまけに、プラグイン開発で必須なコンポーネント及びモジュール群の機能についても知っておく必要があるので開発要員の学習コストもそれなりにかかる。

このように開発においてかなりの苦労が要求されますが、それでもなお自社の業務仕様に合わせてJIRAを拡張したいという需要はあります。そこで、プラグイン開発する新人向けに開発方針をまとめました。

方針1: リソース管理はREST APIを使う

JIRAのリソースと言ったらユーザ情報やプロジェクト・タスク情報。これらの管理はREST APIで十分です。主だったリソースはREST APIで取得・更新・削除できます。またJQL(JIRA Query Language)を利用すれば、条件に似合ったissue情報を好きなように取得することもできます。自社システムとの連携についてはこれで十分。あとマスタ管理であれば、JIRAのプラグインを作成するよりも別途システムを構築した方が製造及び拡張が容易です。

方針2: 主要なコンポーネント及びモジュールを押えておく

プラグイン開発のメリットは、JIRAのコンポーネントとモジュールを活用して自社の業務仕様に合わせJIRAの機能を拡張できる点です。中でも以下のコンポーネントとモジュールは使用頻度が高く、これらだけ覚えても有用なプラグインが作成できます。

ActiveObjects

独自のDBテーブルを生成します。他システムのマスタデータを取り込むときなどに使います。

EventListener

あらゆるイベントに対応する処理を付加します。

各種Manager系

IssueManagerやUserManagerなどリソース管理を行うコンポーネントです。リソース管理だけならREST APIで十分ですが、他のコンポーネントやモジュール上からリソース管理を行うなら必須です。

REST Plugin

独自のREST APIを生成します。JIRAの画面はフレームワークの制約が大きく、画面上のイベントからサーバ処理を行うにはREST APIを通じた非同期通信しかありません。そういう意味ではプラグイン開発必須のモジュールです。よくActiveObjectsとセットで利用されます。

各種Workflow系

JIRAの最大の利点といえば強力なWorkflowをおいて他にありません。WorkflowモジュールにはConditionとValidator及びPost Functionがあり、要望に応じて柔軟に拡張できます。

方針3: 画面作成は極力行わない

AtlassianにはAUIというフロントサイドフレームワークがあります。AUIにはAtlassianらしいデザインを作成するためのCSSと、Atlassianらしいモーションを実現ためのAJSが含まれます。AJSは単なるjQueryのラッパーではなく独自の関数やオブジェクトも含みます。使いこなせば有用なんですけど、ただでさえ学習コストの高いプラグイン開発のレベルを更に一段高くしてくれます。おまけに、フレームワークに従順するように開発する必要があるため、「あのページにコレ入れて」とか無闇に容認すると実現できずに失敗することになります。一見簡単そうに見えて複雑なのがフロントサイドです。

画面に対する要望は対応しないのがベストです。クライアントにはAtlassianの仕様についてよくよく理解してもらう必要があります(簡単そうなだけに)。それでも画面を作成するというなら、リスクを洗い出した上でその旨をクライアントを合意、後々もめないような手筈を整えておいてください。

最後に

開発できる仲間募集してます。

情熱プログラマー書評「新人の頃に出会いたかった本」

ITエンジニアのお勧めで何度か耳にしていた書物情熱プログラマー ソフトウェア開発者の幸せな生き方」がAmazon Japanで電書化されていたので、早速通読しました。以下その書評です。

新人始めプログラマー皆さんへお勧め

社会へ出たてでまだまだ仕事の要領が掴めない新人プログラマーには打ってつけでしょう。堅い言い回しや哲学的な内容も無い、業務知識もそこまで必要としないので結構理解できるはずです。特に、「今すぐ始めよう」の文章について一度は実践してみてください。「良かったなぁ」で終わるのでなく、今すぐ実践のためのスケジュールを作成することが肝心です。

また、日々の忙しさから自らの研鑽を忘れてしまった社会人にとっても気づきと反省を与えてくれます。皆さん一度は通読して損はありません。

例えがくどい、所感や体験談が長い

文章中でサックスやジャズの例えをよく出してくるのですが、共感できるのは一握りの人だけでしょう。書物は著者の言葉で率直に書くものなので仕方ないのですが、正直くどいです。また、文章は所感や体験談が大部分を占めています。話があっちこっち行ったりしているので、個人的には小見出しつけて分かりやすくして欲しかった。後半は「今すぐ始めよう」だけ読んで何が言いたいのか判断していました。

お勧めの読み方

まずは目次を見て、気になる題目から読み始める。全体を通読するのであれば、「今すぐ始めよう」の文章を読み、その内容の経緯が気になったら導入部の文章を読もう。

メモ書き

私の本書に関するメモ書きを一部公開します。

 本当の意味で何かを習得しようと思ったら、誰かに教えてみることをお勧めする。 (師匠になる 第48頁)

要は習得した内容を自分のものとすることです。自分のものとするにはまず整理する。整理するためには実際に教えるということは最適です。

僕らの業界でも、もっと練習する時間が必要だ。 (一に練習、二に練習 第50頁)

「プロとは、クライアントの要望を実現できる技量を有し、その上で実現可能な案を提示すること」というのが私の持論です。技量は練習でしか身につかない。時間が無い?なら今すぐスケジュールを調整するしかない。1日1時間なら余裕で作れるでしょ。

君がいつも繰り返しコーディングしている処理を1つ選び、その処理に関するコードジェネレータを作成してみよう。 (自動化によって仕事を確保する 第62頁)

プログラマーとして楽することに投資を欠かさないこと。

つきに一度は約束の達成率を調べて、自分の約束の仕方が適切かどうか確認しよう。 (できないことは「できない」とはっきり言う 第99頁)

まずは自覚する事、そして改善する事が重要。