JAX-RS/Glassfish/Swaggerでお手軽にはじめるAPIドキュメンテーション
こんにちは!
刺すような暑さが多少は和らいできて助かりますね。。。
さて、継続的インテグレーションの続編、を書く前に。
既存のAPIにほんのちょっと手を加えるだけで、
見た目もきれいで触って試せるドキュメントを簡単に作成できました。
そういう技術がいくつか出てきているようですが、自分で試したのは初めてだったので、
ハマったポイントなども併せて、こちらで紹介していきます。
Swagger Core Library
今回使用したライブラリです。
The goal of Swagger™ is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.
ということで、
- 言語の種類に依存せず
- 人間にもコンピュータにも分かりやすい形で
REST APIへのインタフェースを提供してくれることを意図したライブラリです。
人間がAPIを理解するとき、ソースコードを読んだり、あるいはWikiとかにまとめたドキュメントを読んだりすると思いますが、
という問題は往々にして起こります。
そのような問題に対して、他にも以下のようなライブラリやサービスがソリューションを提供してくれていますが、
今回はひとまず、こちらの Swagger Core Libraryを試してみました。
Swagger UI
Swagger Core Libraryで作成したAPIの情報を、ブラウザに見やすく表示してくれるライブラリ。
特徴的なのは、"Try it out!"でcurlコマンドが見れたり、実際のレスポンスが見れたりするところ。
コードを見なくても、
- 「ちゃんと4+3=7できてる!」
- 「というかそれ以前にAPIがきちんと動いてる!」
のを確認できるのは便利ですね。
環境
今回は、
こんな環境で試してみました。
pom.xmlにSwaggerの依存を追加
JAX-RS 2.xのバージョンに合わせて、swagger-jersey2-jaxrsを選択します。
サンプルアプリ作成時の最新は
http://mvnrepository.com/artifact/io.swagger/swagger-jersey2-jaxrs/1.5.0
なので、pom.xmlに以下のように
<dependency> <groupId>io.swagger</groupId> <artifactId>swagger-jersey2-jaxrs</artifactId> <version>1.5.0</version> </dependency>
依存を追加します。
Swaggerの設定と初期化、resourcesを追加
ApplicationConfig.javaの概略です。
import io.swagger.jaxrs.config.BeanConfig; @ApplicationPath("webresources") public class ApplicationConfig extends Application { // "simple.maven.glassfish.jaxrs.resource" private static final String RESOURCE_PACKAGE = SimpleResource.class.getPackage().getName(); public ApplicationConfig() { BeanConfig beanConfig = new BeanConfig(); beanConfig.setTitle("simpleMavenGlassfishJaxrs"); beanConfig.setDescription("A simple Maven Glassfish JAX-RS project."); beanConfig.setVersion("1.0.2"); beanConfig.setSchemes(new String[]{"http"}); beanConfig.setHost("localhost:8080"); // ex. "localhost:8002" beanConfig.setBasePath("/simpleMavenGlassfishJaxrs/webresources"); // ex. "/api" beanConfig.setPrettyPrint(true); beanConfig.setResourcePackage(RESOURCE_PACKAGE); // ex. "io.swagger.resources" beanConfig.setScan(true); } @Override public Set<Class<?>> getClasses() { Set<Class<?>> resources = new java.util.HashSet<>(); addRestResourceClasses(resources); // enable Swagger resources.add(io.swagger.jaxrs.listing.ApiListingResource.class); resources.add(io.swagger.jaxrs.listing.SwaggerSerializers.class); return resources; } private void addRestResourceClasses(Set<Class<?>> resources) { ... } }
こちらのリンクに沿って、Applicationをextendsしているクラスで以下の設定を行います。
- コンストラクタで基本情報の初期設定
- io.swagger.jaxrs.listing.* の2クラスを追加
web.xmlを使った方法など、別の方法もあるので、上記リンクから辿ってみてください。
アノテーションを追加
SimpleResource.javaクラスの概略です。
@Path("/simple") @Api(tags = {"simple"}) public class SimpleResource { @GET @Path("/hello/{message}") @ApiOperation(value = "Hello Message API", notes = "Append 'Hello, ' before the message.", response = HelloMessage.class) public HelloMessage helloMessage(@PathParam("message") String message) { HelloMessage helloMessage = new HelloMessage(); helloMessage.setMessage("Hello, " + message); return helloMessage; } .... }
- SimpleResourceクラス全体に@Apiを付ける
- ドキュメントを作成したい各エンドポイントに、@ApiOperationを付ける
のが最低限の構成のようです。
確認
http://localhost:8080/simpleMavenGlassfishJaxrs/webresources/swagger.json
にアクセスして、自分のAPIの情報が見れていたら成功です。
{ "swagger" : "2.0", "info" : { "description" : "A simple Maven Glassfish JAX-RS project.", "version" : "1.0.2", "title" : "simpleMavenGlassfishJaxrs" }, "host" : "localhost:8080", "basePath" : "/simpleMavenGlassfishJaxrs/webresources", "tags" : [ { "name" : "simple" } ], "schemes" : [ "http" ], "paths" : { "/simple/hello/{message}" : { "get" : { "tags" : [ "simple" ], "summary" : "Hello Message API", "description" : "Append 'Hello, ' before the message.", "operationId" : "helloMessage", "parameters" : [ { "name" : "message", "in" : "path", "required" : true, "type" : "string" } ], "responses" : { "200" : { "description" : "successful operation", "schema" : { "$ref" : "#/definitions/hello message" } } } } }, "/simple/path_param_addition/{op1}/{op2}" : { "get" : { "tags" : [ "simple" ], "summary" : "Path Param Addtion API", "description" : "Adds two numbers.", "operationId" : "pathParamAddition", "parameters" : [ { "name" : "op1", "in" : "path", "required" : true, "type" : "integer", "format" : "int32" }, { "name" : "op2", "in" : "path", "required" : true, "type" : "integer", "format" : "int32" } ], "responses" : { "200" : { "description" : "successful operation", "schema" : { "$ref" : "#/definitions/path param result" } } } } }, "/simple/path_param_division/{op1}/{op2}" : { "get" : { "tags" : [ "simple" ], "summary" : "Path Param Division API", "description" : "Divide the first number by the second number.", "operationId" : "pathParamDivision", "parameters" : [ { "name" : "op1", "in" : "path", "required" : true, "type" : "integer", "format" : "int32" }, { "name" : "op2", "in" : "path", "required" : true, "type" : "integer", "format" : "int32" } ], "responses" : { "200" : { "description" : "successful operation", "schema" : { "$ref" : "#/definitions/path param result" } } } } } }, "definitions" : { "hello message" : { "type" : "object", "required" : [ "message" ], "properties" : { "message" : { "type" : "string", "description" : "message" } } }, "path param result" : { "type" : "object", "required" : [ "result" ], "properties" : { "result" : { "type" : "string", "description" : "result" } } } } }
よさそうな雰囲気ですね。
Swagger UI
続いて、さっきのswagger.jsonをもとにドキュメンテーションのUIを作ります。
特別な設定は必要なく、
- https://github.com/swagger-api/swagger-ui をclone
- distディレクトリの中身をまるごとホスト
- 例えばhttp://localhost:8080/swagger-ui-dist など、別プロジェクト
などが分かりやすいかと思います。
dist内のindex.htmlをブラウザで開いても大丈夫そう。
スクリーンショット
http://localhost:8080/swagger-ui-dist
にアクセスして、
最上部にあるAPIのURL欄に自分のswagger.jsonまでのURLを入れると、記事冒頭のスクリーンショットが見られます!
はまった点
と、ここまでスムーズにいけば良いのですが、
自分の場合は、swagger.jsonがスカスカになるという問題がありました。
{"swagger":"2.0","info":{"version":"1.0.2"},"host":"localhost:8080/simpleMavenGlassfishJaxrs/webresources","basePath":"/simple","schemes":["http"]}
これは
Swaggerの設定と初期化、resourcesを追加
のところで、サンプルをコピペしていたのが原因だったので、
beanConfig.setResourcePackage("io.swagger.resources");
上の手順にあるように、きちんと自分のリソースクラスを指定したのですが、
private static final String RESOURCE_PACKAGE = SimpleResource.class.getPackage().getName(); .... beanConfig.setResourcePackage(RESOURCE_PACKAGE);
今度はアプリケーション自体がGlassfishにデプロイできなくなるはめに。
java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.AnnotationIntrospector.findPropertyIndex(Lcom/fasterxml/jackson/databind/introspect/Annotated;)Ljava/lang/Integer; at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:372) at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:151) at io.swagger.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:85) at io.swagger.jackson.ModelResolver.resolveProperty(ModelResolver.java:131) at io.swagger.jackson.ModelResolver.resolveProperty(ModelResolver.java:93) at io.swagger.converter.ModelConverterContextImpl.resolveProperty(ModelConverterContextImpl.java:65) at io.swagger.converter.ModelConverters.readAsProperty(ModelConverters.java:58) at io.swagger.jaxrs.Reader.parseMethod(Reader.java:768) at io.swagger.jaxrs.Reader.read(Reader.java:286) at io.swagger.jaxrs.Reader.read(Reader.java:169) at io.swagger.jaxrs.Reader.read(Reader.java:146) at io.swagger.jaxrs.config.BeanConfig.setScan(BeanConfig.java:170) ....
NetBeansでアプリケーションのDependencyを確認してもjackson-databind-2.4.2.jarが入っているし、このバージョンではfindPropertyIndexメソッドもきちんと実装されているのに・・・?
結果的には、実はアプリケーションの問題ではなかったので、
Glassfishで使われているjacksonのバージョンが古いのでそれを新しくすることで問題が解決しました。
おわりに
新規のアプリからでも、既存のアプリからでも、
手間をかけずにお手軽にAPIドキュメントを作成して、楽しく開発しましょう!
Git, Maven, Jenkins, GlassFishを使った継続的インテグレーション(CI) (1)
こんにちは。
今日は、プライベートで最近試している開発環境整備の一環として、
Jenkinsを使った自動テスト・ビルドについて書きたいと思います。
What is CI?
Continuous Integration(継続的インテグレーション)
1度限りもしくは数回限りではなく、継続的に小まめにビルドを実行していくプラクティス
(http://www.atmarkit.co.jp/ait/articles/1309/04/news022.html)
Merits
ここも、上記(http://www.atmarkit.co.jp/ait/articles/1309/04/news022.html)の引用ではありますが・・・。
- 想定外の状況が起こったときに、素早く検知できる
- 仕込んでしまったバグを即座に検知できる
- 開発者の環境依存の問題を検知しやすくなる
- 「私の環境では動くけど・・・」
- ビルドが属人化せずに画一的になりやすい
- 「◯◯さんがビルドしたら失敗/成功した」
こういう状況に思い当たる節のある人も、少なくないのではないでしょうか・・・。
とはいえ
- 導入が面倒そう
- 一部のメンバーだけで利用してもOK
- 手動ビルド・テストと組み合わせてもOK
- まずは簡単なところから
- ex. ビルドエラーが起きた場合はコミット者にメールを通知する
そうですね。できるところからはじめたいものです。
Sample development flow試してみました
最終的には、仕事で関わっているプロジェクトに還元したいのですが、
まずは全体像をつかむために、最小限のサンプルアプリを動かすことにします。
Environments
- ローカル開発環境: MacBook Pro
- サーバ: AWS EC2 (=> のちに社内サーバに置き換えたい...)
- VCS: Git
- サンプルアプリ: AngularJS, Java (JAX-RS)
- 依存管理: Maven
- アプリサーバ: Glassfish
- CIツール: Jenkins
- 開発フロー: GitHub flow (http://qiita.com/tbpgr/items/4ff76ef35c4ff0ec8314)
開発フローは、masterから機能ごとにブランチを切るGitHubフローにしてみました。
git-flowは少し複雑すぎる印象を受けたので・・・。
構成図
こちらのサイト(http://qiita.com/hiroshik1985/items/6433d5de97ac55fedfde)より引用
サンプルアプリでは、RDSにもアクセスしていないし、replicationも実はしていませんが(笑)
ELB経由でEC2インスタンスにアクセスします(図の左半分)。
簡単のため、このEC2インスタンス1つに、JenkinsもGlassfishも載せています。
demoの流れ
- 説明的な名前のブランチをmasterから作成する (add-two-number-division)
- 作成したブランチでローカル開発/プッシュ
- Pull Request を作成
- 自動テストNG (11/2 = 5?)
- テストの成功数、coverage、バグ温床、スタイルの問題、を指摘してくれる
- 再度、ローカル開発
- 再度、プッシュ
- 自動テストNG
- 再度、ローカル開発/プッシュ
- 自動テストOK
- masterへマージ
- なるべく早くデプロイ
準備
サンプルプロジェクトを準備
JAX-RSを使ったREST APIと、それを表示するためのフロントエンドをAngularJSでコーディングしました。
仕様は・・・見ての通り、超カンタンにしてます。
自動テストの確認もしたいので、JUnitでREST APIの単体テストも作っておきます。
AWSの設定
基本的に上記サイト (http://qiita.com/hiroshik1985/items/6433d5de97ac55fedfde) に従って設定しました。
Jenkinsのインストール
ローカルからEC2インスタンスにログインし
ssh -i ~/.ssh/aws/[キーペアファイル… ex. xxx.pem] ec2-user@[Public IP/Elastic IP… ex. 5X.XX.XXX.XX]
Jenkins公式 (http://pkg.jenkins-ci.org/redhat/) に従ってインストールします。
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key (sudo) yum install jenkins
Glassfishなど他のアプリとかぶらないポート(例えば9696)にするには、
ls -ltr /etc/sysconfig/jenkins vi /etc/sysconfig/jenkins ============================== JENKINS_PORT=“8080” ↓ JENKINS_PORT=“9696” ==============================
ポート変更できたら、
# Jenkinsのサービスを起動 sudo service jenkins start # (restart, stopもある) # 自動起動の設定 sudo chkconfig jenkins on # ステータス確認 sudo service jenkins status # 最新化 sudo yum update
ELB経由でEC2上のJenkinsにアクセスできるように、AWSコンソールから設定します。
# 本来はSSLでやった方がいい気がしますが・・・ Security Groups test-web-elb ※任意のIP→ELBに、ポート9696でアクセスさせる Custom TCP Rule TCP 9696 0.0.0.0/0 test-web ※ELB→webは、VPC内アクセスを許可する Custom TCP Rule TCP 9696 10.0.0.0/16 Load Balancers - Listeners ※ ELBからEC2インスタンスへ繋ぐ HTTP 9696 → HTTP 9696
最後に、ブラウザからJenkinsのホーム画面にアクセスできたらOK!
http://[ELBのURL]:9696/
こちらのリンク (http://dev.classmethod.jp/cloud/aws/jenkins_on_ec2/) などを参考に、Jenkinsのセキュリティを設定しましょう。
Glassfishのインストール+warデプロイ
公式サイト (https://glassfish.java.net/download.html#gfoseTab) から、glassfish-4.1-web.zip をローカルにダウンロードします。
インストールは自分はこちらの手順 (http://qiita.com/digdagdag/items/4d26b477bfa3c51771f8) などを参考にしました。
ちなみに、「ローカル以外からGlassFish共通操作画面に接続するには、管理者(admin)パスワードを設定しSSLを有効にする必要がある。」(http://upstart.jp/blog/?p=309)
そうです。
SSLエラーが出たので、Elastic Load Balancing の SSL 証明書を作成 (http://docs.aws.amazon.com/ja_jp/ElasticLoadBalancing/latest/DeveloperGuide/ssl-server-cert.html)。
SSL connection error Unable to make a secure connection to the server. This may be a problem with the server, or it may be requiring a client authentication certificate that you don't have.
再起動して、デフォルトドメインのdomain1が起動中なのを確認します。
sudo bin/asadmin restart-domain
sudo bin/asadmin list-domains
最後に、サンプルアプリのwarをデプロイして、開発の準備は完了です。
開発フロー
とここまで書いたところで、肩が凝ってきてしまったので、
今日は一旦筆を置こうと思います。
続編では、「demoの流れ」の部分で書いた開発フローを
自作自演で(笑)試してみようと思います。
それでは、よい週末を!
応用情報技術者試験に合格しました!
はじめまして。tsumiki_brickです。
4月に受験した応用情報技術者試験の合否が、つい昨日公開されました。
https://www.jitec.ipa.go.jp/1_11seido/ap.html
平成27年度春期の試験に無事合格することができたので、
今後受験する方の参考になるような記事を書ければと思います。
目次
- 受験の動機
- 使用した素材
- 参考書
- Webサイト
- 過去問
- 勉強の流れ
- Tips
- おわりに
受験の動機
- 2011年の特別試験
大学で情報系学科に進み、一通り知識を得ていた(つもりだった)こともあって、
腕試しのつもりで(基本情報を飛ばして)受験してみました。
・・・午前は8割近く得点するも、午後は50点台後半で惜敗。
- 2015年の春試験
時は流れ、いつの間にか都内の某IT系企業に入社。
2015年に入った冬休み頃、ふとAPのことを思い出し、
あの試験を攻略しておきたいという気持ちで再受験しました。
APの謳い文句である
「高度IT人材となるために必要な応用的知識・技能をもち、高度IT人材としての方向性を確立した者」
って自分の手が届く範囲になったのかな、というのも興味がありました。
・・・合格できました!
使用した素材
参考書
- 応用情報技術者 スーパー合格本2011(リンクは2013年版)
午前問題の部分だけ使いました。
分量が多めですが、試験の全体像を把握するのに適している本だと感じました。
分からない点を調べる「辞書」としても使えそうです。
(+) 要所要所で解説が丁寧。
(-) 誤植が多い。答えを隠さないと見えてしまう。
ポケットスタディ 応用情報技術者[第2版](情報処理技術者試験)
- 作者: 村山直紀
- 出版社/メーカー: 秀和システム
- 発売日: 2012/12
- メディア: 単行本
- この商品を含むブログ (1件) を見る
こちらも、午前問題の部分だけを使用。
教科書的な本を使って基本を一通り理解した後の午前対策に役立ちました。
(+) コンパクトなので混雑した電車の中でも使いやすい。
(-) 疑問点の解消にはwebや他の文献を参照する機会が多くなる。
- 応用情報技術者 午後問題の重点対策2012(リンクは2015年版)
2015 応用情報技術者午後問題の重点対策 (午後問題対策シリーズ)
- 作者: 小口達夫
- 出版社/メーカー: アイテック
- 発売日: 2014/12/12
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
名前の通り、午後試験の対策本です。
他の方々のブログで評判が良かったので購入してみましたが、とても役に立ちました。
(+) 解説が非常に丁寧。テーマが毎回異なる午後問題に対応できる「考え方」重視の構成。
(-) 強いて言えば、既に知識のある人には冗長かもしれないコラム
Webサイト
- 応用情報技術者試験.com
解説も丁寧で、スマホ対応もしていて使いやすかったです。
強いて言えば、問題ページから一覧ページに戻るとき、まえ見ていた場所に戻ってくれると便利かも。
過去問
H23-H26あたりを過去数年分解きました。
勉強の流れ
スーパー合格本を解く
↓
ポケットスタディで午前の勉強
↓
『午後問題の重点対策』を信じて解き始める
↓
過去問
↓
試験当日
短い時間で効率よい合格を目指すなら、
他の方々もオススメしているように、まず過去問を時間通りに解いてみて、
自分の勉強すべき分野を把握するのがいいかもしれません。
自分は、2011年に午後落ちしてからの2度目の受験でした。
4年も間が空くと、理解していたはずの事項がほとんど頭から抜けていたので、
ウォームアップの意味でも参考書を一通りさらうことから始めました。
『午後問題の重点対策』は、
「平日の帰宅後に1問以上解く」というのが、自分の中でいいペースメーカーになっていたように思います。
Tips
- スーパー合格本(参考書)を一通りやらない
自分が体験した上で思ったのですが、まずは参考書を一通りやってから問題演習に、という方法は、
結果的にはあまり良くなかったのかもしれません。
そもそも、試験に事実上出題されない(うえに実務でも大して役に立たない)事項も多く載っています。
「問題解く→解説を理解する→分からないところをwebや参考書で調べる」
この流れの方が、効率的だと感じました。
- まとまった時間を何度か作る
→特に午後試験に関しては、制限時間内に問題を解き切ることが大事になります。
本番と同じ時間で(できれば、本番通り眠気に襲われやすい午後一番に)問題演習したり、
足りていない知識を集中して詰め込んだりする時間を作れると、
合格までの道のりがグッと楽になると思います。
- 午後問題で解答する分野を絞り込む
APほど出題範囲が広い試験だと、どうしても自分の苦手な分野からの出題も増えてきます。
午後試験では、11問中、1問必須**、2問から1問選択必須*、8問から4問選択でした。
本番の試験で問題選択に多くの時間を割いてしまうのはもったいないので、
「本命の分野」、「本命が難しかったら解く分野」、「おそらく解かない分野」の見当を事前につけるといいかもしれません。
自分の場合は、以下のようにある程度の目処を立てていました。
○「本命の分野」
情報システム開発
△「本命が難しかったら解く分野」
×「おそらく解かない分野」
組込みシステム開発(なじみがなく、公式を覚えるのも面白くなかった)
システム監査(規格や標準を覚えるのが楽しくなかった)
- 午前試験で途中退出する
APは午前と午後、合わせて5時間の長丁場です。
合格点を取れると確信できたら、さっさと会場を出て、
休憩や午後試験の対策に時間を使う方がいいと思います。
会場近くのレストランも早ければ早いほど混みにくいというメリットもあります。
おわりに
以上、個人的な体験談でした。
「高度IT人材となるために必要な応用的知識・技能をもち、高度IT人材としての方向性を確立した者」になれたかと言えば、正直怪しいですが、
合格を機に、具体的な技術や専門的な知識を身につけていこうというモチベーションは上がりました。
もし気になる部分があれば、参考にしてみて下さい!