grpcでサブディレクトリの中にprotoファイルと.pb.goファイルを入れたい

やりたいこと

・protoファイルをプロジェクトルート直下ではなくサブディレクトリの中で管理したい
・protoファイルからprotocコマンドで生成させるpb.goファイルを、protoファイルと同じ階層に置きたい

環境等

go1.16.6
github.com/mwitkow/go-proto-validators v0.3.2
github.com

前提

・以下のフォルダ構造とします
(プロジェクトルート(自分の環境だとgin-studyというフォルダ))
└grpc
 └gin-study.proto

・protoファイルの中身はこんな感じ

syntax = "proto3";

option go_package = "github.com/Tiratom/gin-study/grpc";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "github.com/mwitkow/go-proto-validators/validator.proto";

(以下後略)

手順

① ターミナルでecho $GOPATHを実行してGOPATHの値を確認する
Users/【名前】/go って感じの値が返ってくると思います

②validator.protoファイルを用意する
2-1. go-proto-validators/validator.proto at master · mwitkow/go-proto-validators · GitHub からvalidator.protoファイルの中身をコピーする
2-2. /Users/【名前】/go/src/github.com/mwitkow/go-proto-validators/validator.proto の位置になるようにvalidator.protoファイルを作成する
2-3. 2-1でコピーした中身を、2-2で用意したファイルの中にペーストする

※補足
・go-prot-validatorの公式のREADMEの手順でprotocコマンドを実行すると、以下のエラーが発生してしまいました

gin-study.proto:7:1: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.

そこで、こちらを参考にこの2-1〜2-3の手順を実行しています
qiita.com
(記事で言及されているように、注意点があることに注意です・・・注意点を対処できる方法はわかりませんでした・・)

③ 以下コマンドをプロジェクトルートで実行
$ protoc --proto_path=${GOPATH}/src --proto_path=:./grpc --go_out=plugins=grpc:./grpc --go_opt=module=github.com/Tiratom/gin-study/grpc --govalidators_out=paths=source_relative:./grpc ./grpc/gin-study.proto

④ 生成物を確認
gin-study(プロジェクトルート)
└grpc
 ┣gin-study.proto
 ┣gin-study.pb.go
 └gin-study.validator.pb.go

GORMで必要カラムだけを取得したい場合

環境

  • Go1.16.6
  • GORM

やりたいこと

GORMでテーブルからSELECTする際に、全カラムではなく必要なカラムだけを取得したい。

どうやるか

公式ページの以下に書いてある通り。(Advancedのページに書いてあったので最初気づかず悩んだので自分用に整理しています)

gorm.io

具体例

type hoge struct {
    Id int64
}
var i *hoge

t.db.Gdb.Table("hoges").Where("name = ?", "aaa").Find(&i)
// ※hogesテーブルはID以外にもいろんなカラムを持っている前提

// i.Id でSELECT結果のIDカラムを取得可能

Tableでテーブル名を指定しているけど、公式の通りModelで該当テーブルに相当する構造体を指定して取得というのも可能です

メモ

structを作らずに、var i *int64ってやって取得できないものかと思ったけど、Scan called without calling Next というエラーで取得はできなかった。この辺はまた調べないとよくわからないな、、

「Linuxで動かしながら学ぶTCP/IPネットワーク入門」感想

「Linuxで動かしながら学ぶTCP/IPネットワーク入門」という本を読んだのでメモ。
(以下は著者のブログのようです)
blog.amedama.jp

なぜ読んだか

  • Prime Readingで無料だったから
  • ネットワーク系を勉強したいと言ったら友人にお勧めされた「マスタリングTCP/IP」がかなり分厚かったので、読み切る自信がなかったがこれなら読めそうと思ったから
  • ネットワーク系への苦手意識があったから

どんな内容だったか

Ubuntuの仮想環境を構築して、pingでの送信元/送信先IPアドレスの様子や、3ウェイハンドシェイクのフラグの様子を見たりと実際の通信の中身を見ながら、TCP/IPの4つの層をそれぞれ学んでいく。
あくまで入門編なので広く浅くと言ったところ。「DNSって何?もっと知りたい!」とかなったらネットで調べるか、DNSについて取り上げた本で勉強する必要がある。

感想

全般

ネットワークのやりとり内容を観察しながらいろんなプロトコルの動きを見れて、理論だけで終わらず実際の様子を見ることで記憶に定着した気がする。IPv4前提だったので、IPv6の解説をしている本もあればいいなあと思った。
コラムも結構充実してて、確かに気になる!という話題やコラムを読むことでさらに理解が進んだ。

電子書籍での購入だったため分厚さがどのくらいかはわからないが、割と手軽にサクッと読めた。1章分も多過ぎず少な過ぎずで自分の集中力が途切れないちょうどいいくらいでキリよく読み進められた。

その他

『3分間ネットワーク基礎講座』がイラストや話し言葉でとってもわかりやすかったけど実際のやり取りの様子を手を動かして見るというのはないので(僕の記憶)、その部分をこの本が補ってくれるっていう感じでセットものとして読むと良さそうな気がする。また、この『Linuxで動かしながら...』だけだと、「具体的な動きが追えてわかるような気がするんだけどなんかわからない、イメージが掴めない・・・」となるかもしれず、イラスト等でイメージを掴む部分は『3分間...』で補ってく、という形が良いかもしれない。
『3分間...』がGUI, 『Linuxで動かしながら...』がCUIってイメージか。

この3分間ネットワーク基礎講座(シリーズ?)、DNSとかルーティングなどに特化した版もあるので、『Linuxで動かしながら...』を読みつつ気になったところはこのシリーズの該当の本を読むとより理解が進むと思う。

なお『3分間...』はド文系のひよっこ社員だった頃の自分でも読めたが、『Linuxで動かしながら...』はシェルの操作等若干基礎知識・技能がないと読み進めるにはしんどいかもしれない。

環境構築について

  • VirtualBoxを1回も使ったことがない人は勉強がてらVirtualBoxで環境構築するのは良いと思う。
  • VirtualBox使ったことあるし・・という人は、dockerでちゃちゃっと構築してさっさと読み進めたほうが良さそう。
  • 以下はDockerでの環境構築用コマンドだけど、後から思い返しているだけなのでうまくいかないかも
$docker pull ubuntu:latest  
$docker run --privileged -it -d ubuntu:latest 
$docker ps ※動いているコンテナID取得
$docker exec -it コンテナID bash 
(以降は#apt-get updateなど、sudoを消したコマンドを実施)

※wgetでスクリプト取得して動かすときも、「sudo 」は置換して消すなりしたスクリプトにした上で動かす必要があります。

注意事項

  • タブレットで読んでてフォーマットが崩れたのか、本のコマンドでちょこちょこハイフンが表示されていないという現象があった(iPadのKindleアプリ利用)
  • ハイフンが消えていることに気づかずに表示されてるものそのまま打ち込んでエラー、という場合があったので、その場合はコマンドをネットで調べて正しい記述方法を調べるのもまたいい勉強になりそう。

この本をお勧めする人

  • ネットワーク全然よくわからないって人(だけどシェルとかLinux触ったことあるよって人)
  • 基本/応用情報処理技術者試験の勉強をしている人

プロジェクト内の他パッケージを絶対パスでimportする際の僕の勘違い

やろうとしたこと

  • mainパッケージにおいて別ディレクトリに入れている別パッケージを相対パスではなく絶対パスで読み込ませる
  • import "github.com/ユーザー名/レポジトリ名/パッケージ名" の形式でインポートしたい

環境

ディレクトリ構造

.(プロジェクトルート)
├── README.md
├── config
│   └── router.go ←configパッケージ
├── go.mod
├── go.sum
└── main.go  ←mainパッケージ

出てきたエラー

  • 絶対パスでのimportの記載箇所で could not import github.com/Tiratom/gin-study/config (no required module provides package "github.com/Tiratom/gin-study/config")

※Tiratomは僕のGitHubのアカウント名、gin-studyはレポジトリ名です。 main.goにおいて、gin-study/configというインポートは成功することは確認しました。また、router.goをGitHubにプッシュしました。その状態でconfigパッケージを絶対パスでインポートしようとしたのですが、前述のインポートできませんよエラーが発生しました。main.goは以下のように記述していました。

package main

// import "gin-study/config"
import "github.com/Tiratom/gin-study/config"

func main() {
    r := config.GetRouter()
    r.Run(":8080")
}

解決策

Goのpackageを作ろうとしたらgo.modの作り方で困った件 - Qiita

を参考にさせていただきました。

go.modのmoduleの値をもともとはmodule gin-study としていましたが、module github.com/Tiratom/gin-study に修正したところ、無事importでエラーが発生しなくなりました。

補足・メモ

Modules · golang/go Wiki · GitHub において、

A module declares its identity in its go.mod via the module directive, which provides the module path. The import paths for all packages in a module share the module path as a common prefix. The module path and the relative path from the go.mod to a package's directory together determine a package's import path.

という記述があります。 go.modのmoduleに設定した値がインポートパスの共通プレフィックスとなるため、moduleの値がgin-studyにしていたときはインポートがgin-study/configなら成功するけどgithub.com... だと成功しない、という状態になっていたようです。(インポートのパスはGitHubのURLを元につけるのだと勘違いしていました・・・)

また、import "gin-study/config" でも絶対パスのインポートはできていたのですが、import "github.com/..." という形式でのインポートが正だとばかり思っていたので誤った方法でのインポートしかできていないと思い込んでいました。

github.com... のimportはGitHubにプッシュした後でないと行えないと思っていたのですが、上記の理由から別にプッシュしてなくてもimportできるようですね。

多岐にわたって理解が甘く様々な箇所で勘違いをしていました。

複数webhookがあるけど1つしか更新したくない時のaws codepipeline put-webhookで渡すjsonの中身

qiita.com こちらに従ってCodePipelineがGitHubのRelease作成で発火するようになりました。感謝。
1点作業する中で疑問に思ったこととその調査結果メモを備忘録として残しておこうと思います。

疑問に思ったこと

「webhook設定の変更(AWS側)」で行っているaws codepipeline put-webhookにおいて、WebHookが複数存在する時は、全てのwebhook分更新用jsonは用意しないといけないのか?

結論

更新したいwebhook分だけでOK

結論に至るまで

  1. aws codepipeline list-webhooks --region "ap-northeast-1" を実行
{
    "webhooks": [
        {
            "definition": {
                "name": "hoge1--Source--hoge1",
                "targetPipeline": "pipeline1",
                "targetAction": "Source",
                "filters": [
                    {
                        "jsonPath": "$.ref",
                        "matchEquals": "refs/heads/{Branch}"
                    }
                ],
                "authentication": "GITHUB_HMAC",
                "authenticationConfiguration": {
                    "SecretToken": "TOKEN"
                }
            },
            "url": "URL",
            "arn": "ARN",
            "tags": []
        },
        {
            "definition": {
                "name": "hoge2--Source--hoge2",
                "targetPipeline": "pipeline2",
                "targetAction": "Source",
                "filters": [
                    {
                        "jsonPath": "$.ref",
                        "matchEquals": "refs/heads/{Branch}"
                    }
                ],
                "authentication": "GITHUB_HMAC",
                "authenticationConfiguration": {
                    "SecretToken": "TOKEN"
                }
            },
            "url": "URL",
            "arn": "ARN",
            "tags": []
        }
    ]
}

二つwebhookが存在している・・・

  1. 更新するwebhook用のjsonファイルを用意する
    Qiitaの記事を元に
{
  "webhook": {
    "name": "hoge1--Source--hoge1",
    "targetPipeline": "pipeline1",
    "targetAction": "Source",
    "filters": [{ "jsonPath": "$.action", "matchEquals": "published" }],
    "authentication": "GITHUB_HMAC",
    "authenticationConfiguration": {
      "SecretToken": "TOKEN"
    }
  }
}

のようなjsonファイルを用意。
hoge2--Source--hoge2 の方のwebhookは特に変更したくないのでこのjsonファイルには何も記述せず。

  1. webhook-putコマンドを実行
    Qiitaの記事に記載されている通り、aws codepipeline put-webhook --cli-input-json file://webhook_config.json --region "ap-northeast-1" を実行。

  2. 再度aws codepipeline list-webhooks --region "ap-northeast-1" を実行

{
    "webhooks": [
        {
            "definition": {
                "name": "hoge1--Source--hoge1",
                "targetPipeline": "pipeline1",
                "targetAction": "Source",
                "filters": [
                    {
                        "jsonPath": "$.action",
                        "matchEquals": "published"
                    }
                ],
                "authentication": "GITHUB_HMAC",
                "authenticationConfiguration": {
                    "SecretToken": "TOKEN"
                }
            },
            "url": "URL",
            "arn": "ARN",
            "tags": []
        },
        {
            "definition": {
                "name": "hoge2--Source--hoge2",
                "targetPipeline": "pipeline2",
                "targetAction": "Source",
                "filters": [
                    {
                        "jsonPath": "$.ref",
                        "matchEquals": "refs/heads/{Branch}"
                    }
                ],
                "authentication": "GITHUB_HMAC",
                "authenticationConfiguration": {
                    "SecretToken": "TOKEN"
                }
            },
            "url": "URL",
            "arn": "ARN",
            "tags": []
        }
    ]
}

put-pipelineで指定したjsonでは記述していなかったhoge2--Source--hoge2 のwebhookには何も影響なし!

putって言うからjsonファイルの中身が正になって記載していなかったwebhookの情報が消えるのかも?どうしようか・・?と悩んでいましたが、そんな心配は不要でした!

SpringBootの例外を処理する共通処理の作成

記事概要

SpringBootで作成したwebアプリケーションにおいて発生する例外を処理してくれる共通のクラスを作成する
 
 

環境メモ

  • SpringBoot 2.2.2
     
     

    構造メモ

    source/main/java/aaa/bbb/ccc/controllerフォルダ内に、例外を処理するためのクラス「ExceptionController.java」を作成
     
     

    ソースメモ

@ControllerAdvice
public class ExceptionController {
  public ExceptionController(){}


  // 自前で作成したHogeHogeExceptionを処理するためのメソッド。HogeHogeExceptionのクラスの内容は後述。  
  @ExceptionHandler(HogeHogeException.class)
  public ModelAndView hogehogeExceptionHandler(HogeHogeException e, RedirectAttributes redirectAttributes){
    ModelAndView mav = new ModelAndView();
    mav.setViewName("redirect:/");
    redirectAttribuets.addFlashAttribute("errorMessage", "エラーです");
    return mav;
  }

  @ExceptionHandler(Exception.class)
  public ModelAndView allExceptionHandler(Exception e){
    e.printStackTrance();
    ModelAndView mav = new ModelAndView();
    mav.setViewName("error");   // エラーページに遷移させる
    return mav;
  }
}

 
 

補足

処理内で何か例外が発生すると、ここの処理が呼び出されます。
 
 

自作例外クラスメモ

// ReponseStatusをつけていますが、結局上の例外処理クラスでredirectさせているのでステータスコードは302になります・・・。ちゃんとした処理方法はまた勉強します・・・。
@ResponseStatus(HttpStatus.NOT_FOUND)
public class HogeHogeException extends RuntimeException {
  public HogeHogeException(String message) { super(message); }
}

 
 

参考サイト

※上の内容は参考サイトの内容をちゃんと踏まえてない箇所も多いです・・・これはあくまで自分用の記事なので、もしこの記事をお読みになった方は以下サイトをきちんと参照しておくことを推奨します。
qiita.com fa11enprince.hatenablog.com

SpringBootのJpaRepositoryで指定カラムでソートした上で全件取得

内容

SpringBootのJpaRepositoryを使用して、指定したカラムで並び替えた状態でテーブルから全てのデータを取得するにはどうすればよいか。

方法

レポジトリのインターフェース内に、List<T> findByOrderBy【並び替えをしたいカラム名】(); の抽象メソッドを追加する。

参考資料

www.baeldung.com
※4.2のSortパラメーター追加の方法だと、Privateメソッドにアクセスしているといったエラーメッセージが出て動かせませんでした・・・。

コメント

findAllOrderByだと自動生成のメソッドとしてはうまく動きませんでした。