Go言語とGoogle Cloud Functionsで、URLを渡すとOGPメタデータをjsonで返してくれるAPIを作る

19年3月にGoogle Cloud FunctionsがGo言語を正式サポートしていたとのことで、URLを渡すとOGP+αが取得できるCloud Functionsを作ってみました。

環境は以下の通り。

$ go version
go version go1.12.7 darwin/amd64

$ gcloud version
Google Cloud SDK 256.0.0
beta 2019.05.17
bq 2.0.46
core 2019.07.26
gsutil 4.41

$ hugo version
Hugo Static Site Generator v0.55.6/extended darwin/amd64 BuildDate: unknown

以下ステップバイステップで作り方をみていきます。

GCPでプロジェクトを作る

cloud-functions-testという名前でプロジェクトを作ります。

新しく「cloud-functions-test」プロジェクトを作る

gcloud CLI(Cloud SDK)のインストール&セットアップ

Google Cloud SDK documentation  |  Cloud SDK  |  Google Cloudの内容に従いCloud SDKをインストールします。 インストール後はCloud SDKのコンポーネントのアップデートと、先に作成したプロジェクトの選択と、そのプロジェクトでCloud Functionsを有効化しておきます。

$ gcloud components update

All components are up to date.

$ gcloud projects list
PROJECT_ID                   NAME                  PROJECT_NUMBER
cloud-functions-test-248711  cloud-functions-test  673440494381

$ gcloud config set project cloud-functions-test-248711
Updated property [core/project].

$ gcloud services enable cloudfunctions.googleapis.com
Operation "operations/acf.********-****-****-****-************" finished successfully.

コードを書く前に

まずざっと以下の資料に目を通して、どうすべきかを把握しておきます。ちなみに8/3時点では日本語版は内容が古いようので、英語版を見る必要ありです。

まとめると、

  • サポートしているGoのバージョンはGo 1.11
  • HTTPリクエストで発火させる場合は、

    func Handler(w http.ResponseWriter, r *http.Request) {
    }
    

    のようなnet/httphttp.HandleFuncに食わせるのと同様の関数を実装する

  • 依存関係の解消はGo modulesか、vendorディレクトリに置くかのいずれか

    • ただし、go.modが存在する場合はvendorディレクトリは無視されるので、vendorで管理しているはずなのにうまく動かない場合はgo.modが存在しないか確認する

コードを書く

  • $GOPATH内にプロジェクトがある
  • Go modulesで依存関係を管理する

👆を前提にSpecifying dependencies in Go  |  Cloud Functions Documentation  |  Google Cloudを見ながらコードを書きます。

$ mkdir $GOPATH/src/github.com/nishim/gogp
$ cd $GOPATH/src/github.com/nishim/gogp
$ export GO111MODULE=on
$ go mod init 
$ vi gogp.go

コンソールでも確認できます。 書いたコードはGitHubにあります。コードが書き終わったら依存関係のアップデートをしておきます。

$ go mod tidy

デプロイする

gcloud CLIでデプロイします。出力にもある通り、少しだけ時間がかかります。

$ gcloud functions deploy Gogp --runtime go111 --trigger-http --memory=128MB
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 128
entryPoint: Gogp
httpsTrigger:
  url: https://us-central1-cloud-functions-test-248711.cloudfunctions.net/Gogp
labels:
  deployment-tool: cli-gcloud
name: projects/cloud-functions-test-248711/locations/us-central1/functions/Gogp
runtime: go111
serviceAccountEmail: cloud-functions-test-248711@appspot.gserviceaccount.com
sourceUploadUrl: https://storage.googleapis.com/gcf-upload-us-central1-7da3dd30-c7fd-4789-a282-7caaae91b03d/f9be229c-5e24-4702-9ff3-6fc00143bb22.zip?GoogleAccessId=service-673440494381@gcf-admin-robot.iam.gserviceaccount.com&Expires=1564836842&Signature=dd%2FoJW4P%2F0xAJbg9mnbV861VP6eT6ylifuYyUEkDRA0Tes8xUBmH8sx1rsogF3k%2BImvLs37CX1JPcnOp4vVxrQSyEMZ8%2BiFhA2SluC7PjxNzQDLOX9q4Du6uudrUNExgUUx0mmIawQieQTtSnrPY0aFSo3heh5jiKg1uJrawxOPVac0bxBftF0nYqEX82L24xwVNh6p4D%2FMjQPcdZY1Nradj5dzt4yzIbv82urbOdS47z7ZyVFxk2Z5IlYzcy8n%2BoMg%2BUl1U1Lte%2FL%2B%2BsMgzFtfPSx7nOCoOLt3u%2FxgauVLw2a40qLtb7t6DzZCRYUC87MqhSQ7%2FwEeaR7ON5bSDWg%3D%3D
status: ACTIVE
timeout: 60s
updateTime: '2019-08-03T12:24:40Z'
versionId: '1'

これでデプロイできました。httpsTriggerにあるのがエンドポイントになります。試しにcurlして見ると?

$ curl -s "https://us-central1-cloud-functions-test-248711.cloudfunctions.net/Gogp?url=https%3a%2f%2fblog%2eliclab%2ecom%2f2019%2d06%2d17%2fgo%2dx%2dnet%2dhtml%2dutf8%2dbom%2f" | python -m json.tool
{
    "description": "Go\u306egolang.org/x/net/html\u30d1\u30c3\u30b1\u30fc\u30b8\u3067BOM\u4ed8\u304dUTF-8\u306b\u3084\u3089\u308c\u305f\u8a71",
    "favicon": "",
    "image": "",
    "site_name": "",
    "site_url": "https://blog.liclab.com/",
    "title": "Go\u306egolang.org/x/net/html\u30d1\u30c3\u30b1\u30fc\u30b8\u3067BOM\u4ed8\u304dUTF-8\u306b\u3084\u3089\u308c\u305f\u8a71",
    "type": "article",
    "url": "https://blog.liclab.com/2019-06-17/go-x-net-html-utf8-bom/"
}

うまくいきました。コンソールでも確認できます。

コンソールで追加したCloud Functionsが確認できる

おわりに

基本的にはGoでWebアプリを作る時と同じことをするだけなので、お手軽でいいですね。料金もAlways Free枠が大きくプライベートユースであれば無料枠内で問題なく利用できそうです。

次はこのAPIを利用して、Hugoでブログカードを利用できるようにしていきます。