うごく生ゴミプログラマの備忘録

うごく生ゴミ 〜再臨〜

Go言語でAPI作った話

書くこと

  • Go言語でRestAPIつくりましたって話

  • 参考にした本とか記事とか

  • 環境構築とか

  • 書いたソースと簡単な説明とか

  • その他感想とか

Go言語でRestAPI作りましたって話

RestAPIって言っても、ランダムに運勢をJSON形式で返すだけの おみくじAPIです。 GETメソッドで omikuji.json を叩くと運勢が帰ってきます。 ブラウザで直接開いた場合以下のような感じです。まんまJSONです。

f:id:jBellTree:20160516083509p:plain

参考にした本とか記事とか

まず一通り基本的な文法とか、お作法的なところを↓の本で勉強しました。 ちなみに今回はKindle版を買った。検索は対応してるっぽいです。

https://www.amazon.co.jp/%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0Go%E8%A8%80%E8%AA%9E-%E6%9D%BE%E5%B0%BE%E6%84%9B%E8%B3%80-ebook/dp/B01FH3KRTI?ie=UTF8&qid=&ref_=tmm_kin_swatch_0&sr=www.amazon.co.jp

で、RestAPI作りたいなーって思ったら以下の記事を見つけたので参考にさせていただきました。

qiita.com

環境構築とか

上の記事で使用されている go-json-rest なるライブラリを使いましょうという方針でいく。 が、俺の環境にはまだそんなライブラリを落としてきていない。ので落としてくるのだが、じゃあどうやるのかというと、 俺は↓の記事を参考に ghq なる物をインストールし、ghqを使用して go-json-rest をインストールしました。

ghq... 連合国軍総司令部???

qiita.com

書いたソースと簡単な説明とか

構成

パッケージ構成は以下のようにしました。 ソース内の packaege ~~~ も実際のフォルダ構成と同じ。

main
 ├ bin/
 └ main/
     ├ OmikujiApi.go
     │
    ├ data/
     │  └ OmikujiData.go
     │
      └ resource
          └ Omikuji.go

OmikujiApi.go

なんかいろいろやってる。 go-json-rest ライブラリのAPIをちゃんと読まないといけないんだけど、 たぶん、 * 受け付けるメソッドの設定(GETとかPOSTとかDELETEとか)、 * パスのルーティング(? っていう言葉でいいのかな) http:// ... /omikuji.json というパスとそのパスにアクセスされた場合に実行する処理の紐付け * 何番のポートを使うかの設定 (今回は 8081番)

をやっている。(つもりになってます。)

package main

import (
    "net/http"
    "github.com/ant0ine/go-json-rest/rest"
    "./resource"
    "log"
)


func main() {

    api := rest.NewApi()
    api.Use(rest.DefaultDevStack...)
    api.Use(&rest.CorsMiddleware{
        RejectNonCorsRequests: false,
        OriginValidator: func(origin string, request *rest.Request) bool {
            return true
        },
        AllowedMethods: []string{"GET"},
        AllowedHeaders: []string{
            "Accept", "Content-Type", "X-Custom-Header", "Origin"},
        AccessControlAllowCredentials: true,
        AccessControlMaxAge:           3600,
    })
    router, err := rest.MakeRouter(
        rest.Get("/omikuji.json", resource.GetOmikuji),
    )
    if err != nil {
        log.Fatal(err)
    }
    api.SetApp(router)
    log.Fatal(http.ListenAndServe(":8081", api.MakeHandler()))
}

OmikujiData.go これが実際にJSON形式にして返すデータ。 SetUnsei() を使うと運勢がランダムにセットされる。

package data

import (
    "time"
    "math/rand"
)


type OmikujiData struct {
    Unsei string
}

func (omikujiData *OmikujiData) SetUnsei() {

    unseiMap := map[int]string{
        0: "大吉",
        1: "中吉",
        2: "小吉",
        3: "末吉",
        4: "吉",
        5: "凶",
        6: "末凶",
        7: "小凶",
        8: "中凶",
        9: "大凶",
    }

    rand.Seed(time.Now().UnixNano())
    unsei := unseiMap[rand.Intn(10)]
    omikujiData.Unsei = unsei
}

Omikuji.go

OmikujiData構造体をJSONにして返す関数を書いた。

package resource

import (
    "github.com/ant0ine/go-json-rest/rest"
    "../data"
)


func GetOmikuji(w rest.ResponseWriter, r *rest.Request) {

    omikujiData := new (data.OmikujiData)
    omikujiData.SetUnsei()
    w.WriteJson(omikujiData)
}

その他感想とか

正直、ここまでめっちゃスムーズにできたと思う。 JavaJAX-RSのプロジェクト作って、RestAPIの動作確認まで…とかと比べてだけど。 たぶん Go言語の方がずっと詰まるところが少なかったと思う。

動作が確認できるまでの途中途中での、「なんかうまくいかないんだが?」っていうのってモチベーションの維持に非常に関わるので、 そういうのが少ないのって素晴らしいと思う。まる。

webpack + Babel + React(ES2015使用)の設定

やりたいこと。 * ReactをJSXを使用して書きたい。 * EcmaScriptの構文も使用して書きたい * .jsファイルと、.jsxファイルに変更があった場合自動的にビルドしてほしい。 * 自動的にソースマップも出力してほしい。

webpack.config.js

// コマンドメモ
// -p : minify
// --watch : ファイルの変更を監視 ビルドの自動化
// $ webpack -p --progress --colors --watch

var path = require('path');
var webpack = require('webpack');

module.exports = {
    // エントリーポイント
    entry: './script/src/main.jsx',
    // ソースマップ出力
    devtool: "#source-map",
    // 出力先設定
    output: { 
        path: __dirname,
        filename: './script/dest/bundle.js' 
    },
    module: {
        loaders: [
            // .jsxファイル用
            {
                test: /.jsx?$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015', 'react']
                }
            },
            // .jsファイル用
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015']
                }
            }
        ]
    },
    resolve: {
        // ここに登録した拡張子は import時に省略できる
        extensions: ['', '.js', '.jsx']
    }
};

以下のコマンドで実行

$ webpack -p --progress --colors --watch

俺がBracketsに入れてるエクステンションまとめ

f:id:jBellTree:20160410030442p:plain

Mac でも Windows でも使えて、動作が安定していて、標準で日本語に対応していてライブプレビューできて簡易サーバー立ち上げられる最強伝説エディタ Bracketsに俺がよく追加しているエクステンションまとめた。

相変わらずUTF-8のファイルしか扱えないけど、そこは割り切っていこう。

React (.jsx) language mode for Brackets

React(.jsx)モードを追加するエクステンション

Go-IDE

Go言語モードを追加するエクステンション

Monokai Dark Soda

テーマを変更するやつ。 黒ベースで最高にCoolだぜ。

FuncDocr

JSDocのテンプレートを挿入してくれるやつ。 ためしてないけどPHPでもいけるっぽい。

Tabs - Custom Working

開いてるファイルをタブ表示してくれるやつ。

Show Whitespace

スペースとかタブとかを可視化してくれるやつ。 可視化されてないと不安になるので、精神衛生上とても重要なエクステンション。

Indent Guides

インデントにあわせて縦線を表示してくれるやつ。 上の Show Whitespace とのコンボで最強になれる。

Brackets Exclude Indexing FileTree

開いているフォルダー内に 30000以上ファイルがあるとエラーになるんだが、node_moduleフォルダとかあると簡単に30000ファイルくらい超えるので、node_moduleを編集対象のフォルダから除外してくれるエクステンション。

上にあげたエクステンションのみ有効にした場合こんな感じになる。 f:id:jBellTree:20160410031653p:plain

もっとゴテゴテにカスタマイズしてた時もあったけど、今はシンプルに保つのもいいかなと思ったりしているところ。

「UXデザイン入門」読みました

www.amazon.co.jp

↑の「UXデザイン入門」を読んだ。

というのも、UIを作る技術があっても、UIといっしょに語られることが多いUXについてほとんど勉強したことがなかったので。

本の内容としては、UXを設計する過程で行うべきアンケートとかインタビューとかの方法が詳しく解説されていた。

一方で「UXデザイン入門」と言っているだけあり、どういう場合にどういうコンポーネントを使うと効果的とかいう話はほとんどなかった。そもそも、そういう定石みたいなものなんて無いのか。

面白いなーって思ったのは、設計する上で、そのアプリケーションを使用想定するターゲット(ペルソナ)を詳細に(名前や趣味まで)設定すべきっていうところで、はぁーなるほどぉってなった。

まる。

React + gulp サンプル

Material Design Lite

www.getmdl.io

React

facebook.github.io

React使いつつ、マテリアルデザインも使いたいなーと思って、Material Design Lite を組み合わせてみた時のメモ。

ビルドツールには gulp を使用したので、まず gulpfile.js から。

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var plumber = require('gulp-plumber');
var browserify = require('browserify');
var source = require("vinyl-source-stream");
var reactify = require('reactify');
var buffer = require('vinyl-buffer');


gulp.task('dist', function(){
  var bundler = browserify('./script/src/main.jsx', { debug: true });
  return bundler
        .transform(reactify)
        .bundle()
        .pipe(plumber())
        .pipe(source('build.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./script/dist/'));
});


gulp.task('watch', function() {
    gulp.watch('./script/src/*.js', ['dist']);
    gulp.watch('./script/src/*.jsx', ['dist']);
    gulp.watch('./script/src/**/*.js', ['dist']);
    gulp.watch('./script/src/**/*.jsx', ['dist']);
});


gulp.task('default', ['dist', 'watch']);

次に HTMLファイル。 body要素の最後で、ビルド後のjsファイルを読み込むようにする。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>test</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link href="./style/material.min.css" rel="stylesheet">
    <link href="./style/style.css" rel="stylesheet">
  </head>
  <body>
    <noscript>JavaScriptを有効にして下さい。</noscript>
    <div id="appView"></div>
    <script src="./script/dist/build.js"></script>
  </body>
</html>

エントリーポイントとなる main.jsx 3行目で、Material Design LiteのJavaScriptを読み込んでいる。 6行目で読み込んでいる AppView.jsx がルートコンポーネント

(function () {
    'use strict';
    var mdl = require('material-design-lite');
    var React = require('react');
    var ReactDOM = require('react-dom');
    var AppView = require('./component/AppView.jsx');

    // アプリケーション全体のコンポーネントを表示
    ReactDOM.render(
        <AppView />,
        document.getElementById('appView')
    );

}());

Go言語インストールからHelloWorld、あと特徴とか忘れないうちにメモっとく

インストール手順

MacにHomebrewを使ってインストールした。Homebrewはインストール済の前提。

$ brew install go

バージョンを確認

$ go version

Hello World!

package main

import (
  "fmt"
)

func main() {
  fmt.Println("Hello World!")
}

Hello World 実行手順

自分は以下のような sh ファイルを作った。

今回はとりあえず test.sh という名前で保存した。

export GOPATH=任意のパス
export PATH=$PATH:$GOPATH/bin
cd ${GOPATH}
go install ./src/github.com/jsuzuki20120311/go_test

Hello Worldのソースが書けたら、

$ ./test.sh

その後、別窓でターミナルを開いて

$ ./go_test
Hello World!

Hello World! が出力されればめでたしめでたし。

その他、Hello Worldやる過程で調べてわかったこととかメモ

クラスなんてものは無い 代わりに 構造体 なるものがある

実際に書いてみた。

    type box struct {
        width int
    }
     
    func (b *box) get_width() int {
        return b.width
    }
     
    func main() {
        b := box{width: 10}
        fmt.Println(b.get_width())
    }

他、継承なんてない。コンポジッション関係を使え。あとインタフェースはある。 このあたりを箇条書きにすると

  • is - a 関係 : × 代わりに has - a 使え
  • has - a 関係 : ○
  • can do 関係 : ○

また別の日にもう少し詳しく整理して書こうと思う。