B-Teck!

お仕事からゲームまで幅広く

【雑記】29歳になりました。

さて、まぁ掲題の通りなんですが、29歳になりました。
(この記事は予約投稿なので書いているときはまだ28ですが) ついに20代最後の歳ですね。

前置き

元号が令和に切り替わり、GWも折り返しを過ぎちゃいましたね。
私は連休中、Androidの勉強をしたり、普段できていない部屋の片付けをしたりしていました。
本当は最近一番ハマっているストVもやりたいんですが、なかなかまとまった時間が取れてなくて…
(IDはbeatbeat-djamです!フレンド募集してます!)

近況報告

近況ですが、

  • 仕事とかプログラミングとか
    500人未満くらいの規模の自社サービスの会社で、
    アプリのサーバーサイドをメインにいくつかのサービスを持たせてもらってます。
    毎日Kotlinが書けて楽しい!
    今年は未経験領域への挑戦として、Android勉強してアプリリリースまでしようと思ってます。
    できるといいなぁ。
    スキルセットその他の話はProfileを参照くださいな。

  • 私生活
    妻と喧嘩したり仲直りしながらも、なんとかうまくやってこれています。
    転職を機に前職より少し忙しくなったので、家庭の時間が少なくなっているのがネックです…。
    母子家庭の一人っ子、かつ大学以来一人暮らしだった自分が人と暮らすのはなかなか容易ではなく、
    今でも妻に迷惑をかけることしきりです。改善していきたいですね…。
    あとは相も変わらず金欠です。奨学金ェ…

といった感じです。

振り返りとか

思えば20代後半は決断の時期でした。
今まで人に流されて生きてきた自分が、結婚・転職と人生を変える決断を二度もしています。
どちらもいい選択だったと思っているし、決断できてよかったなと思っています。
これからの一年が30代前半を決める事になっていくと思うので、
この気持ちを一年後も持っていられるように努力を続けていきたいですね。

何はともあれ、この記事を見て頂いてる方々と結ばせていただいたご縁と共に、
また一年頑張っていこうと思っています。
引き続きいろいろご迷惑をおかけすると思いますが、仲良くしてくださいね。

ぷれぜんとこ〜な〜

以下お約束で置いているだけですがプレゼントコーナーです。

JSONからJSON Schemaを生成してYAMLに変換する

YAMLで書いてるSwaggerの定義に実装済みのAPIを記述したいが、
レスポンスの定義を手で書くのはしんどい…みたいなときに、
実際に返却しているJSONから生成できれば便利では!?と思ってやってみた。

TL;DR

  • QuicktypeでJSONからJSON Schemaを生成
  • json2yamlでJSON Schemaをyamlに変換
  • Swaggerで読み取れて便利

手順

不要そうなところは各自適宜飛ばしてください。

Quicktypeのインストール

# quicktypeインストールのための手順
# Homebrewインストール
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# node.js(npm)インストール
brew install nodebrew
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
nodebrew install-binary latest # 必要に応じて変えてください
# quicktypeインストール
npm install -g quicktype

json2yamlのインストール

# json2yamlインストールのための手順
# MacはデフォルトでPython2.7がインストールされているのでそのまま使う
# (2019/04/24時点)
# pipインストール
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py --user
rm get-pip.py 
# パスを通す
export PATH="$HOME/Library/Python/2.7/bin:$PATH"
echo 'export PATH="$HOME/Library/Python/2.7/bin:$PATH"' >> ~/.bash_profile

# json2yamlインストール
pip install json2yaml --user

実行例

あくまで食わせたJSONの定義のみを吐き出すので、実際のrequiredと正しいかとか、
細かいオブジェクトが網羅できているかはチェックが必要なので注意。

# homeにおいたresponse.jsonをschema.yamlに変換して吐き出す
quicktype response.json --lang schema | json2yaml > schema.yaml

生成元のjson

{
  "foo": [ 1, null ],
  "baz": {
    "foo": [ true, "bar" ],
    "baz": "qux"
  }
}

yaml変換後のSchema

$schema: http://json-schema.org/draft-06/schema#
$ref: '#/definitions/Test'
definitions:
  Test:
    type: object
    additionalProperties: false
    properties:
      foo:
        type: array
        items:
          anyOf:
          - type: integer
          - type: 'null'
      baz:
        $ref: '#/definitions/Baz'
    required:
    - baz
    - foo
    title: Test
  Baz:
    type: object
    additionalProperties: false
    properties:
      foo:
        type: array
        items:
          $ref: '#/definitions/Foo'
      baz:
        type: string
    required:
    - baz
    - foo
    title: Baz
  Foo:
    anyOf:
    - type: boolean
    - type: string
    title: Foo

平成最後の記事更新でした。
令和でまたお会いしましょう。

【Kotlin】JerseyをKotlinで動かす その2 パラメータの取扱編

前回の記事 beatdjam.hatenablog.com

前回はJerseyの環境づくりと起動方法、Kotlinへの変換について書きました。
今回は各種リクエストパラメータをどうやって取り扱うかを説明します。

準備

今回の記事の内容を扱うにあたり、新しいResouceクラスを作成しましょう。
下記の形でParametersResource.ktを作成します。
このクラスには @Path("parameters") アノテーションがついているので、
http://localhost:8080/myapp/parameters に対応するクラスとなります。
クラスに@Pathがついている状態でメソッドにも@Pathがついているとき、
クラスのpath/メソッドのpathに対応します。

package com.example

import com.example.form.BeanParamSample
import java.nio.charset.Charset
import javax.validation.Valid
import javax.ws.rs.*
import javax.ws.rs.core.MediaType

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("parameters")
class ParametersResource {

}

HTTPリクエストのクエリ

HTTPリクエストのクエリに含まれている値を利用するには、@QueryParam を使います。
例)
@QueryParam("parameter") parameter: String?

http://localhost:8080/myapp/parameters/queryparam?parameter=hoge

    @GET
    @Path("/queryparam")
    @Produces(MediaType.TEXT_PLAIN)
    fun queryParam(@QueryParam("parameter") parameter: String?): String {
        return if (parameter.isNullOrEmpty()) {
            "Parameter is Empty."
        } else parameter
    }

クエリをdata classに対応させる

前述したQueryParamをdata classのフィールドに定義します。
これを、対応させたいResourceクラスで@BeanParam アノテーションをつけて記述すると、
リクエスト時に自動でdata classに格納してくれるようになります。
後述する @PathParam@FormParamでも利用できるので覚えておきましょう。

また、JerseyではJavaEEのBean Validationという仕組みが利用できます。
@field:NotNull@field:NotEmpty などのバリデーション用のアノテーションを設定すると、
正しくないリクエストに対して、自動で400 Bad Requestを返却してくれるものです。

data class BeanParamSample (
        @QueryParam("parameter1")
        val parameter1: String?,

        @QueryParam("parameter2")
        @field:NotNull
        val parameter2: String?,

        @QueryParam("parameter3")
        @field:NotEmpty
        val parameter3: String?
)

 

@GET
@Path("/beanparam")
@Produces(MediaType.TEXT_PLAIN)
fun beanparam(@BeanParam @Valid parameter: BeanParamSample): String {
    return buildString {
        appendln(
                if (parameter.parameter1.isNullOrEmpty()) {
                    "Parameter is Empty."
                } else parameter.parameter1
        )
        appendln(parameter.parameter2)
        appendln(parameter.parameter3)
    }
}

Pathに含まれる値

HTTPリクエストのパスに含まれる値を利用するためには @PathParam アノテーションを利用します。
また、@Path の指定時にパラメータとしたい箇所を{}でくくる必要があります。
例)
@Path("/pathparam/{parameter1}
@PathParam("parameter") parameter: String?

http://localhost:8080/myapp/parameters/pathparam/hogehoge

@GET
@Path("/pathparam/{parameter}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParam(@PathParam("parameter") parameter: String?): String {
    return if (parameter.isNullOrEmpty()) {
        "Parameter is Empty."
    } else parameter
}

リクエストパスからパターンに対応した値を取り出す

パターンに対応する文字列から複数を取り出すような事もできます。
{parameter1}.{parameter2} のようなパターンを設定すると、
0000.1234 のようなパスの00001234 をそれぞれ取得できます。
例)
@Path("/pathparam/{parameter1}.{parameter2}")
@PathParam("parameter1") parameter1: String?
@PathParam("parameter2") parameter2: String?

http://localhost:8080/myapp/parameters/pathparam/1234.5678

@GET
@Path("/pathparam/{parameter1}.{parameter2}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParamSplit(
        @PathParam("parameter1") parameter1: String?,
        @PathParam("parameter2") parameter2: String?
): String {
    return (parameter1 ?: "") + "." +  (parameter2 ?: "")
}

リクエストパスから正規表現に対応した値を取り出す

パターンは正規表現で記述することもできます。
例)
@Path("/pathparam/regex/{regexMatched:.*}")
@PathParam("regexMatched") regexMatched: String?

http://localhost:8080/myapp/parameters/pathparam/regex/hogefuga/hoge

@GET
@Path("/pathparam/regex/{regexMatched:.*}")
@Produces(MediaType.TEXT_PLAIN)
fun pathParamRegex(@PathParam("regexMatched") regexMatched: String?): String {
    return if (regexMatched.isNullOrEmpty()) {
        "Not matched by regex."
    } else regexMatched
}

Formから送信されたリクエストを取得する

application/x-www-form-urlencoded 形式で送られたリクエストのパラメータは、
@FormParamで取り出すことができます。
例)
@FormParam("form1") form1param : String?
@FormParam("form2") form2param : String?

POSTなのでブラウザから直接たたけないため、CLI上で下記を叩いてください。
curl -d "form1=form1text" -d "form2=form2text" http://localhost:8080/myapp/parameters/formparam

@POST
@Path("/formparam")
@Produces(MediaType.TEXT_PLAIN)
fun formParam(
        @FormParam("form1") form1param : String?,
        @FormParam("form2") form2param : String?
): String {
    return buildString {
        appendln("form1 : $form1param")
        appendln("form2 : $form2param")
    }
}

ファイルアップロードに対応する

ほぼ以前書いた下記記事のままです。
【Kotlin/Java】Jersey2でファイルアップロードを扱う - B-Teck!

POSTなのでブラウザから直接たたけないため、CLI上で下記を叩いてください。
curl --header "Content-Type:application/octet-stream" -d "{"hoge": "fuga"}" http://localhost:8080/myapp/parameters/upload

@POST
@Path("/upload")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.TEXT_PLAIN)
fun upload(input : ByteArray): String {
    return input.toString(Charset.defaultCharset())
}

ここまでの作業

下記のタグまでが今回の記事の作業分です。
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/tree/chapter2

作成したファイル
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/blob/chapter2/src/main/kotlin/com/example/ParametersResource.kt
https://github.com/beatdjam/Jersey-On-Kotlin-Sample/blob/chapter2/src/main/kotlin/com/example/form/BeanParamSample.kt