寝ても覚めてもこんぴうた

プログラム書いたり、ネットワーク設計したり、サーバ構築したり、車いじったり、ゲームしたり。そんなひとにわたしはなりたい。 投げ銭は kyash_id : chidakiyo マデ

goでoapi-codegenを使ってopenapi 3.0してみた(chi-server)

OpenAPI何もわからんですが、
Go で OpenAPI 3.0 に対応したいと思ったのですが、swaggerはどうやら OpenAPI 2.0 とやららしいので、
oapi-codegen を利用してみました。

インストール

goがインストールされれている環境で

go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest

を実行すると oapi-codegen がインストールされます。

利用方法

今回は chi-server を利用しようと思います。
標準では echo サーバを生成したような記憶があります(ど忘れ)

また、READMEに書いてあるサンプルの静止コマンドでは、goのファイルが1つになってしまいますので、
運用も考え、server, types, spec の3ファイルに分かれるようにコマンドを実行します。

コマンドの引数がREADMEなどを読む感じでうまく適用できなかったのですが試行錯誤(やコードを読んで)以下で実行しています

oapi-codegen -package hoge -old-config-style -generate "chi-server" api.yaml > api.gen.go

oapi-codegen -package hoge -old-config-style -generate "types" api.yaml > types.gen.go

oapi-codegen -package hoge -old-config-style -generate "spec" api.yaml > spec.gen.go

このように実行することで、httpサーバとしての api.gen.go , リクエスト/レスポンスパラメータの型としての types.gen.go , oapiのspecファイルとしての spec.gen.go の3ファイルがそれぞれ生成されます。

httpサーバとしての組み込み

サーバとしての組み込みは難しいことはなく、 api.gen.go ファイルの中に Handler を生成する関数が複数用意されているので、
必要な項目て利用できるものを使いhttpサーバを起動しましょう。(詳細略:手抜き)

困ったこと

chi 以外の実装を試していないので、ほかがどうかはわかっていないのですが、chi 関しては、
swaggerを利用したバリデーションなどが標準的に生成されたコードの中で組み込まれず、自分でmiddlewareなどを実装する必要がありました。
これはもう少しよしなにやってくれるような期待をしていたのでびっくりしたのと、
security BearerAuth あたりも割と自分で実装する必要がありました。

最後に

openapi3.0 を使って実装するのが初だったので最初のYAMLの作成に結構手間取りましたが、
実際に開発の流れになると、yamlで変更したものがgoの実装に反映されたり、
webビューからリクエストを投げて動作確認をしたりということが気軽に行えるのでとても良かった。

YAMLを書く → 生成してみる → 生成された構造体/コードを見る(gitのdiff)

というのを繰り返すことで、YAMLで表現したことがどういう意味を持っているのかということが理解しやすい、
しかも生成が速いということで非常に良い感じでした。

ではでは。

参考(ツールの評価のためにも色々参考にしました)

github.com

future-architect.github.io

future-architect.github.io

future-architect.github.io

future-architect.github.io

github.com

zenn.dev

github.com

rinoguchi.net

github.com

times.hrbrain.co.jp

github.com

blog.ebiiim.com

github.com

ツール

editor.swagger.io

Alfread の代わりに Raycast を使い始めたメモ

身の回りで使い始めた人が増えてきたので、インストールしてみたメモです。

細かい部分は追記するかもしれませんししないかもしれません。笑

インストール

こちら からダウンロードし、ポチポチーっとインストールする。

設定した項目

Alfread に設定していた起動のショートカットを Raycast に向ける

単にキー設定を変更しただけ。(Alfreadの設定をずらして、Raycastの設定をAlfreadに設定していたものにする。一応ショートカットがぶつかってると重複しているよ、と教えてくれるようだ)

おいおいやっておきたいこと

参考記事に乗っている拡張機能を適当に必要な物を追加しておきたい。

デフォルトで使うといらない候補が結構出てくる感があるので、必要じゃないものは切っておきたい(めんどくさがりなので切ってない)

そのうち設定変更などしたら追記します。(Alfreadも課金していたのに何一つ便利設定していなかった人)

ではでは。

参考記事

motemen.hatenablog.com

zenn.dev

IntelliJでmermaid記法を有効化する

割と簡単な手順でIntelliJ上でmermaid記法を利用できるようになるのでメモ

IntelliJの設定

Preferences(⌘ + ,) -> Language & Frameworks -> Markdown -> Merkdown Extensions の Mermaid を install してチェックを有効化する

有効化したらIDEを再起動しましょう

利用方法

普通にMarkdownを書く(README.mdなど)際に、

`` `mermaid
erDiagram
    CUSTOMER ||--o{ ORDER : places
    ORDER ||--|{ LINE-ITEM : contains
    CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
`` `

※スペースが入っているのはわざとです

上記のように記述すると以下のようなプレビューが表示されます

便利

ではでは。

CloudRun 上でgoで書かれたサービスを動かす場合の基本的なmainの書き方

ドキュメントとしてはここ

cloud.google.com

GitHubはここにある

github.com

実際のコード

import (
        "context"
        "fmt"
        "log"
        "net/http"
        "os"
        "os/signal"
        "syscall"
        "time"
)

// Create channel to listen for signals.
var signalChan chan (os.Signal) = make(chan os.Signal, 1)

func main() {
        // Determine port for HTTP service.
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
                log.Printf("defaulting to port %s", port)
        }

        srv := &http.Server{
                Addr:    ":" + port,
                Handler: http.HandlerFunc(handler),
        }

        // SIGINT handles Ctrl+C locally.
        // SIGTERM handles Cloud Run termination signal.
        signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

        // Start HTTP server.
        go func() {
                log.Printf("listening on port %s", port)
                if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
                        log.Fatal(err)
                }
        }()

        // Receive output from signalChan.
        sig := <-signalChan
        log.Printf("%s signal caught", sig)

        // Timeout if waiting for connections to return idle.
        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
        defer cancel()

        // Add extra handling here to clean up resources, such as flushing logs and
        // closing any database or Redis connections.

        // Gracefully shutdown the server by waiting on existing requests (except websockets).
        if err := srv.Shutdown(ctx); err != nil {
                log.Printf("server shutdown failed: %+v", err)
        }
        log.Print("server exited")
}

*ドキュメントから転記

こんな感じ。

Make でコマンド実行した結果を変数として使いたい

具体的には gcloud auth print-access-token の出力をMakeの実行に利用したかっただけなのですが、
書きっぷりに若干の癖があるのでメモ。

記述方法

hoge:
  $(eval TOKEN=$(shell gcloud auth print-access-token))
  hogecommand ~~~ --token="$(TOKEN)"

こんな感じ。

GCP のメタサーバから Project ID を取得する(Cloud Runでも)

GCPでアプリケーションを動かす場合、Project ID のパラメータをプログラム内から利用したい場合があります。

環境変数で渡す、というのも方法として悪くないと思いますが、
GCP環境で動いている場合にはメタサーバからProject IDを取得することができます。

今回はGoを用いてメタサーバから取得する方法をメモしておきます。

コード

import "cloud.google.com/go/compute/metadata"

~~ snip ~~

c := metadata.NewClient(&http.Client{})
pid, err := c.ProjectID()

~~ snip ~~

上記のような比較的簡単なコードでプロジェクトIDを取得することができます。

注意点

上記のコードは、GCP上のメタサーバへ接続する処理が内部で行われているため、
ローカルや、何かCI環境上で取得処理を実行する場合、接続先に到達できずtimeoutが発生します。
timeoutが発生すること自体は問題がないように思えるかもしれませんが、しばらくプログラムが止まっている状態になるので、
テストなどで呼ばれると非常に困ると思いますので、呼び出す部分でGCP上で実行されているか否かの判定処理などは必要になりますのでご注意を。

その他の関数

metadataの実装をサラッとみる限り以下のようなものが実装されています。

ProjectID
NumericProjectID
InstanceID
InternalIP
ExternalIP
Hostname
InstanceTags
InstanceName
Zone
InstanceAttributes
ProjectAttributes
InstanceAttributeValue
ProjectAttributeValue
Scopes
Subscribe

適当に抽出してこのような感じです。

参考

github.com

ではでは。