Go言語とTypeScript(JavaScript)でライブラリなしでAjaxなコードを書いてみた

Go & TypeScriptでAjax

ライブラリなしで、GoとjavaScript(実際に実装したのはTypeScriptですが)を使って本当に簡単なAjaxなアプリ?を書いた

なお、コードの詳細な説明はコード中のコメントに記載していて、本文では大まかな流れの説明のみを記載している

プロジェクト構成

apprppt
      |_source
      |      |_index.js 
      |      |_index.ts
      |      |_package.json
      |      |_tsconfig.json
      |_view
      |    |_index.html
      |_main.go

フロント側の設定ファイル

package.json

{
  "name": "ajax",
  "version": "1.0.0",
  "description": "ajax",
  "main": "./index.js",
  "scripts": {
    "start": "",
    "build": "tsc index.ts"
  },
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "typescript": "^2.1.6"
  },
  "dependencies": {},
  "directories": {},
  "repository": {
    "type": "git",
    "url": "github.など"
  },
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "github.など"
  },
  "homepage": "github.など"
}

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "moduleResolution": "node",
        "target": "es5",
        "declaration": true,
        "sourceMap": true,
        "lib": [
            "dom",
            "es5"
        ],
        "noImplicitAny": true,
        "strictNullChecks": false,
        "noFallthroughCasesInSwitch": true,
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitUseStrict": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "forceConsistentCasingInFileNames": true,
        "traceResolution": false,
        "listFiles": false,
        "stripInternal": true,
        "skipDefaultLibCheck": true,
        "skipLibCheck": false,
        "pretty": false,
        "noEmitOnError": true
    },
    "include": [
        "./**/*.ts"
    ],
    "types": [
    ],
    "exclude": [
        "node_modules",
        "code/definition-file/usage/",
        "code/definition-file/augmentGlobal/",
        "code/definition-file/issue9831/",
        "code/**/*-invalid.ts",
        "code/**/*-invalid.d.ts",
        "code/**/invalid.ts",
        "code/**/invalid.d.ts",
        "code/**/*-ignore.ts",
        "code/**/*-ignore.d.ts",
        "code/**/ignore.ts",
        "code/**/ignore.d.ts"
    ]
}

HTMLファイル

index.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>Ajax</title>
</head>

<body>
<p id="click-here"> click here</p>
      <script type="text/javascript" src="../source/index.js"></script>
</body>

</html>

「click here」をクリックすると、「非同期」というポップアップが表示され、その後にJsonを反映した以下の文字が表示される

名前 : Go
型 : Static

TypeScriptファイル

index.ts

const id = 'click-here';
// idで指定して、elemntを取得
const e = document.getElementById(id);
// イベントリスナー登録
// クリックされたら、コールバック関数発動
e.addEventListener('click', () => {
    // 生のjavaScriptでAjaxを行うためには、XMLHttpRequestを使用する

    // XMLHttpRequestインスタンスの生成
    const httpRequest = new XMLHttpRequest();

    // openメソッド : リクエストを初期化する
    // 第1引数で、GETかPOSTのリクエストメソッドを指定
    // 第2引数で、"リクエスト先のURL"
    // 第3引数で、同期か非同期かの選択(非同期の場合は、true)
    httpRequest.open("GET", "/json", true)

    // readyStateプロパティ : XMLHttpRequestオブジェクト(HTTPリクエスト)のサーバとの通信の状態
    // この値がサーバとの通信状態によって変化する
    // readyStateプロパティの値が変化するたびにonreadystatechangeイベントが発生する
    // このonreadystatechangeイベントが発生したら、readyStateプロパティをチェックすれば、現在の通信状態を知ることができる

    console.log(httpRequest.readyState);

    // XMLHttpRequestオブジェクト(HTTPリクエスト)のonreadystatechangeイベントが発生したら、=で与えた関数が発動する
    httpRequest.onreadystatechange = () => {

        // 通信が完了したならば
        if (httpRequest.readyState === 4 && httpRequest.status === 200) {
            // jsonをtextデータとして受け取る
            const jsonText = httpRequest.responseText

            // textデータとして受け取ったjsonをパース
            const json = JSON.parse(jsonText);

            // 通信が完了(受信)したら、行う処理を記載
            e.innerHTML = `
            <p>名前: ${json["Name"]}</p>
            <p>型 : ${json["LangType"]}</p>
            `
        }
    }
    // sendメソッド : openで作成したHTTPリクエストをサーバへ送信する
    // POSTの場合は、送信するデータを引数で与える
    // GETの場合は、nullを引数で与える
    httpRequest.send(null);

    // 非同期のテスト
    // 非同期で通信しているので、HTMLの<p>が変化するよりもこちらの方が先に呼び出される
    window.alert('非同期');

})

index.tsでやっていること

<p id="click-here"> click here</p>に対して、イベントリスナーを登録して、「click here」をクリックすると e.addEventListener('click', () => {} で登録しているコールバック関数が呼び出される

コールバック、非同期処理に関しては以下の記事がわかりやすい
http://qiita.com/YoshikiNakamura/items/732ded26c85a7f771a27 http://qiita.com/kiyodori/items/da434d169755cbb20447

コールバック関数内で、XMLHttpRequestオブジェクトを生成してクライアントからサーバへリクエストを送信している

XMLHttpRequest は、クライアントとサーバーの間でデータを伝送するための機能をクライアント側で提供する API です。
https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest (引用元)

今回はXMLHttpRequestで非同期でクライアントからサーバへリクエストを送信しているので、クリックされると、後に記載されている window.alert('非同期'); が先に呼ばれて、 <p id="click-here"> click here</p>の要素がJsonの値を反映したものに変化するより先に、windowのalertがポップアップされる

その他のXMLHttpRequestオブジェクトを使用したクライアントからサーバへのリクエストの送信処理の詳しいことは、コード中にコメントとして記載している

Goファイル

main.go

package main

import (
    "fmt"
    "net/http"
    "html/template"
    "encoding/json"
)

func main() {
    fmt.Println("The Server runs with http://localhost:8080/")
    http.Handle("/source/", http.StripPrefix("/source/", http.FileServer(http.Dir("source/"))))
    http.HandleFunc("/", Handler)
    http.HandleFunc("/json", JsonHandler)
    http.ListenAndServe(":8080", nil)
}
// 構造体
type Language struct {
    Name     string
    LangType string
}

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

    tmpl := template.Must(template.ParseFiles("./view/index.html"))
    tmpl.Execute(w, nil)
}

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

    // 構造体をインスタンス化
    l := Language{Name : "Go", LangType: "Static"}

    // Header() : WriteHeaderによって送信されるheaderのmapを返す
    // func (h Header) Set(key, value string)
    // headerエンティティのkeyに対してvalueを関連付ける
    w.Header().Set("Content-Type", "application/json; charset=utf-8")

    // WriteHeader(int) : ステータスコードと共にHTTPのレスポンスヘッダを送信する
    // http.StatusOKは200が設定されている
    w.WriteHeader(http.StatusOK)

    // Encoderは、出力ストリームにJSONオブジェクトを書き込む
    // NewEncoder(w io.Writer) : wに書き込みを行い、新しいEncoderを返す
    // Encode() : 引数のJSONエンコーディングをWriterに書き込む
    json.NewEncoder(w).Encode(l)
}

main.goでやっていること

XMLHttpRequestオブジェクトでリクエストが送信され、"/json"のURLに登録されているハンドラが発動する
構造体のフィールドを元に、JSONにしレスポンスしている

参考にさせていただいたサイト

https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest http://qiita.com/katsunory/items/9bf9ee49ee5c08bf2b3d http://www.ajaxtower.jp/ini/ http://www.ajaxtower.jp/ini/http/index2.html http://www.ajaxtower.jp/ini/http/index4.html

※ Qiitaでも同一記事を投稿している http://www.sekky0905.com/entry/2017/02/25/Go%E8%A8%80%E8%AA%9E%E3%81%A8TypeScript%28JavaScript%29%E3%81%A7%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AA%E3%81%97%E3%81%A7Ajax%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%84 qiita.com