Goのnet/httpパッケージでHello WorldするだけのWebアプリ

本記事の目的

Goを学ぼうかどうか判断するために、簡単なWebアプリを作ってみます (アクセスしたら、Hello Worldと表示するだけ)。

開発環境

Goを信用して良いのか分からなかったので、環境を汚さないために、Dockerでやります。 面白かったら、デバッカーとかで内部まで見たいので、ローカルで環境構築します。

ディレクトリ構成は以下のようにしました。 compileFileディレクトリ内にgoファイルを置いて、ビルドしていきます。

compileFile (ディレクトリ)
Dockerfile
docker-compose.yml
# Dockerfile
FROM golang:latest
RUN mkdir -p /go/src
version: '3'
services:
  go:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - ./compileFile:/go/src
    working_dir: /go/src

コンテナ内に入って、goのコマンドを確かめてみます。 --service-portsを指定しないと、8080ポート同士を繋げることはできないので、注意です。 docker psでちゃんとポートフォワードできていることを確認しておきます。

$ docker-compose run --service-ports go /bin/bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
af4f9c066ecd        golean_go           "/bin/bash"         7 seconds ago       Up 2 seconds        0.0.0.0:8080->8080/tcp   golean_go_run_a79a836040ab

ひとまず、go と打ってみて、使えるコマンドを確認します。

Go is a tool for managing Go source code.

Usage:

    go <command> [arguments]

The commands are:

    bug         start a bug report
    build       compile packages and dependencies
    clean       remove object files and cached files
    doc         show documentation for package or symbol
    env         print Go environment information
    fix         update packages to use new APIs
    fmt         gofmt (reformat) package sources
    generate    generate Go files by processing source
    get         add dependencies to current module and install them
    install     compile and install packages and dependencies
    list        list packages or modules
    mod         module maintenance
    run         compile and run Go program
    test        test packages
    tool        run specified go tool
    version     print Go version
    vet         report likely mistakes in packages

Use "go help <command>" for more information about a command.

Additional help topics:

    buildconstraint build constraints
    buildmode       build modes
    c               calling between Go and C
    cache           build and test caching
    environment     environment variables
    filetype        file types
    go.mod          the go.mod file
    gopath          GOPATH environment variable
    gopath-get      legacy GOPATH go get
    goproxy         module proxy protocol
    importpath      import path syntax
    modules         modules, module versions, and more
    module-get      module-aware go get
    module-auth     module authentication using go.sum
    module-private  module configuration for non-public modules
    packages        package lists and patterns
    testflag        testing flags
    testfunc        testing functions

Use "go help <topic>" for more information about that topic.

go build go run go fmtは近いうちに使いそうです。

プロジェクト作成

馴染みが深いWebアプリからGoを理解していこうと思いました。 サンプルコードとか見ながら、Hello Worldをブラウザ上に表示するプログラムを書きます。

package main

import "io"
import "net/http"

func mainHandler(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, `Hello World!!!`)
}

func main(){
    http.HandleFunc("/main", mainHandler)
    http.ListenAndServe(":8080", nil)
}

1コマンドで整形できるので、整形後ビルドします! ちなみに、ビルド時にリンターも働いているのか、改行の位置や使ってないパッケージがあると怒られます。

ビルドすると、goファイルのあるディレクトリ名の実行ファイルが作られました。

$ go fmt
$ go build
$ ls
server main.go
$ ./server

http://localhost:8080/main にアクセスすると、Hello Worldを確認できました!

スクリーンショット 2020-10-13 1.23.10.png

ちなみに、Macで動かしたい場合は、以下でMac用にコンパイルできます。

$ GOOS=darwin GOARCH=amd64 go build

net/httpパッケージ

わかりやすいところから見ていきます。 これでサーバーを立てられるようです。 第一引数がポートの指定、第二引数でHandlerを選択できるようで、nilの場合デフォルトのDefaultServeMuxが使われるようです。

http.ListenAndServe(":8080", nil)

DefaultServeMuxって何?

ドキュメントを読み進めると、以下の記述にあたります。

HandleFunc registers the handler function for the given pattern in the DefaultServeMux.
The documentation for ServeMux explains how patterns are matched.

HandleFuncでURLのパターンに対応するハンドラーをDefaultServerMuxに登録できる...みたいなことが書いてあります。ルーティング的な何かと思っておきましょうか。

なので、以下は/mainにアクセスしたら、mainHandlerの処理を実行と読めます。

http.HandleFunc("/main", mainHandler)

ioパッケージの方は何してるか分かるので、置いておきます。

document Package http

Localに導入

brewで簡単に入ります。

$ brew install go
$ go version
go version go1.15.3 darwin/amd64

REPLも入れておきます。 gore v0.5.0だと動かなかったので、バージョンを落としています。

# これをしてインストールできるようになりましたが、いらないかもです。
$ export GO111MODULE=on
$ go get github.com/motemen/gore/cmd/gore@v0.4.0
$ gore -version
gore 0.4.0 (rev: HEAD/go1.15.3)

間違えてインストールした場合は以下で削除できます。

$ go clean -i github.com/motemen/gore/cmd/gore

ちなみに、v0.5.0だと以下のエラーメッセージがでます。

gore: could not load 'fmt' package: err: exit status 1: stderr: build flag -mod=mod only valid when using modules

これでローカル環境も整ったので、あとは遊ぶだけです。

総括

Go楽しいですね。 ターミナルアプリ (TUI) とか作ってみたい。

雑多な感想

Qiitaで投稿しようかと思ったけど、Qiitaは怖い人ばかりで治安も悪いので、故郷のHatena Blogでひっそり過ごすことにした。