OpenAPI3の`#/components/examples/`で定義したexampleは`'#/components/schemas/`で`$ref`できない

タイトルままなのだけれど、OpenAPI3の#/components/examples/で定義したexampleは'#/components/schemas/$refできません。 APIのレスポンスボディの例として使おうとして気づきました。

NGパターン

OpenAPIで、#/components/examples/に例を定義して、'#/components/schemas/で定義したスキーマオブジェクトで参照してみます。 以下のようなyaml

openapi: "3.0.3"
info:
  title: sample
  description: "`hoge"
  version: "1.0.0"
servers:
  - url: http://example.com/api
paths:
  /user:
    post:
      description: create user
      responses:
        '201':
          description: created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas: 
    User:
      type: object 
      required: 
        - id
      properties:
        id: 
          type: integer 
          format: int64 
        name:
          type: string
      example:
        $ref: '#/components/examples/UserExample'
  examples:
    UserExample:
      value:
        id: 1
        name: John

このyamlをSwagger Editorで表示すると、エラーは出力されないものの、exampleの表示は$ref: '#/components/examples/UserExampleになって意図したオブジェクトが表示されません。 下記のようなイメージ。

exampleをうまく参照できていない
exampleをうまく参照できていない

スキーマのexample表示もなにかがおかしい

スキーマの例にもvalueが表示される
スキーマの例も何かがおかしい

OKパターン

色々試したんですが、APIのレスポンスボディとして#/components/examples/に定義した例を使いたい場合は、Media Type Objectexamplesフィールドで参照するとうまくいきます。

openapi: "3.0.3"
info:
  title: sample
  description: "`hoge"
  version: "1.0.0"
servers:
  - url: http://example.com/api
paths:
  /user:
    post:
      description: Returns all pets from the system that the user has access to
      responses:
        '201':
          description: create user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
              examples:
                User:
                  $ref: '#/components/examples/UserExample'
components:
  schemas: 
    User:
      type: object 
      required: 
        - id
      properties:
        id: 
          type: integer 
          format: int64 
        name:
          type: string
      example:
        id: 2
        name: Bob
  examples:
    UserExample:
      value:
        id: 1
        name: John

上記のように書くと、以下のようにちゃんと表示してくれます。

exampleをうまく参照できている
exampleをうまく参照できている

それもそのはずで、OpenAPIの仕様をちゃんと読むと、exampleフィールドとexamplesフィールドって明確に区別されてるのです。

例えば、Schema Objectなどにあるexampleフィールドの型はAnyでフリーフォーマットな記載が可能なものです。

一方で、#/components/examples/はExample Object を定義しているので、このObjectが利用可能なフィールドでだけ参照することができます。

仕様をちゃんと読まずに、しょうもないことに時間を使ってしまいまいた。英語力が欲しい。

IFTTT と Micorosoft Power Automate を連携して Alexa から Microsoft TODO にタスク登録しようとしてうまくいかなかった記録

追記あり:結局、連携させることができました。

上手くいかなかったことも記録しておけば後々役に立つかもしれないので書いておきます。

やりたかったこと

Alexa 経由で音声で、Microsoft TODO にタスクを登録したい。

やろうとしたこと

Webhook で IFTTT をトリガーに Microsoft Flow を動かす - Qiitaを参考に以下をやってみようとした。

  • IFTTT
    • Alexaの”Item added to your To Do List”トリガーを利用して、AlexaのToDoリストへのタスクの追加を契機にアクションを実行
    • Webhooksの"Make a web Request"アクションを利用して、AlexaのToDoリストに追加されたタスクの名称をBodyにしつつ、Power AutomateのWebhookへリクエストを送る
  • Microsoft Power Automate
    • "HTTP要求の受信時”を使ってリクエストを受け付ける
    • "タスクの作成(プレビュー)"を使ってMicrosoft ToDoにリクエストの内容でタスクを作成する

できたこと

  • IFTTT
    • Alexaの”Item added to your To Do List”トリガーを利用して、AlexaのToDoリストへのタスクの追加を契機にアクションを実行
  • Microsoft Power Automate
    • "HTTP要求の受信時”を使ってリクエストを受け付ける
    • "タスクの作成(プレビュー)"を使ってMicrosoft ToDoにリクエストの内容でタスクを作成する
      • ローカルマシンからInvoke-WebRequestコマンドレットを利用してタスクを作成することができた
        • Invoke-WebRequest $URL -Method POST

できなかったこと

  • IFTTTでWebhooksの"Make a web Request"アクションを利用して、AlexaのToDoリストに追加されたタスクの名称をBodyにしつつ、Power AutomateのWebhookへリクエストを送ること
    • トリガーからserviceは起動できているが、serviceが失敗する
      • エラーメッセージは以下の通り
        • Action failure message: Unable to make web request. Your server returned a undefined
    • Power Automate側の実行履歴にログが残っていない

考えていること

  • Power Automate側の実行履歴にログが残っていないので、IFTTTから正しいURLでPower Automateを呼び出せていないものと思われる
  • IFTTTに設定しているURLと同じURLを使って、Invoke-WebRequestでリクエストしてPower Automateを実行できているので、URLの誤入力ではない
  • IFTTTに設定する際のエスケープが必要?と適当にやってみたがうまくいかない。
    • URL全体をクォートしてみる ⇒ そもそもIFTTTは引用符始まりのURLを受け付けてくれないのでNG
    • URLのクエリパラメータを<<<>>>で囲ってみる ⇒ エラーに変化はない
  • うーんよくわからないけど何か制限事項があるのか...?

代替手段

追記

日を置いて改めて設定を見直したら、BODYの指定を誤っていて(記号({)が全角文字だった)、それを直しただけで正常にPOSTできるようになりました。 とてもしょうもないのですが、連携できてよかった。

あとは余談ですが、Curlでアンパサンドを含むURLを送付するときはエスケープしないとBashの機能と競合するので注意しましょう。

自分向けのリンク集(開発手法まわり)

随時更新

自分向けのリンク集(開発手法まわり)

随時更新

AnacondaがPowershellでうまく起動しないときの対策

これまでAnacondaがPowershellではうまく起動しないと思っていて、Anaconda Powershell Promptをわざわざ起動していた。 ところが、Anaconda がやっと PowerShell に公式対応した - Qiitaを参考にconda init powershellするとPowerShell の Profileを書き換えて、Powershell起動時にcondaの環境も起動してくれる。

余談

いったんは上記で対応したのだが、若干の気持ち悪さはある(起動時間も気になる)。 anacondaは楽ではあるのだが…素のpythonをインストールして、pipしたほうがいいのかもしれない…

WindowsのVSCodeからGitにSSH接続しようとして失敗するときの暫定対策

自分用の雑なメモ

症状

  • WindowsVScodeからGitにSSH接続しようとする(=pushやpullをしようとする)とSSH接続エラーになる
    • エラーの内容はPermission denied (publickey)
    • sshキーのパスフレーズを入力していないので当然だが、入力することができない
  • git bash からのpushやpullは問題ない

暫定対策

以下の環境変数を定義する*1

DISPLAY=needs-to-be-defined
SSH_ASKPASS=/mingw64/libexec/git-core/git-askpass

暫定対策

環境変数SSH_ASKPASSを使って、SSHキーのパスフレーズ入力にgit同梱のaskpassプログラムを指定している。これにより、パスフレーズ入力が必要になるとaskpassプログラムを起動し、その中ででパスフレーズ入力してVSCodeに渡せるようになる。

これでいいんだっけ?

  • そもそもVSCodeの中で完結することも可能だった気がする。
  • 毎回パスフレーズ入力するのも面倒
    • ただ、とりあえず暫定的にうごくようになっただけでもまし。

参考

*1:git-gui--askpassでもよい

自分向けのリンク集(プロジェクト運営周り)

PMBOKをみろ、というむきもあると思うが、もう少しライトでもいいよね。というリンク集。

随時更新