株式会社diffeasyでフロントエンドエンジニアをやっているカオルコです!
普段、バックエンドの方が用意してくれたデータをひたすら表示するお仕事をしていますが、APIリクエスト投げた向こう側の世界、のぞいてみたくなりませんか・・・!?
というわけで、超シンプルなRESTful APIをJavaScriptで実装して、データの流れを追っかけてみました😎
言葉遣い、用語の使い間違いがあればそっと教えて下さいmm
この記事は diffeasy Advent Calendar 2018 15日目の記事です。
前提
- npm(6.4.1)
- vue/cli(3.1.1)
- Vue(2.5.17)
- Vuex
- axios
- Express(4.16.0)
▼フォルダ構成
practice-express/
├ client/
│ ├ package.json
│ └ ...
└ server/
├ package.json
└ ...
client/配下にVueのソースを、server/配下にExpressのソースを置いていきます。
フロントエンドの構築
インストール
# vue/cliをインストールしていない場合
npm install -g @vue/cli
cd ~/workspace/practice-express
vue create client
# vue createが終了したら
cd client
npm insall
npm install axios --save
# 起動後、`http://localhost:8080/`にアクセス
npm run serve
Hello, Vue🎉
Storeを構成する
practice-express/
├ client/
│ ├ package.json
│ ├ ...
│ ├ store/
│ │ ├ modules/
│ │ │ ├ test.js
│ │ │ └ ...
│ │ ├ index.js
│ │ └ mutation.js
│ └ ...
今回はstore/index.jsにVuexのインスタンス定義をし、store/modules/配下にapiを投げるモジュールを書いていきます。
store/mutation.jsには定数を定義しています。(→ミューテーション・タイプに定数を使用する)
リクエスト投げ投げモジュールを作成
import axios from 'axios'
const API_URI = 'http://localhost:3000'
import {
TEST, TEST_FAILURE, TEST_SUCCESS
} from '../mutation'
export default {
state: {
test: null
},
getters: {
test: state => {
return state.test
}
},
actions: {
[TEST] (params = null) {
let data = {}
if (params) data = params.data
axios.get(API_URI + '/test', {data: data})
.then(res => {
if (res.status === 200 || res.status === 304) {
if (res.data.error) {
this.commit(TEST_FAILURE, res.data)
} else {
this.commit(TEST_SUCCESS, {data: res.data, callback: params.callback})
}
}
})
.catch(error => {
throw error
})
}
},
mutations: {
[TEST_FAILURE] (state, data) {
console.log('TEST_FAILURE')
},
[TEST_SUCCESS] (state, data) {
console.log('TEST_SUCCESS')
state.test = data.data.text
if (data.callback) {
data.callback(data.data)
}
}
}
}
これでthis.$store.dispatch('TEST')
とコンポーネント内で呼ぶと、http://localhost:3000/test
へgetリクエストが発生するようになりました!
バックエンドの構築
インストール
cd ~/workspace/practice-express
mkdir app
cd app
npm init
npm install express-generator -g
# expressをviewエンジンなしでインストール
express --no-view
# 起動後、`http://localhost:3000/`にアクセス
DEBUG=myapp:* npm start
Hello, Express🎉
自動生成されたファイルを眺めてみる
practice-express/
└ server/
├ ...
├ package.json
├ app.js
├ bin/
│ └ www
├ public/
└ routes/
└ index.js
bin
環境立ち上げ時に実行される処理を置くところ
public/
静的ファイルを置くところ
http://localhost:3000/
はここのindexを表示するみたい
routes/
ルーティング処理を置くところ
クライアントからの要求に対しての処理群
app.js
メインファイル
共通する設定や処理はここに書く
APIを実装してみる
http://localhost:3000/test
へGETリクエストが来たら、{"text":"success!"}
を返すAPIを作ります。
まずは、ルーティングを作成。
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var testRouter = require('./routes/test'); // ←追加
var app = express();
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/test', testRouter); // ←追加
module.exports = app;
実際に処理をするファイルを作成
var express = require('express')
var router = express.Router()
router.get('/', function(req, res, next) {
const data = {
text: 'success!'
}
res.send(data)
})
module.exports = router
expressを再起動し、http://localhost:3000/test
へアクセスしてみます。
{"text":"success!"}
と表示されたら大成功🎉
VueからExpressにリクエストを投げ、レスポンスデータを表示する
フロントエンドとバックエンド、それぞれのピースはできたので、組み合わせてみます。
buttonをクリックするとtextareaにレスポンスデータが表示されるコンポーネントを作成しました。
<template>
<div>
<button type="button" @click="click">get</button>
<textarea v-model="test"></textarea>
</div>
</template>
<script>
export default {
name: "HelloWorld",
computed: {
test () {
return this.$store.getters.test
}
},
methods: {
click () {
this.$store.dispatch('TEST')
}
}
};
</script>
🙃
CORS(オリジン間リソース共有)
異なるドメインに対してアクセスを行ったとき、許可なくレスポンスデータを読み込むことができない仕組みです。
スキーム・ホスト・ポート番号で評価されます。
(→ https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)
今回はhttp://localhost:8080
とhttp://localhost:3000
でポートを分けて実装したので怒られたようです。
Express側で、http://localhost:8080
からのレスポンスデータ読み込みを許可します。
// CORSを許可する処理を追加
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next()
})
🎉🎉🎉
最後に
マークアップエンジニア出身なこともあり、JavaScript以外の言語に馴染みがないので、APIを作って学んでみるのにExpressはとてもいいなと思いました!(何をやってるか読解するのにストレスがあまりない)
今回はGETのみでしたが、次回はCRUD制覇したり、認証まわりの実装にチャレンジしたりしたいと思います!
Have a nice RESTful!