dictknifeにshrinkコマンドを追加した

github.com

発端

qiitaのAPIを実行してみるとあるユーザーのストックの情報が取れるらしい(実はストックは公開情報だったんですね)。

GET /api/v2/users/:user_id/stocks

指定されたユーザがストックした記事一覧を、ストックした日時の降順で返します。

そしてここに含まれている以下のfieldが本文全文の値を保持している(一方はHTML化後)。

  • rendered_body
  • body

やばい。どのくらいやばいかというと、38MBとかになっている。

$ ls -lh src/stocks.yaml
-rw-r--r--  1 podhmo  staff    38M  3 26 03:07 src/stocks.yaml

shrink

とりあえず小さくしたかったのでshrinkコマンドを追加した(まだpypiにはあげていない)。

$ dictknife shrink -h
usage: dictknife shrink [-h] [--max-length-of-string MAX_LENGTH_OF_STRING]
                        [--max-length-of-list MAX_LENGTH_OF_LIST] [--cont-suffix CONT_SUFFIX]
                        [--with-tail]
                        [-i {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}]
                        [-o {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}]
                        [files [files ...]]

shrink

positional arguments:
  files

optional arguments:
  -h, --help            show this help message and exit
  --max-length-of-string MAX_LENGTH_OF_STRING
  --max-length-of-list MAX_LENGTH_OF_LIST
  --cont-suffix CONT_SUFFIX
  --with-tail
  -i {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}, --input-format {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}
  -o {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}, --output-format {yaml,json,toml,csv,tsv,raw,env,md,markdown,spreadsheet}

shrinkを使って小さくする

defaultでは以下の様な仕様で捨てられる

  • 文字列は100文字以上が切り捨てられる
  • 配列は長さ3以上が切り捨てられる(先頭3件のみ取得)

それぞれ --max-length-of-string, --max-length-of-list で変更できる。

実際に使ってみると、38MBから17KBになったので小さくなった。

$ dictknife shrink src/stocks.yaml > /tmp/shrinked.yaml
$ ls -lh /tmp/shrinked.yaml
-rw-r--r--  1 podhmo  wheel    17K  4  1 15:49 /tmp/shrinked.yaml

shapeで比較

dictknife shapeでどういうkeyが存在するかを調べられる。

元のデータと比較してどのようなkeyが存在するかを比較して、JSONSchemaやOpenAPI docをなどを作ろうとしたときのために、fieldが欠損していないかなどを調べてみる。

$ diff -u <(dictknife shape src/stocks.yaml) <(dictknife shape /tmp/shrinked.yaml)
--- /dev/fd/63  2020-04-01 15:53:17.000000000 +0900
+++ /dev/fd/62  2020-04-01 15:53:17.000000000 +0900
@@ -62,4 +62,3 @@
 []/response/content/[]/user/website_url
 []/response/status_code
 []/response/url
-?[]/response/content/[]/tags/[]/versions/[]

tagsが消えてしまっていた。まぁ先頭N件に含まれない場合には仕方がない。こうなってしまう。

--with-tailで先頭と末尾N件取得するように変えられる。

$ diff -u <(dictknife shape src/stocks.yaml) <(dictknife shape <(dictknife shrink --with-tail src/stocks.yaml))

ちなみにdictknife shapeはこういう感じの出力だった(request,responseを余分に保持している。実際のresponseはresponseのcontent部分)。

$ dictknife shape /tmp/shrinked.yaml
[]
[]/headers
[]/headers/Cache-Control
[]/headers/Connection
[]/headers/Content-Type
[]/headers/Date
[]/headers/ETag
[]/headers/Link
[]/headers/Rate-Limit
[]/headers/Rate-Remaining
[]/headers/Rate-Reset
[]/headers/Referrer-Policy
[]/headers/Server
[]/headers/Strict-Transport-Security
[]/headers/Total-Count
[]/headers/Transfer-Encoding
[]/headers/Vary
[]/headers/X-Content-Type-Options
[]/headers/X-Download-Options
[]/headers/X-Frame-Options
[]/headers/X-Permitted-Cross-Domain-Policies
[]/headers/X-Request-Id
[]/headers/X-Runtime
[]/headers/X-XSS-Protection
[]/response
[]/response/content
[]/response/content/[]
[]/response/content/[]/body
[]/response/content/[]/coediting
[]/response/content/[]/comments_count
[]/response/content/[]/created_at
[]/response/content/[]/group
[]/response/content/[]/id
[]/response/content/[]/likes_count
[]/response/content/[]/page_views_count
[]/response/content/[]/private
[]/response/content/[]/reactions_count
[]/response/content/[]/rendered_body
[]/response/content/[]/tags
[]/response/content/[]/tags/[]
[]/response/content/[]/tags/[]/name
[]/response/content/[]/tags/[]/versions
[]/response/content/[]/title
[]/response/content/[]/updated_at
[]/response/content/[]/url
[]/response/content/[]/user
[]/response/content/[]/user/description
[]/response/content/[]/user/facebook_id
[]/response/content/[]/user/followees_count
[]/response/content/[]/user/followers_count
[]/response/content/[]/user/github_login_name
[]/response/content/[]/user/id
[]/response/content/[]/user/items_count
[]/response/content/[]/user/linkedin_id
[]/response/content/[]/user/location
[]/response/content/[]/user/name
[]/response/content/[]/user/organization
[]/response/content/[]/user/permanent_id
[]/response/content/[]/user/profile_image_url
[]/response/content/[]/user/team_only
[]/response/content/[]/user/twitter_screen_name
[]/response/content/[]/user/website_url
[]/response/status_code
[]/response/url

shrink後のyamlはこのようなもの