gorillaでAPIサーバを書く 1
gorillaを使ってAPIサーバを書く。
ディレクトリ構成としては、以下を想定。
.api │ ├── handlers │ ├── core.go │ └── router.go └── api.go
それぞれのファイルは大まかに以下のような役割になります。
- api.goはサーバの起動設定などを記載
- router.goはファイル名の通りrouterなので、パスに合わせたハンドラの設定
- core.goはハンドラーの実装
まずは必要なパッケージのインストール
go get github.com/gorilla/mux
api.goはgorilla特有の処理などは書かないので割愛。
router.go では、mux.Routerを使ったRouter関数を定義します。 エンドポイントを指定して、エンドポイントごとにHTTPメソッドに対応するHandler関数を設定します。
package handlers import ( "net/http" "github.com/gorilla/mux" ) const ( RegexMatchUserID = "[A-Za-z0-9]{3}" ) func Router() *mux.Router { r := mux.NewRouter() s := r.PathPrefix("/api/"). Subrouter().StrictSlash(false) usersPath := "/users/" subpath := usersPath + "{userId:" + RegexMatchUserID + "}" s.HandleFunc(usersPath, GetUsers).Methods("GET") s.HandleFunc(subpath, GetUserById).Methods("GET") s.HandleFunc(subpath, DeleteUserById).Methods("DELETE") s.HandleFunc(subpath, CreateUser).Methods("POST"). Headers("Content-Type", "application/json") return r }
PathPrefixでベースとなるURLを元にエンドポイントを組み立て行く方法の他に、下記のようにPathとPathPrefixを組み合わて同じように書くことが出来ます。
func Router() *mux.Router { r := mux.NewRouter() userPath := urlbase + "/users/" users := r.Path(userPath).Subrouter() users.Methods("GET").HandlerFunc(GetUsers) subpath := userPath + "{userId:" + RegexMatchUserID + "}" usr := r.PathPrefix(subpath).Subrouter() usr.Methods("GET").HandlerFunc(GetUserById) usr.Methods("DELETE").HandlerFunc(DeleteUserById) usr.Methods("POST").HandlerFunc(CreateUser) return r }
Handlerメソッドについては、次回記載します。
SICPを読む会 1 問題1.3
SICP Support for DrRacketのインストールを参考にDrRacketをインストールして実行環境を作成します。
DrRacketで言語宣言ペイン(上側のペイン)で、#lang planet neil/sicp と書いて実行しても調べたページとは違う挙動しましたが
Schemeが実行出来るようなで練習問題を実施。
今日は問題1.3を実施。
今回は考え方としては3値のうち一番小さい値は何かという観点で手続きを定義します。
下記の一番最初のifの評価としては、『xはyよりも大きい、またはxはzよりも大きいのどちらもFalseになる = xは最も小さい』という周りくどい評価を実施しています。
> (define (square x) (* x x)) > (define (sum-of-squares x y) (+ (square x) (square y))) > (define (f x y z) (if (or (>= x y) (>= x z)) (if (or (>= y z) (>= y x)) (sum-of-squares x y) (sum-of-squares z x)) (sum-of-squares y z))) > (f 3 4 5) 41 > (f 4 3 5) 41 > (f 4 5 3) 41
また、schemeではminという手続きが定義されており最小の値を求めることが出来るので、以下のように書き換えることが出来ます。
> (define (f x y z) (if (= (min x y z) x) (sum-of-squares y z) (if (= (min x y z) y) (sum-of-squares x z) (sum-of-squares x y)) ) ) > (f 3 4 5) 41 > (f 4 3 5) 41 > (f 5 4 3) 41
このような場合はifではなくcondを使ったほうが可読性が上がるので、condを使って書き換えます。
> (define (f x y z) (cond ((= (min x y z) x) (sum-of-squares y z)) ((= (min x y z) y) (sum-of-squares x z)) (else (sum-of-squares x y)))) > (f 3 4 5) 41 > (f 4 5 3) 41 > (f 5 3 4) 41
goのお勉強1
スコープ
変数や関数名で1文字目が小文字だとパッケージ内からのみ見える。大文字だとパッケージ外からのみ見える。
ポインタ
ポインタは、C言語と同様に利用できる。
package main import "fmt" func main() { a := 5 var pa *int = &a // *intはint型のpointer fmt.Println(pa) // アドレスが表示される fmt.Println(*pa) // 値(5)が表示される *pa = 10 fmt.Println(a) // 10が表示される }
ただし、C言語と違いポインタは演算は出来ない。 c言語だと配列とかはポインタで表現され、以下のようにできるがgoでは出来ないことを確認する。 C言語では以下のように記述できる。
#include <stdio.h> int main() { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int* p = array; /* 配列の全要素の値を表示する */ for (int i = 0; i < 10; ++i) { printf("*p = %d\n", *p); p = p + 1; /* ポインタの値を 1 増やす */ } return 0; }
goで同じような処理をしようとしてみるとinvalid operationとコンパイルエラーになる。
スライスにしても同様にコンパイルエラーになる。
package main import "fmt" func main() { arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var p *[10]int = &arr for i := 0; i < 10; i++ { fmt.Println(*p) // [1 2 3 4 5 6 7 8 9 10]が出力される // fmt.Println(p[i]) とすると配列のi番目の値を出力できる p = p + 1 // invalid operation: p + 1 (mismatched types *[10]int and int) となりコンパイルエラーになる。 } }
Omnibus InstallerでインストールしたChefのRubyでserverspecを実行する
chefのバージョンを確認する。
# chef-client -v Chef: 12.0.3
Rubyのバージョンを確認する。
/opt/chef/embedded/bin/ruby -v ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-linux]
rubyなどはchef/embeddedに入っているので、serverspecのインストールを行う。
/opt/chef/embedded/bin/gem install serverspec
serverspec-initを実行する
# /opt/chef/embedded/bin/serverspec-init Select OS type: 1) UN*X 2) Windows Select number: 1 Select a backend type: 1) SSH 2) Exec (local) Select number: 2 + spec/ + spec/localhost/ + spec/localhost/sample_spec.rb + spec/spec_helper.rb + Rakefile + .rspec
serverspecを実行する
# cd spec/localhost # /opt/chef/embedded/bin/rake
パーフェクトRuby写経 特異メソッドの作り方
特異メソッドとは、クラスに定義されたメソッドの他に、そのオブジェクト固有のメソッド持つことができ、それを特異メソッドといいます。
特異メソッドを定義するには、メソッドを定義したいオブジェクトをメソッド名の前に指定してメソッドを記述します。 また、特異メソッドの中でsuperを呼び出すと、クラスに定義されている同名のメソッドが呼び出されます。
class Foo def override_me p 'in Foo class' end end foo = Foo.new bar = Foo.new def bar.singleton_method p 'Called!' end def bar.override_me p 'in Foo class' end bar.singleton_method bar.override_me
モジュールに定義されたメソッドを、オブジェクトの特異メソッドとして取り込む。 そのさいには、extendを用います。
module Sweet def self.lot %w(brownie apple-pie bavarois pudding).sample end def greet_to(name) p "Hello, #{name}. My name is #{self.class}" end end o = Object.new o.extend Sweet o.greet_to 'world' #o.lot p Sweet.lot
また、self.lotのようにモジュールのメソッド名の前にselfをつけて定義すると、モジュールの特異メソッドとなります。
また、モジュール関数は「privateなインスタンスメソッドであると同時に、モジュールの特異メソッドでもある」メソッドとの事なので、これも特異メソッドの一種のようです。
module MyFunctions def my_module_func p 'Called!' end module_function :my_module_func end
一つのメソッドの場合は上記のように記述し、複数のメソッドを定義さする場合には下記のように記述するようです。
module MyFunctions module_function def my_first_func p 'first!' end def my_second_func p 'second!' end end