node.js入門
node.jsとは
Node.jsはサーバー側で動作するJavaScriptであり、Web業界ではかなり注目されています。大量の処理に対応するために、ノンブロッキングI/Oというモデルを採用されている
いまアツいJavaScript!ゼロから始めるNode.js入門〜5分で環境構築編〜
node.js(イベントループ)
node.jsは大量のリクエストを処理していくための仕組みであるが、これまでもApacheのようにスレッドモデルの仕組みが使われていた。
スマホなどで膨大なリクエストが来た場合にどうしても対応できない問題が発生してきたのでnode.jsはイベントループという仕組みを採用した。
- スレッドモデル
リクエストが来た時にスレッドという処理が立ち上がる。 次のリクエストが来た場合、スレッドは同時に一つのリクエストしか処理できないため新しいスレッドを作って対応することになる。 スレッドを立ち上げるにはメモリを消費するのでたくさんのリクエストが来ると、スレッドを立ち上げることができなくなり、リクエストが待ち状態になってしまう。
- イベントループ
そんなスレッドモデルに代わって出てきたのがイベントループ。メインスレッドとバックグランドで動いているスレッドがある。 メインスレッドには処理待ちのキューがあって、そこに処理がたまっている間、ループを回して別のリクエストが来た場合キューに登録していく。 そしてループが回ってキューに何かが登録されているのを見たら順にバックグラウンドの処理に回す。 ただ処理が終わる順番がわからない上、ループをブロックしないように書かなくてはならない。
Webサーバーを作成する
- server.js
//httpとfsを読み込む var http = require('http'), fs = require('fs'); //settingsファイルを読み込む var settings = require('./settings'); var server = http.createServer(); //serverにリクエストが来た時の処理 server.on('request', function(req, res) { //ファイル読み込む fs.readFile(__dirname + '/public_html/hello.html', 'utf-8', function(err, data) { if (err) { res.writeHead(404, {'Content-Type': 'text/plain'}); res.write("not found!"); return res.end(); } //書き出す res.writeHead(200, {'Content-Type': 'text/html'}); res.write(data); res.end(); }); }); //serverの設定を読み込む server.listen(settings.port, settings.host); console.log("server listening ...");
- settings.js
exports.port = 1337; exports.host = '192.168.0.11'; //localhost
- public_html/hello.html
<html> <h1>Hello!</h1> </html>
ターミナルにて以下コマンドを実行する
node server.js
mysql × node.js
- mysql.js
npm install mysqlでモジュールインストール
var mysql = require('mysql'); //mysql接続情報 var connection = mysql.createConnection({ host : 'localhost', user : 'user_name', password : 'password', database : 'database_name' }); //sql作成 var sql = 'SELECT * FROM user WHERE id = ?;'; var userId = "1"; //接続する connection.connect(); //プレースホルダー使用 var query = connection.query(sql, [userId]); query //error処理 .on('error', function(err) { console.log('err is: ', err); }) //結果 .on('result', function(rows) { console.log('The res is: ', rows ); }) //終了 .on('end', function(rows) { console.log('end'); connection.destroy(); //接続終了 });
上記ソースを以下コマンドで実行
$ node mysql.js The res is: RowDataPacket { id: 1, nickname: 'kosachan' }
上記データが取得できます。 node.jsまだ入門ですが次回はフレームワークexpressと合わせたコードを書いていけたらと思います。
MacにAzure入れてみた
Azureとは
Windows Azureは世界規模に展開されているクラウドサービスで、ユーザーが数人の小規模なサービスから、数百万人規模の大量にアクセスが発生するような大規模なサービスまで、さまざまなクラウドサービスに対応し、開発や提供することができます。
インストール方法
CLIインストール
- npm パッケージのインストール
- Node.js と npm がインストールされている必要があります
[Mac] Node.js と npm をインストールする方法 [Homebrew] | CodeNote.net
次のコマンドを使用して Azure CLI パッケージをインストールします。
npm install azure-cli -g
azureコマンドが使うことができるか確認する
azure
他にも azure help
azure version
でazureの情報を確認することができました。
Azure ログインを使用した対話型認証
引数なしで azure login コマンドを使用して、次のいずれかによる対話型認証を行います。
多要素認証を必要とする職場または学校のアカウント ID (組織アカウントとも呼ばれる)
Microsoft アカウント ID (Resource Manager モード コマンドにアクセスする場合)
azure login info: Executing command login info: To sign in, use a web browser to open the page http://aka.ms/devicelogin. Enter the code XXXXXXXXX to authenticate.
上記操作で表示されたコードをコピーし、ブラウザーを開いて http://aka.ms/devicelogin (または指定された場合は別のページ) にアクセスする。コードを入力すると、使用する ID のユーザー名とパスワードを入力するように求められます。このプロセスが完了すると、コマンド シェルによってログイン プロセスが完了します。
info: Added subscription Visual Studio Ultimate with MSDN info: Added subscription Azure Free Trial info: Setting subscription "Visual Studio Ultimate with MSDN" as default + info: login command OK
次にアカウントの発行設定ファイルをダウンロードするには、次のコマンドを使用します。
azure account download
ここでサブスクリプションが取得できるはずがないというメッセージ ここでつまづきましたがmicrosoftのアカウントは作成しているがazureの無料試用版のアカウントは登録してないので取得できない。
以下URLで必要情報を入力し再度 azure account downloadをすると
ブラウザが立ち上がり
証明書のpublishsettingsファイルがダウンロードされる
次に 先ほどダウンロードしたファイルをimportする
azure account import <file>
次回は仮想マシンの作成から進めていきたいと思います。
GinでORM(xorm)を使ってみる
Gin API実装
Go言語製WAF GinでWebアプリを作ってみる【準備編】 | eureka tech blog
モデル(Model)設計
modelsディレクトリにuser.goを作成する
- Repository構造体定義
- Repository構造体に「DBからデータを取得する処理」を定義
- RepositoryからUser構造体を生成する処理を実装
ソースは以下のとおり
package models import ( "github.com/go-xorm/xorm" _ "github.com/go-sql-driver/mysql" "fmt" ) var engine *xorm.Engine // init ... func init() { var err error engine, err = xorm.NewEngine("mysql", "root:pass@/golang") if err != nil { panic(err) } } // User is type User struct { ID int `json:"id" xorm:"'id'"` Username string `json:"name" xorm:"'nickname'"` } // NewUser ... func NewUser(id int, username string) User { return User{ ID: id, Username: username, } } // UserRepository is type UserRepository struct { } // NewUserRepository ... func NewUserRepository() UserRepository { return UserRepository{} } // GetByID ... func (m UserRepository) GetByID(id int) *User { var user = User{ID: id} has, hage := engine.Get(&user) if has { return &user } return nil }
xormとは
Go言語のORM ドキュメント
Documentation - xorm: Simple & Powerful ORM Framework for Go Programming Language
1.インストール
$ go get github.com/go-xorm/xorm
2.まずデータベースのためのEngineを作る
engine, err := xorm.NewEngine(driverName, dataSourceName)
user.goのソース上では
engine, err = xorm.NewEngine("mysql", "root:pass@/golang")
driveNameにDB、dataSourceNameにユーザ名:パスワード/ DB名をそれぞれ指定する。
3.ORM Methods(基本)
- Insert
affected, err := engine.Insert(&struct) //INSERT INTO struct () values ()
- 1レコード参照
has, err := engine.Get(&user) //SELECT * FROM user LIMIT 1
- 複数レコード参照
sliceOfStructs := new(Struct) err := engine.Find(sliceOfStructs) // SELECT * FROM user
- update文
affected, err := engine.Id(...).Update(&user) // UPDATE user SET ...
- delete文
affected, err := engine.Where(...).Delete(&user) // DELETE FROM user Where ...
- レコードcount
counts, err := engine.Count(&user) // SELECT count(*) AS total FROM user
他にも複数条件や並び替えなどの指定は以下ドキュメントを参照する github.com/go-xorm/xorm - Go Walker
*Xormはまた、生のSQL実行をサポートしています
results, err := engine.Query("select * from user")
*mysqlのドライバーもinstall忘れずに
$ go get github.com/go-sql-driver/mysql
次に
xorm:”‘カラム名'”とアノテーションを入れることで、構造体のフィールドとデータベースのカラムをマッピング
type User struct { ID int `json:"id" xorm:"'id'"` Username string `json:"name" xorm:"'nickname'"` }
Controller実装
modelのNewUserRepositoryからGetByIDの中身を取得して返すcontrollerを作成
package controllers import ( "golang/models" ) // User type User struct { } // NewUser func NewUser() User { return User{} } // Get func (c User) Get(n int) interface{} { repo := models.NewUserRepository() user := repo.GetByID(n) return user }
main.go実装
main.goにuser_idユーザー情報を返します。
package main import ( "golang/controllers" "github.com/gin-gonic/gin" "reflect" "strconv" ) // main ... func main() { router := gin.Default() router.GET("/:id", func(c *gin.Context) { // Pramを処理する n := c.Param("id") id, err := strconv.Atoi(n) if err != nil { c.JSON(400, err) return } if id <= 0 { c.JSON(400, gin.H{"status": "id should be bigger than 0"}) return } // データを処理する ctrl := controllers.NewUser() result := ctrl.Get(id) if result == nil || reflect.ValueOf(result).IsNil() { c.JSON(404, gin.H{}) return } c.JSON(200, result) }) router.Run(":8080") }
ここまででhttp://localhost8080/:idを指定すると DBに入っている情報を参照してデータを返してくれることが分かりました。
ここまではチュートリアルなので次回はviewなどを作り簡易なサイトを作成できればと思います。
Mysqlをローカルに入れてみる(Mac)
Mysqlインストール
前回の記事でGoのwebフレームワークを使ってAPIを実装するにあたりローカルにMysqlを用意してMVCを実装してみる。
以下コマンドでインストール
$ brew install mysql
mysqlのバージョンを確認する
$ brew info mysql mysql: stable 5.7.14 (bottled) Open source relational database management system https://dev.mysql.com/doc/refman/5.7/en/ Conflicts with: mariadb, mariadb-connector-c, mysql-cluster, mysql-connector-c, percona-server /usr/local/Cellar/mysql/5.7.14 (13,467 files, 447M) * Poured from bottle on 2016-09-02 at 00:12:25
サーバーを開始してみる
$ mysql.server start Starting MySQL . SUCCESS!
mysqlにログインしてみる
$ mysql -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.7.14 Homebrew Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
こんな感じでログインできたことがわかります。
次にパスワードを設定してみる
Mysqlでのパスワード設定
ここで少しつまづく
$ mysql_secure_installation
ここでpaswordの強度を聞かれる - Low - Medium - Strong
何も確認せずとりあえずMediumを使って半角英数字小文字と数字で設定すると 以下エラーが出る
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
MySQL 5.7.8以降のrpmパッケージではvalidate_passwordプラグインがデフォルトで有効になっているらしい
mysql> SHOW VARIABLES LIKE 'validate_password%'; +--------------------------------------+--------+ | Variable_name | Value | +--------------------------------------+--------+ | validate_password_dictionary_file | | | validate_password_length | 8 | | validate_password_mixed_case_count | 1 | | validate_password_number_count | 1 | | validate_password_policy | MEDIUM | | validate_password_special_char_count | 1 | +--------------------------------------+--------+
どうやら特殊文字と半角大文字が一文字ずつ必要だったらしい
今回はローカルでしか使わないのでセキュリティレベルを落としてパスワード作成
mysql> SET GLOBAL validate_password_policy=LOW; Query OK, 0 rows affected (0.00 sec)
そしてもう一度以下コマンドで設定していくとパスワードを設定することができます。
$ mysql_secure_installation
ログインしてみる
$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 14 Server version: 5.7.14 Homebrew Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
無事ログインできました。
おまけ(mysqlセキュリティポリシー)
LOW ポリシーは、パスワードの長さのみテストします。パスワードは少なくとも 8 文字の長さでなければなりません。
MEDIUM ポリシーは、パスワードが最低 1 つの数値文字を含み、1 つの小文字および大文字を含み、1 つの特殊文字 (英数字以外) を含む必要があるという条件を追加します。
STRONG ポリシーは、パスワードの 4 文字以上の部分文字列が、(辞書ファイルが指定された場合に) 辞書ファイル内の単語と一致してはならないという条件を追加します。
Gin入門編やってみた(Mac)
Ginとは
Go言語のWebFrameworkの一つです。
参考
エウレカさんのチュートリアルを途中まで再現してみました。 APIですこしつまづいているのでAPI実装は次回の記事で
Go言語製WAF GinでWebアプリを作ってみる【準備編】 | eureka tech blog
Goのインストール
$ brew install go
macでは一発でインストールできますがwindowsではすこし手間がかかりますが簡単にインストールできます。
goのバージョンを確認
$ go version go version go1.6.2 darwin/amd64
Ginインストール
Goの触れる環境を作成したら次にGinをインストールしてみる。 まずはGOPATHとGOROOTの設定
export GOPATH="$HOME/repos/gohome" export GOROOT="/usr/local/opt/go/libexec" export GOBIN="$GOPATH/bin" export PATH="$GOBIN:$GOROOT/bin:$PATH"
設定が反映されているか確認してみる
$ go env GOARCH="amd64" GOBIN="/bin" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOOS="darwin" GOPATH="/Users/home/code/golang" GORACE="" GOROOT="/usr/local/opt/go/libexec" GOTOOLDIR="/usr/local/opt/go/libexec/pkg/tool/darwin_amd64" GO15VENDOREXPERIMENT="1" CC="clang" GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common" CXX="clang++" CGO_ENABLED="1"
ここまでできたらGinをインストールしてみる
$ go get github.com/gin-gonic/gin
これでGinがインストールされます。
HelloWorld
ブラウザで確認してみる 1.まずは開発用のディレクトリを作成し main.goファイルを作成する。
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.String(200, "Hello world") }) r.GET("/hoge", func(c *gin.Context) { c.String(200, "fuga") }) r.Run(":8080") }
サーバー起動
$ go run main.go [GIN-debug] GET / --> main.main.func1 (3 handlers) [GIN-debug] GET /hoge --> main.main.func2 (3 handlers) [GIN-debug] Listening and serving HTTP on :8080 [GIN] 2016/09/01 - 22:42:19 | 200 | 94.169µs | ::1 | GET / [GIN] 2016/09/01 - 22:42:27 | 404 | 1.202µs | ::1 | GET /fuga [GIN] 2016/09/01 - 22:42:38 | 200 | 6.408µs | ::1 | GET /hoge
localhost:8080にアクセスすると
localhost:8080/hogeでアクセスするとfugaがでてきます。
サーバにアクセスするごとにコマンドラインでGETリクエストがきていることがわかります。
次回はつまづいているAPIを実装してみようと思います。
1週間Go言語を勉強して登壇してみた vol.2
Go言語 × SlackAPI
この記事ではGo言語とslackAPIを用いてメッセージを送ってみようと思う
Slackとは
主にビジネス向けのチャットツールを使っている Slackは2013年8月のリリース後、わずか2年半でDAU200万を突破、2016年5月時点ではDAU300万を突破した、アメリカ発のサービスである。
背景
このままではLTでGoの文法紹介になってしまうため 何かものを作ろうと思った。
台風が最近多く天気が不安なことがあるのでlivedoorの天気予報RSSを利用して明日の天気と気温を通知してくれるサービスを作ってみた。
SlackAPI(Incomming WebHooks)を使用する(LT登壇まであと3日)
- Incomming WebHooksとは?
=Slackが発行するURLへPOSTするとSlackにメッセージが投稿される簡単にメッセージを送ることができるAPIである。
上記からTokenを取得する。
Goを使ってslackに通知してみた(LT登壇まであと2日)
http.clientを使ってGETリクエストを送信してみた。
実際のソースは以下である
package main import ( "bytes" "net/http" "net/url" "fmt" ) var( token string = ""//Token追記 apiUrl string = "https://slack.com/api/chat.postMessage" ) func main() { data := url.Values{} data.Set("token",token) data.Add("channel","#general") data.Add("username","testBot") data.Add("text", "test") client := &http.Client{} r, _ := http.NewRequest("POST", fmt.Sprintf("%s",apiUrl), bytes.NewBufferString(data.Encode())) r.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, _ := client.Do(r) fmt.Println(resp.Status) }
実行するとこれだけでslackにメッセージを送ることができます。
Goでslackに天気予報通知してみた(LT登壇まであと1日)
登壇まであと残すところあと1日
以下のlivedoorRSSを用いて東京の天気予報を取得する。
http://weather.livedoor.com/forecast/rss/area/130010.xml
package main //packageをimport import ( "bytes" "net/http" "net/url" "fmt" "encoding/xml" "io/ioutil" "log" ) //変数宣言 var( //SlackAPIトークン token string = "" //SlackApiのメッセージリクエストURL apiUrl string = "https://slack.com/api/chat.postMessage" //livedoor天気予報のRSS(東京) FEED_URL string = "http://weather.livedoor.com/forecast/rss/area/130010.xml" ) //構造体 type WeatherHack struct { Title string `xml:"channel>title"` Description []string `xml:"channel>item>description"` } func main() { //getWeather関数にRSSのURLを渡す wh, err := getWeather(FEED_URL) //error処理 if err != nil { log.Fatalf("Log: %v", err) return } //URLに生成するデータを追加 data := url.Values{} data.Set("token",token) data.Add("channel","#general") data.Add("username","天気予報Bot") data.Add("icon_url","http:~~~.jpg") data.Add("text", wh.Description[2]) fmt.Println(data) //http.clientを使用してGETリクエスト送信 client := &http.Client{} r, _ := http.NewRequest("POST", fmt.Sprintf("%s",apiUrl), bytes.NewBufferString(data.Encode())) r.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, _ := client.Do(r) fmt.Println(resp.Status) } //天気情報を取得する func getWeather(feed string) (p *WeatherHack, err error) { //http.Getメソッドを利用してGETリクエストを送る res, err := http.Get(feed) if err != nil { return nil, err } b, err := ioutil.ReadAll(res.Body) if err != nil { return nil, err } wh := new(WeatherHack) err = xml.Unmarshal(b, &wh) return wh, err }
上記をターミナルにて以下コマンドを実行する
go run ファイル名.go
実行ができたら 200 OKと返ってくる
slackに通知が来ているので確認してみると 以下のように天気が通知されていることがわかります。
無事本田翼さんから天気予報が届いたことが確認できました。
Goをしてみたまとめ
コンパイル型を使ったことがそんなに多くないので型宣言を忘れがちになった
1週間でここまでしたがまだまだメソッドなど多く奥が深い
GETリクエスト以外にもPOSTだけで5通りもの方法がある
エラーがわかりやすいため学習が比較的スムーズにできた
Goを一週間してきたことをまとめてみましたが まだまだここからがスタートなので次は並列処理、ポインタの理解をより深めてマスターして記事を公開していきます。
1週間Go言語を勉強して登壇してみた vol.1
Go言語
「Go」は2009年にGoogleによって発表されたコンパイラ型のプログラミング言語である。
YouTubeやDropbox、Uberなどでもサービスのクリティカルな部分にGo言語を採用されている界隈で有名な言語となっている 特にGo言語は処理速度がとても速いため、APIのバックエンドやバッチ処理など「パフォーマンスがネックとなる部分」に採用されることが多いです。Androidの開発にも使える。
Goを始めた理由
- もともとGoに興味があったがしていなかった。
- 社外の人との合同LT会(勉強会)で登壇することに
- LTまでの1週間の間に新言語をどれだけ習得できるのかやってみたかった(5日間は別仕事してるので仕事を終えてからです)
GoTour始めてみた(LT登壇まであと7日)
先輩エンジニアの人に勧めていただいたGoTourを3日で終わらようと決意
phpと違うなと感じたこと(LT登壇まであと6日)
GoTourを文法を一通り終わらせてbasicまでやってみて気づいたことを書いてみる。
- コンパイル型であること
- 並列処理ができること
- 変数名の 後ろ に型名を書く
- 変数に暗黙的な型宣言ができる etc.(k := 3)
- Goはポインタを扱うことができる
- defer ステートメントという呼び出し元の関数の終わり(returnする)まで遅延させるものがあること。
- 特有の構造体を持っていること
goにwhile文がなくfor文でループすることができる。
- 標準のfor文
func main() { for i := 0; i < 10; i++ { } }
- whileのfor文での記述
func main() { for sum < 1000 { } }
- 並列処理とは
func main() { go func() { //このブロックは並列して実行される }() //このブロックは上の記述と同時に実行される }
go特有の構造体
Goはクラスや継承の機能がないが以下のこれらを用いることでオブジェクト指向プログラミングが可能になる。
- メソッドの定義
- 構造体埋め込み
構造体の定義と初期化 - Goの場合、大文字から始まる名前 (関数名、型名、フィールド名) は、他のパッケージからアクセス可能になる
//構造体定義 type User struct { name string age int } //User構造体にアクセス var u User u.name = "taro" u.age = 30 fmt.Printf("name:%s", u.name)
- Goの構造体は以下のような初期化関数を作るのが一般的である
func newUser(name string, age int) *User { u := new(User) u.name = name u.age = age return u } var user *User = newUser("taro",30)
急いで学ぶGo lang#5 構造体 | Developers.IO
Goで何を作ろうか考える(LT登壇まであと4日)
長くなってきたので次の記事へ続く...。