日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

Splatoonの企業対抗戦やってるコミュニティに入ったらすごく楽しかった話

これは Splathon Advent Calendar 2018 - Adventar の9日目の記事です。

なんでもどうぞってことだったのでSplathonの思い出を語ろうと思います。
Splathonってなんだろうとか、コミュニティ楽しそうとか、チーム組んで戦うのが楽しそうってのが伝わったら嬉しいです。

Splathonとは

Splathonという単語の意味はこんな感じらしいです。
最近はコミュニティ名として使われてる印象です。

「スプラソン」(Splathon)とは、スプラトゥーンsplatoon)とマラソンmarathon)を組み合わせた 株式会社Speee発祥の造語で、複数の参加チームが、マラソンのように、 数時間から数日間の与えられた時間を徹してSplatoonに没頭し、戦果を競い合うゲームイベントのことをいいます。

オフライン、もしくはオンラインで企業対抗戦をやったり、
企業関係なくチームを組んで一定期間でリーグ戦を行うなど色んなイベントがあったりします。
どんなイベントがあったりするのか気になる方は、
アドベントカレンダー1日目のkawakuboxさんの記事がよくわかると思うので見てみてください!

kawakubox.hatenablog.com

Splathonとの出会い

参加している人がWeb企業の人が多いためか、
参加してる人がフォロー内にいて、
突如Twitterのタイムラインに #splathon というハッシュタグが流れて来たのがきっかけでした。

羨ましがってる様子です。

おもむろにつぶやいてみたら中に人がいたら招待してもらうといいっぽく、
探してみたらいたのでどうにか招待してもらうことに成功しました。
コミュニティが気になる方は中の人の知り合いを探してみてください!w

参加したイベント

会社のメンバーでいろんなイベントに参加したりしました。

Splathon #7, #8

Splathonはオフラインである会場に集まって競い合うイベントですね。
イメージはSplatoon甲子園のような感じです。

www.youtube.com

Splathon eXtreme - Draft Tournament#1

eXtremeはウデマエXの人が集まって、 すっごい強い人(語彙力)がリーダーになってドラフトしたチームで競い合うイベントです。
ウデマエXになったばっかりでそんなに強くないから選ばれんやろーとか思ってたら選ばれて、
スマブラのムービーで驚愕してるイカちゃんみたいな顔をしながら怯えていました。

www.youtube.com

Splathon Ladder League #1 #Spladder

Ladder Leagueはオンラインのイベントで、
数ヶ月の期間で順位を決めるリーグでした。

全試合録画されててすごいw
最終的な順位は25チーム中7位でした。

#Splathon Ladder League #1 #Spladder - YouTube

Splathon Online League #3

Splathon Online Leagueはsolってよく訳されてるんですが、
(初め全然わからなくてsolってなんだ・・・ってなってました。
エンジョイよりのオンラインのイベントで、
参加したい人を運営の人がいい感じ(語彙力)に割り振って数ヶ月で、
順位を決めるようなイベントです。

チームで戦う楽しさ

コミュニティに入って同じ会社のメンバーでチーム作ったんですが、チームでやるのすごいよかったです。
まずは、チームでやるとみんな次勝つためにどうしたら良いかって考えるようになりました。
自分の立ち回りをもう少しこうしてほしいと言ってもらえたり、
対面が強い前線の味方を活かすために塗り拡げるの優先で動いたほうが良かったなー考えたりなど。

あとは、単に練習という名目でリーグマッチに行くのが単に楽しいです。
(今のチームのAjitoonでは練習として毎週木曜日にリーグマッチに行っています。

さらに、自分が使う武器だけではなく、
チームでの武器の組み合わせを試すというのもすごい楽しいです。
Ajitoonは初めメンバーの3/4のスペシャルがスーパーチャクチのチャクチーズで、
打開とは🙄みたいなチームでしたが、
今は色んな組み合わせが試せてすごい楽しいです。
(一人カーボンローラー固定だけど

Splathon #7, #8やLadder League #1のおかげでそんな楽しみ方を出来ました。
チームを作るきっかけをくれたSplathon、そのチームでプレイするきっかけを作り続けてくれるSplathonに感謝!!
コミュニティの楽しさとチームを組む楽しさが伝わったかどうか怪しいですが、
チームを組んで対抗戦するの本当に楽しいんで、
ぜひ皆さんもチーム組んだりしてみてください!

Splatoon2から始めてウデマエXまで行くときにやったりしたことの備忘録

この記事はSplatoon Advent Calendarの1日目として書かれています。
勢いで作ったら結構埋まっててとても嬉しいですw

adventar.org

なにを書こうか悩んだんですが、
Splatoon2が発売されてからウデマエX行くまでを振り返って、
自分がどうやってウデマエXまで行けたかを書いてみようかなと思います。
ウデマエXを目指す方のなにか参考になれば嬉しい限りです。

今のウデマエと使用武器

普段の使用武器はマニューバ系やシューター系の短距離から中距離のブキを持っています。
今現在のXパワーは2100 ~ 2300強くらいをさまよう、一部ではX底辺と言われたりするくらいのウデマエです。

初めS+0までのとき

初めS, S+0まで行ったときはずっとボールドマーカーを使っていました。
特にルールごとになにか考えることもなくプレイしていた気がしますw
唯一やってたことは率先してオブジェクトに絡むことをしていました。
エリアだったらエリアを塗る。
ヤグラだったらヤグラに乗る。
ホコならホコを持つ。
自分以外がやらなそうだったら自分がやるようにしてたら上がれたような気がします。

A+ ~ S+2あたりをウロウロしてるとき

S+0までは発売から3ヶ月ほどですんなり一度上がれたんですが、
その後立ち回りがわからなくなってきてウデマエが上がったり下がったりするようになりました。
正直ボールドマーカーに限界を感じるようになったのでいろんな武器を使うようにしました。

エリアでは

  • ボールドマーカー
  • スクリュースロッシャー
  • N-ZAP85
  • N-ZAP89
  • ダイナモローラーテスラ
  • バケットスロッシャーデコ
  • スパッタリーヒュー

ヤグラでは

  • ジェットスイーパー
  • ホットブラスター
  • もみじシューター
  • スパッタリーヒュー

ホコでは

  • ボールドマーカー
  • バケットスロッシャーデコ
  • スパッタリー
  • スパッタリーヒュー

アサリでは

  • スプラローラー
  • ホットブラスター
  • デュアルスイーパー
  • スパッタリーヒュー

などを使っていました。
かなり迷走気味ですね。
でも、これをやってよかったなと思うことがありました。
使っていた武器との対面の仕方や、その武器がどこに立ちたくなるかのポジションがわかるようになったことです。
どこに潜伏してそうかとか、どういう行動をあの武器はやられたら嫌かがわかると、
それらの武器に対して優位に対面できると思うので、
いろんな武器を持ってガチマッチに潜ったのはつらかったけど本当によかったなと思います。

S+の数字を上げていったとき

いろんな武器を持っていたんですが、
アメフラシが強いなーと思ってたのと、キル性能が高かったのもあり
スパッタリーヒューに使用武器が固定され始めて、
ようやくS+にも数字がついて落ち着くようになってきました。
その頃ちょうどウデマエXが出るという話が出てきたので、
S+10くらいまでなら頑張りたいなと思ってどうやったらよくなるかを考え始めた時期でした。
そこでやったのが上手い人の動画を見て学ぶということでした。
今考えると、もうちょっと早くやっても良かったんじゃないかなとかよぎりますねw

エリア

まずはエリアですが、
スパッタリーヒューを使っていこうと思ってたのでYoutubeで探したら、
あしんさんという配信者さんがガチエリアでの立ち回りを解説している動画や、
よくやってる試し打ちを動画にされていたのでそれを見てとりあえず丸パクリして徐々にアレンジしていくことにしました。

www.youtube.com

www.youtube.com

エリアの立ち回りの動画を見たとき、
打開とか抑えの考えを一切自分は持ってなかったので、本当に参考になりました。
打開時にちゃんと味方と合わせるというのが大事で、
それさえ出来たらあとはサクサク数字が上がって4種の中で一番はじめにXになりました。
途中でX導入されたので元々強かった人々がいなくなったってのもありそうですがw
あとは試し打ちをちゃんとやったらエイムがかなり良くなって対面も勝てるようになったので、
ちゃんとやると効果出てよかったです。
バスケでもシュート練習しないとシュートはいらなくなるし、
ピアノでも練習しないと指動かないしなーとか思ってやっぱ練習大事だなと思いました。

ヤグラ

ヤグラはS+0に行った後に、様々な武器を使ってAまで落ちてしまい、
その際、もみじシューターを使って這い上がってきたんですが、
塗り拡げてキル武器にキルを取らせて、自分がヤグラに乗って、止めるときは雨をはけば勝てると思ってたので、
特段探さず殺傷能力の上がったスパッタリーヒュー+アメフラシでどうにかしていましたw
デュアルスイーパーカスタムが出た後は更に塗りやすくなったので持ち替えて、
塗りながらヤグラに乗ってアメフラシで止めるという方針でXまで行きました。

ホコ

ホコは結構好きだったんですが、
苦戦してたので探したらメシアはボールドさまという配信者さんの動画を見つけて参考にしてました。

www.youtube.com

この時まで何も考えずホコを進めてたんですが、
ゴールから限りなくホコを遠ざけるとか、どこまではホコを進ませても大丈夫とかそういう考え方を気付かされた動画でした。
どこまでには必ず止める。
無駄に突っ込まないが大事ですね。
ホコ持ちが得意だったこともあり、この考え方のおかげでわりとすんなり上がることが出来ました。
ホコではスパッタリーヒューよりスパッタリーをよく使っていました。

アサリ

アサリはエリアのおかげで周りが見えるようになって特段なにもなく上がってしまったので割愛しますw
武器はデュアルスイーパーカスタムがでて使いやすかったのでずっとデュアルスイーパーカスタムを使っていました。

まとめ

所感としては個人的には

  • ある程度ルールなれるまではひたすら同じ武器を使うとよかった
  • ガチマッチはオブジェクトに絡むようにするとよかった
  • ガチマッチ慣れてきたらいろんな武器をいろんなルールで使ってみるとよかった
  • 立ち回りよくわからなくなってきたら動画を見て真似してみるとよかった

という感じでした!
もしSplatoonやっててなにか悩んだ人の参考にでもなればとても嬉しいです!

Scala製ValidationライブラリのAccordを触るぞい

最近Scalaのコードを書いててフレームワークに付随しないタイプのValidationのライブラリなんか無いかなー
と探していたらAccordというものを見つけたので触ってみた備忘録です。

Accord: A sane validation library for Scala

準備

検証用リポジトリはこちらで、使ったライブラリのversionは0.7.2でした。

github.com

installはbuild.sbtのlibDependenciesに追加する感じですね
書いたbuild.sbtはこんな感じでした

val commonSettings = Seq(
  version := "0.1-SNAPSHOT",
  scalaVersion := "2.12.5",
)

lazy val root = (project in file("."))
  .settings(commonSettings)
  .settings(
    name := "scala validation sample",
    libraryDependencies ++= serverDependencies
  )

val serverDependencies = Seq(
  "com.wix" %% "accord-core" % "0.7.2"

)

Accord概要

Accordのvalidationは特定の型に対するValidatorを定義して、
com.wix.accord.validate関数がそのValidatorを利用してvalidationを行い、
最終的にはResult traitを継承した(?)SuccessかFailureを返すみたいな形みたいですね。
validate関数はimplicit parameterでValidatorを渡せるようになっているので、
スコープ内にValidatorを定義しておけば引数から渡さなくても渡せますね。
明示的に渡したい場合は第二引数(?)に渡してあげれば渡せますね。

Ref: http://wix.github.io/accord/api.html#execution

使ってみた

実際に書いてみたコードはこんな感じでした。
APIサーバとかで使うならJSON形式で゚来たRequest Bodyをなんらかのcase classのオブジェクトにマッピングして、
そのオブジェクトをvalidationするみたいな形にするかなーとか思いながら書いてました。

package com.ru.waka

import com.wix.accord.{NullSafeValidator, RuleViolation, Validator, validate}
import com.wix.accord.ViolationBuilder.singleViolationToFailure
import com.wix.accord.dsl._

object Accord {
  implicit val hogeValidator: Validator[Hoge] = validator[Hoge] { h =>
    h.a is notEmpty
    h.b is in(1, 2)
  }

  implicit val FugaValidator: Validator[Fuga] = validator { f =>
    f.as has size > 0
  }

  implicit val PiyoValidator: Validator[Piyo] = validator { p =>
    p.as is notEmpty
    p.bs is myNotEmpty as "その値"
  }

  /**
    * @see http://wix.github.io/accord/dsl.html#combinators
    */
  def main(args: Array[String]): Unit = {
    println(validate(Hoge(a = "", b = 10)))
    // Failure(Set(a must not be empty, b with value "10" got 10, expected one of: [1, 2]))

    println(validate(Fuga(Nil)))
    // Failure(Set(as has size 0, expected more than 0))
    println(validate(Fuga(Seq(1, 2, 3))))
    // Success

    println(validate(Piyo(Nil, Nil)))
    // Failure(Set(as must not be empty, その値 List() は空じゃだめなんじゃ〜))
    println(validate(Piyo(Seq("a"), Seq(1))))
    // Success
  }

  case class Hoge(a: String, b: Int)

  case class Fuga(as: Seq[Int])

  case class Piyo(as: Seq[String], bs: Seq[Int])

  def myNotEmpty[T <: Seq[_]]: Validator[ T ] =
    new NullSafeValidator[ T ](
      test    = x => x.nonEmpty,
      failure = x => RuleViolation(x, s"$x は空じゃだめなんじゃ〜")
    )
}

感想

  • 😁 Validationの成功失敗、失敗はどの項目がどのルールで失敗したかが返るので基本的なValidationの機能は満たしてる
  • 😁 既存のルールが割と多いので時前で定義せずともわりと使える
  • 😁 困ったら自分でも作れるのでまあ便利
  • 😁 レポジトリのStar数もそれなりにあるし、開発も続いてるし息短くはなさそう
  • 😥 エラーメッセージを日本語にしたいと思ったんだけど、既存のものを変える方法が見つけられてなくて困ってる
    • h.a as "変な値" is notEmpty みたいに定義しても 変な値 must not be empty となるのでメッセージ全体は変えられなかった
    • このあたりはもう少し深掘りしながらissueとかも見ていこうかなと思った

PHPのプロファイリングが出来るblackfireでPOSTリクエストもプロファイルする

以前blackfireを試したんですが、そのときはブラウザでページを開いて、
chrome extentionでプロファイリングしてました。
なのでGET以外のリクエストがプロファイルやりづらく、
もうちょっといいやり方無いかなと思って探してみました。

以前の話
arata.hatenadiary.com

やることはblackfire agentをどこかにインストールして、そこからcurlコマンドで計測するという感じです。
今回自分はMacでやったのでbrewで入れました。
インストール手順はこのあたりです。
configのid, tokenとサーバに設定するid, tokenは異なるので注意が必要です。
blackfire.io

実際にやってみるとこんな感じでした。

$blackfire config
--------------------------------------------------------------
 Welcome to the Blackfire CLI utility configuration assistant
--------------------------------------------------------------

Your Blackfire Client ID and Token are available at:
https://blackfire.io/my/settings/credentials#client

Enter your Client ID: XXX
Enter your Client Token: YYY
------------------------------------------------------------------------------
The following configuration has been updated successfully
/path/to/.blackfire.ini

Thank you for using Blackfire
------------------------------------------------------------------------------

サーバの実装として使ったレポジトリはこちら

github.com

blackfireはcurlコマンドをwrapしてくれるみたいです。
curlでのリクエストを取れればいいんですけど、そんなときに便利なのがchromeのdev toolですね。
こんな感じでリクエストをコピーしてきます。

f:id:arata3da4:20180628173432p:plain

実際blackfireでcurlをwrapして叩いてみました。
GraphのURLはごまかしてます。

# 対象のserver起動
$make compose id=xxx token=yyy                                                                         [master]@(blackfire-with-slim)
docker-compose build
Building web
Step 1/10 : FROM php:7.1.10
 ---> c342f917459a
Step 2/10 : RUN apt-get update
 ---> Using cache
 ---> 8f08514cd607
Step 3/10 : RUN apt-get install -y wget
 ---> Using cache
 ---> 558f46f226ce
Step 4/10 : RUN wget -O - https://packagecloud.io/gpg.key | apt-key add -
 ---> Using cache
 ---> dc02abcab12c
Step 5/10 : RUN echo "deb http://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list
 ---> Using cache
 ---> 947920d5728f
Step 6/10 : RUN apt-get update
 ---> Using cache
 ---> 98aa1854625d
Step 7/10 : RUN apt-get install -y blackfire-agent
 ---> Using cache
 ---> d0725ad5b875
Step 8/10 : COPY ./blackfire.ini /etc/blackfire/agent
 ---> Using cache
 ---> 9a8965d48d25
Step 9/10 : RUN /etc/init.d/blackfire-agent restart
 ---> Using cache
 ---> f6360b5dc8d4
Step 10/10 : RUN apt-get install blackfire-php
 ---> Using cache
 ---> 40f8638aca26
Successfully built 40f8638aca26
Successfully tagged blackfire-with-slim_web:latest
docker-compose up
Starting blackfire-with-slim_web_1 ... done
Attaching to blackfire-with-slim_web_1
web_1  | make: Entering directory '/opt/app'
web_1  | /etc/init.d/blackfire-agent start
web_1  | Starting Blackfire Agent: blackfire-agent.
web_1  | /usr/local/bin/php -S 0.0.0.0:8080 -t web

# 別ターミナルで実行してみます
$ blackfire curl 'http://localhost:8080/hey' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' -H 'Content-Type: application/json' -H 'Accept: */*' -H 'Referer: http://localhost:8080/' -H 'Connection: keep-alive' --data-binary '{"name":"blackfire"}' --compressed
Profiling: [########################################] 10/10
Blackfire cURL completed
Graph URL https://blackfire.io/profiles/XXXXXXX/graph
No tests! Create some now https://blackfire.io/docs/cookbooks/tests
No recommendations

Wall Time     126ms
I/O Wait        n/a
CPU Time        n/a
Memory          1MB
Network         n/a     n/a     n/a
SQL             n/a     n/a

Graph URLで表示されているURLにアクセスするとこんなグラフが見れました。

f:id:arata3da4:20180628173422p:plain

POSTもラクラクプロファイルできて便利!

scalikejdbcを使ってMySQLにクエリを投げるだけのメモ

久しぶりにScalaを触ってMySQLにクエリを投げたいだけなんだけど、
それすらもぱっとは思い出せなかったので備忘録として書いとこうと思います。

scalikedjbc

github.com

検証用レポジトリはこちら。
make run で多分動きます。

github.com

build.sbt

とりあえずおもむろにbuild.sbtにscalikejdbcを追加します。
3系出てたんですね。
長いこと触って無くて知りませんでした。

scalaVersion := "2.12.5"

libraryDependencies ++= Seq(
    "org.scalikejdbc" %% "scalikejdbc" % "3.2.3",
    "mysql" % "mysql-connector-java" % "6.0.6"
)

書いたコードは結局このくらいでした。
localTxの実装を見たらなにかあったらThrowableが投げられるみたいだったのでcatchingで囲むことにしました。
Throwableが投げられたとしても特に何もしなかったらrollbackされなかったので、
投げられたら(Leftが返ってきたら)rollbackするような実装にしました。

package com.ru.waka

import java.time.LocalDateTime

import scalikejdbc.{ConnectionPool, DBSession, NamedDB, SQL}

import scala.util.control.Exception._

object Hello {
  private val connectionSymbol = 'testDB

  Class.forName("com.mysql.cj.jdbc.Driver")

  ConnectionPool.add(connectionSymbol, "jdbc:mysql://localhost/test?characterEncoding=UTF-8", "root", "")

  val repository = new HelloRepository(connectionSymbol)

  def main(args: Array[String]): Unit = {
    val time = LocalDateTime.now().toString
    NamedDB(connectionSymbol) localTx {implicit  session =>
      (
        for {
          _ <- createTable()
          _ <- repository.put(time)
          rs <- repository.fetch()
        } yield rs) match {
        case Right(rs) =>
          session.connection.commit()
          println(rs)
        case Left(th) =>
          session.connection.rollback()
          println(th)
      }
    }
  }

  def createTable()(implicit session: DBSession): Either[Throwable, Boolean] = catching(classOf[Throwable]) either {
    SQL(
      """
        |CREATE TABLE IF NOT EXISTS foo (hello varchar(100))
      """.stripMargin
    ).execute().apply()
  }
}

class HelloRepository(connectionName: Symbol) {
  def put(hello: String)(implicit session: DBSession): Either[Throwable, Int] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |INSERT INTO foo (hello) VALUES (?);
        """.stripMargin
      ).bind(hello).executeUpdate().apply()

  def fetch() (implicit session: DBSession): Either[Throwable, Seq[Map[String, Any]]] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |SELECT hello FROM foo;
        """.stripMargin
      ).map(_.toMap()).list().apply()
}

scalikejdbc.SQLの引数にクエリを渡して、
executeしてapplyすればクエリが走りました。
めでたしめでたし。
implicit parameterってどう使われるのかの理解が浅かったのでこのあたりも参考に読みました。

参考

いちいちsessionを渡さなくてもいい感じに渡してくれるので便利ですね。
(暗黙なのちょっと不安だけど)

PHPのjson_encodeで空オブジェクトを出力する

phpで空オブジェクトを出力したくなって、
おもむろに json_encode([]); とやったら空配列になってしまいました。

$php -a
Interactive shell

php > echo json_encode([]);
[]

さてどうしたものかと思ってふと浮かんだstdClassを突っ込んでみました。
そしたら空オブジェクトがおもむろに表示されました。

php > echo json_encode(new stdClass());
{}

もしかしてオプションある?と思って調べてみたらありました。

http://php.net/manual/ja/json.constants.php

php > echo json_encode([], JSON_FORCE_OBJECT);
{}

php最高!めでたしめでたし。

API BlueprintとdrakovとdreddでAPIドキュメントを書きつつモックサーバを立ててさらにテストを走らせる

タイトルの通りのことをやってみました。
どんな時にテストがコケるか等の精査が出来てないのでまた続きを書くことになりそうですが、
とりあえずやってみたメモです。

API Blueprint?

API Blueprintはmarkdown形式でドキュメントを書けるweb APIドキュメンテーションを書く用の言語ですかね。

API Blueprint | API Blueprint

この形式で書いて別のツールで、モックサーバを起動したりテストを走らせたり出来るみたいです。

API Blueprint Tools | API Blueprint

drakov?

drakovはblueprintの形式で書かれたファイルを利用してモックサーバを起動できるツールです。

github.com

API Blueprintとでググるapi-mockというものがよく出てきたんですが、
最近メンテされてないような雰囲気があり使うのはやめました。

MacOSでビルドが出来ずこのissueにたどり着き、

github.com

このissueにたどり着いて、よし、別のを探そうとなりました。

github.com

dredd?

dreddはblueprint形式で書かれたファイルを利用して、
特定のエンドポイントに対してその仕様になっているかをテストしてくれるツールです。

github.com

ドキュメント

Dredd — HTTP API Testing Framework — Dredd latest documentation

やったこと

API Blueprintの適当なAPIドキュメントを書いて、
drakovでモックサーバを起動して、 dreddでphpで実装したサーバに対してテストを投げてみました。

ソースコードはこのあたりに置きました。
make server/mockでモックサーバが起動し、
make testでdreddのテストが走ります。
どちらも利用前にmake installを走らせる必要があります。
(makeで依存書けるのに忘れてた。)

github.com

上では触れてないのですが、
make documentで aglioというツールを利用したいい感じのドキュメントを表示することができます。

github.com

モックサーバの起動

api.apibというファイルでとても雑なドキュメントファイルを作りました。
/api/user?id=1 のようなエンドポイントを叩くとjsonでResponseを返してくれます。

FORMAT: 1A

# テストAPIドキュメント

## ユーザ一覧を出力する [/api/user?id={id}]

### user_detail [GET]

+ Parameters
    + id: 1 (number)


+ Response 200 (application/json)

        [
          {
            "id": "1",
            "first_name": "田中",
            "last_name": "太郎"
          }
        ]

make server/mockでdrakovを実行するとこんな感じになります。
別のシェルからcurlを叩いたらちゃんと定義したレスポンスが返ってきました。

$make server/mock
npm run mock-server

> hello-api-blueprint@1.0.0 mock-server /Users/a-tanaka/Documents/Ghq/github.com/ara-ta3/hello-api-blueprint
> drakov -f ./api.apib --watch

[INFO] No configuration files found
[INFO] Loading configuration from CLI
   DRAKOV STARTED
[LOG] Setup Route: GET /api/user user_detail
   Drakov 1.0.4      Listening on port 3000
 FILE SPY   ACTIVE
[LOG] GET /api/user?id=1
[MATCHING] by url pattern: /api/user MATCHED
[DRAKOV] GET /api/user?id={id} user_detail

# 別のシェルから
$curl 'localhost:3000/api/user?id=1'
[
  {
    "id": "1",
    "first_name": "田中",
    "last_name": "太郎"
  }
]

便利そう!(小並感

テストを特定のエンドポイントに対して走らせる

上に書いたapi.apibをそのまま利用します。
サーバの実装にはこんなファイルを用意しました。
php便利ですね。

main.php

<?php

header("Content-Type: application/json");

echo json_encode([
    [
        "id"=> 2,
        "first_name"=> "田中",
        "last_name"=> "太郎"
    ]
]);

dredd用の設定ファイルはこんな感じになってます。
serverの項目にサーバを起動するコマンドを書いてあげました。
make serverは php -S 127.0.0.1:8080 main.php のコマンドをwrapしていて、
どのリクエストが飛んでもmain.phpの出力を表示してくれます。

dry-run: null
hookfiles: null
language: nodejs
sandbox: false
server: make server
server-wait: 3
init: false
custom: {}
names: false
only: []
reporter: null
output: []
header: []
sorted: false
user: null
inline-errors: false
details: false
method: []
color: true
level: info
timestamp: false
silent: false
path: []
hooks-worker-timeout: 5000
hooks-worker-connect-timeout: 1500
hooks-worker-connect-retry: 500
hooks-worker-after-connect-wait: 100
hooks-worker-term-timeout: 5000
hooks-worker-term-retry: 500
hooks-worker-handler-host: 127.0.0.1
hooks-worker-handler-port: 61321
config: ./dredd.yml
blueprint: api.apib
endpoint: 'http://127.0.0.1:8080'

実際にテストコマンドを実行してみました。
成功パターンだとつまらないので、
main.phpからfirst_name, last_nameの項目を削除して、テストをこけさせてみました。

<?php

header("Content-Type: application/json");

echo json_encode([
    [
        "id"=> 2,
    ]
]);
# 成功パターン
$make test
npm run dredd

> hello-api-blueprint@1.0.0 dredd /Users/a-tanaka/Documents/Ghq/github.com/ara-ta3/hello-api-blueprint
> dredd

info: Configuration './dredd.yml' found, ignoring other arguments.
info: Starting backend server process with command: make server
info: Waiting 3 seconds for backend server process to start
php -S 127.0.0.1:8080 main.php
info: Beginning Dredd testing...
pass: GET (200) /api/user?id=1 duration: 53ms
complete: 1 passing, 0 failing, 0 errors, 0 skipped, 1 total
complete: Tests took 56ms
make[1]: *** [server] Terminated: 15
info: Backend server process exited

# main.phpから削ったあとのパターン
$ make test
npm run dredd

> hello-api-blueprint@1.0.0 dredd /Users/a-tanaka/Documents/Ghq/github.com/ara-ta3/hello-api-blueprint
> dredd

info: Configuration './dredd.yml' found, ignoring other arguments.
info: Starting backend server process with command: make server
info: Waiting 3 seconds for backend server process to start
php -S 127.0.0.1:8080 main.php
info: Beginning Dredd testing...
fail: GET (200) /api/user?id=1 duration: 39ms
info: Displaying failed tests...
fail: GET (200) /api/user?id=1 duration: 39ms
fail: body: At '/0/first_name' Missing required property: first_name
body: At '/0/last_name' Missing required property: last_name

request:
method: GET
uri: /api/user?id=1
headers:
    User-Agent: Dredd/5.1.4 (Darwin 16.7.0; x64)
    Content-Length: 0

body:



expected:
headers:
    Content-Type: application/json

body:
[
  {
    "id": "1",
    "first_name": "田中",
    "last_name": "太郎"
  }
]
statusCode: 200


actual:
statusCode: 200
headers:
    host: 127.0.0.1:8080
    date: Thu, 22 Mar 2018 20:39:44 +0900
    connection: close
    x-powered-by: PHP/7.1.4
    content-type: application/json

body:
[
  {
    "id": 2
  }
]



complete: 0 passing, 1 failing, 0 errors, 0 skipped, 1 total
complete: Tests took 42ms
make[1]: *** [server] Terminated: 15
info: Backend server process exited
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! hello-api-blueprint@1.0.0 dredd: `dredd`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the hello-api-blueprint@1.0.0 dredd script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/a-tanaka/.npm/_logs/2018-03-22T11_39_44_687Z-debug.log
make: *** [test] Error 1

エラー内容がわりと豊富で便利そうです。

まとめと感想

  • API Blueprint、色んなツールが存在して便利そう
  • API Blueprint形式のドキュメントを書いて、フロントエンドの開発時にモックサーバを立てて、サーバサイドにはテストを流すことができそうで便利そう
  • どこまでテストが信頼できるかの調査が必要そう
  • markdownとはいえ、独自言語なのでチームメンバー全員が覚えたりするの大変かも

もう少し使ってみて色々試していけたらなと思います。