【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜登録・更新・削除
目次
前回に引き続き今回もExpressで開発したREST APIをNuxt.jsで実行するということをやっていきたいと思います。
前回は取得までをやりましたが、今回は登録・更新・削除のAPIを叩いていきましょう。
前回の記事をまだ読んでいない方はこちらから先にご覧ください。
【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜取得
https://www.dailyupblog.com/web_development/1078/
それでは早速いきましょう。
データを登録するAPIを実行する
まず、データ登録APIを実行していきましょう。
まず、apiを追記するので、「api」フォルダ内のindex.tsを開きましょう。
import axios from "axios";
const myApi = axios.create({
baseURL: "http://localhost:5000/meibo",
responseType: "json"
});
export default {
async getMeiboData() {
try {
const response = await myApi.get("");
return response.data;
} catch (error) {
console.log(error);
}
},
async getIdMeiboData(id: string) {
try {
const response = await myApi.get(`/${id}`);
return response.data;
} catch (error) {
console.log(error);
}
},
//追記
async postMeiboData(data: any) {
try {
await myApi.post("", data);
} catch (error) {
console.error(error);
}
}
};
上記のようにpostMeiboData関数を追記しました。
続いて、入力フォームのコンポーネントを作成します。
「components」フォルダ内にForm.vueファイルを作成します。
Form.vueファイルには下記のように記述しましょう。
<template>
<el-form :model="form" ref="form" label-width="120px" class="demo-ruleForm">
<el-form-item label="Name" prop="name">
<el-input v-model="form.meibo_data.name"></el-input>
</el-form-item>
<el-form-item label="Intro" prop="intro">
<el-input v-model="form.meibo_data.intro"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="postData()">追加する</el-button>
<el-button @click="changePage(Path.HOME)">戻る</el-button>
</el-form-item>
</el-form>
</template>
<script>
import Vue from "vue";
import { Path } from "~/constants";
import meiboApi from "~/api/index";
export default Vue.extend({
data () {
return {
form: {
meibo_data: {
name: '',
intro: ''
}
},
Path: Path
}
},
methods: {
resetForm (form) {
this.$refs[form].resetFields();
},
async postMeiboData () {
await meiboApi.postMeiboData(this.form);
},
changePage (path) {
this.$router.push({ path });
},
postData () {
this.postMeiboData();
this.changePage(Path.HOME);
}
}
});
</script>
name、introといった二つの入力フォームを設置しました。
idはExpress側でランダムな文字列を生成してくれるので、入力欄は不要です。
「追加する」ボタンをクリックすると、postData関数を呼び出すようにしています。
このpostData関数の中ではpostMeiboData関数を呼び出して、登録APIを叩いています。
changePage関数も呼び出して、APIを叩いた直後にトップページに遷移するようにしています。
async postMeiboData () {
await meiboApi.postMeiboData(this.form);
},
changePage (path) {
this.$router.push({ path });
},
postData () {
this.postMeiboData();
this.changePage(Path.HOME);
}
また、「追加する」ボタンの横には「リセット」ボタンを設けて、クリックでresetForm関数を呼び出すようにしています。
resetForm (form) {
this.$refs[form].resetFields();
},
これにより、入力内容をリセットすることができます。
続いて、このコンポーネントを呼び出すためのページを作ります。
「pages」フォルダ内にpost.vueファイルを作成してください。
post.vueには下記のように記述しましょう。
<template>
<div class="container">
<h1>名簿を追加する</h1>
<Form />
</div>
</template>
<script>
import Vue from "vue";
export default Vue.extend({
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
}
</style>
続いて、このページへ遷移させるためのボタンを設置しましょう。
まず、ページを遷移させるためにpathに追加しましょう。
「constants」フォルダ内のPath.tsを開いて下記のように追記しましょう。
export enum Path {
HOME = "/",
RESULT = "/result",
POST = "/post" //追記
}
次に、「pages」フォルダ内のindex.vueとresult.vueに下記のように記述しましょう。
<template>
<div class="container">
<h1>名簿アプリケーション</h1>
<SearchForm />
<el-button @click="changePage(Path.POST)">名簿を追加</el-button> //追記
<Table v-bind:getTableData="tableMeiboData" />
</div>
</template>
<script>
import Vue from "vue";
import meiboApi from "~/api/index";
import { Path } from "~/constants";
export default Vue.extend({
data () {
return {
tableMeiboData: [],
Path: Path
};
},
methods: {
async getMeiboData () {
const res = await meiboApi.getMeiboData();
this.tableMeiboData = res.data;
},
changePage (path) {
this.$router.push({ path });
}
},
mounted () {
this.getMeiboData();
}
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
}
table th,
table td {
padding: 0.8em;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
text-align: left;
}
</style>
<template>
<div class="container">
<h1>名簿アプリケーション</h1>
<SearchForm />
<el-button @click="changePage(Path.POST)">名簿を追加</el-button> //追記
<Table v-bind:getTableData="tableMeiboData" />
</div>
</template>
<script>
import Vue from "vue";
import meiboApi from "~/api/index";
import { Path } from "~/constants"; //追記
export default Vue.extend({
data () {
return {
tableMeiboData: [],
Path: Path //追記
};
},
methods: {
async getIdMeiboData () {
const res = await meiboApi.getIdMeiboData(this.$route.query.id);
this.tableMeiboData = res.data;
},
changePage (path) { //追記
this.$router.push({ path });
}
},
mounted () {
this.getIdMeiboData();
},
watch: {
'$route' (to, from) {
this.getIdMeiboData()
}
},
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
}
</style>
ここまでできたら、完成です。
expressとnuxtを起動して、ブラウザで「http://localhost:3000」にアクセスしてみてください。
すると下記のように「名簿を追加」ボタンが追加されているはずです。
このボタンを押すと編集画面に飛びます。
下記のように適当に入力して、「追加する」ボタンを押してみましょう。
下記のようにデータが追加されたら成功です!
データを更新するAPIを実行する
続いてはデータベースのデータを更新するAPIを実行してみましょう。
まず、更新APIを追加するので、「api」フォルダ内のindex.tsを開いて下記のように追記してください。
import axios from "axios";
const myApi = axios.create({
baseURL: "http://localhost:5000/meibo",
responseType: "json"
});
export default {
async getMeiboData() {
try {
const response = await myApi.get("");
return response.data;
} catch (error) {
console.log(error);
}
},
async getIdMeiboData(id: string) {
try {
const response = await myApi.get(`/${id}`);
return response.data;
} catch (error) {
console.log(error);
}
},
async postMeiboData(data: any) {
try {
await myApi.post("", data);
} catch (error) {
console.error(error);
}
},
// 追加
async putMeiboData(data: any, id: string) {
try {
await myApi.put(`/${id}`, data);
} catch (error) {
console.error(error);
}
}
};
第一引数のデータを第二引数のidをパスパラメーターとして、更新APIを実行しています。
続いて、更新フォームのコンポーネントを追加しましょう。
「components」フォルダ内にEditForm.vueを作成して下記のように記述しましょう。
<template>
<el-form :model="form" ref="form" label-width="120px" class="demo-ruleForm">
<el-form-item label="Name" prop="name">
<el-input v-model="form.meibo_data.name"></el-input>
</el-form-item>
<el-form-item label="Intro" prop="intro">
<el-input v-model="form.meibo_data.intro"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="putData()">更新する</el-button>
<el-button @click="changePage(Path.HOME)">戻る</el-button>
</el-form-item>
</el-form>
</template>
<script>
import Vue from "vue";
import { Path } from "~/constants";
import meiboApi from "~/api/index";
export default Vue.extend({
data () {
return {
form: {
meibo_data: {
name: '',
intro: ''
}
},
Path: Path
}
},
methods: {
async getIdMeiboData () {
const res = await meiboApi.getIdMeiboData(this.$route.query.id);
this.form.meibo_data.name = res.data[0].name;
this.form.meibo_data.intro = res.data[0].intro;
},
async putMeiboData () {
await meiboApi.putMeiboData(this.form, this.$route.query.id);
},
changePage (path) {
this.$router.push({ path });
},
putData () {
this.putMeiboData();
this.changePage(Path.HOME);
}
},
mounted () {
this.getIdMeiboData();
}
});
</script>
Elementのel-formで作成します。
まず、ページ遷移後にクエリパラメーターからidを取ってきて、id絞り込みデータ取得APIを実行します。
下記のように、取得APIを呼び出した後に、とってきたデータのnameとintroをform内のそれぞれに代入しましょう。
こうすることで、ページ遷移後にフォーム内にデフォルトで更新内容が入っている状態になります。
async getIdMeiboData () {
const res = await meiboApi.getIdMeiboData(this.$route.query.id);
this.form.meibo_data.name = res.data[0].name;
this.form.meibo_data.intro = res.data[0].intro;
},
下記箇所にて、putData関数では、データ更新APIとその後にTOPにページ遷移させる処理を実行するように記述しています。
async putMeiboData () {
await meiboApi.putMeiboData(this.form, this.$route.query.id);
},
changePage (path) {
this.$router.push({ path });
},
putData () {
this.putMeiboData();
this.changePage(Path.HOME);
}
続いて、ページを作成します。
「pages」フォルダ内にedit.vueを作成してください。
下記のように記述します。
<template>
<div class="container">
<h1>名簿を更新する</h1>
<EditForm />
</div>
</template>
<script>
import Vue from "vue";
export default Vue.extend({
data () {
}
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
}
</style>
ここでは、先ほど作ったEditFormコンポーネントを呼び出します。
次はこの更新ページへ遷移するために、名簿テーブル内に更新ボタンを設置します。
今回作ったページに遷移させる必要があるため、「constants」のPath.tsに下記のように追記しましょう。
export enum Path {
HOME = "/",
RESULT = "/result",
POST = "/post",
EDIT = "/edit" //追加
}
ここまでできたら、次は「components」フォルダ内のTable.vueを開いて下記のように記述してください。
<template>
<div>
<el-table :data="getTableData" style="width: 100%">
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name" label="Name" width="180"></el-table-column>
<el-table-column prop="intro" label="Intro"></el-table-column>
<el-table-column>
<template slot-scope="scope" label="No">
<el-button @click="changePage(Path.EDIT, scope.$index)">更新</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Vue from "vue";
import { Path } from "~/constants";
export default Vue.extend({
props: {
getTableData: {
type: Array,
default: () => { }
}
},
data () {
return {
dataArray: this.getTableData,
Path: Path
}
},
methods: {
changePage (path, index) {
this.$router.push({ path, query: { id: this.getTableData[index].id } });
}
},
mounted () {
console.log(this.dataArray);
}
});
</script>
まず、template内には下記の更新ボタンを追加しました。
更新ボタンをクリックすると、changePage関数が実行されますが、引数には遷移先のパスと、クリックしたテーブルの行のidを入れます。
この際、idをとってくるためにslot-scopeを使います。
このslot-scopeを使うことでel-tableで渡された:data=”getTableData”をslotとして受け取ることでtemplateタグ内で様々なデータを扱うことができます。
<el-table-column>
<template slot-scope="scope" label="No">
<el-button @click="changePage(Path.EDIT, scope.$index)">更新</el-button>
</template>
</el-table-column>
「更新」ボタンを押した際に実行される関数は下記です。
changePage (path, index) {
this.$router.push({ path, query: { id: this.getTableData[index].id } });
}
$router.pushでページ遷移する際に引数で渡ってきたidをクエリパラメーターで渡すようにします。
これで、nodeを実行して、nuxtを起動して、「http://localhost:3000」にブラウザでアクセスしてみてください。
下記のようにテーブル内の各行に「更新」ボタンが追加されます。
「スティーブ」の行の「更新」ボタンをクリックしてください。
そうすると下記のような更新入力フォームのページに飛びます。
すでに「スティーブ」の情報が入っています。
試しに名前を「ボブ」に変更してみましょう。
これで「更新する」ボタンをクリックしてください。
このように「スティーブ」が「ボブ」に更新されているのがわかると思います。
データを削除するAPIを実行する
最後にデータベースのデータを削除するAPIを実行します。
まず、apiを追加するので、「api」フォルダ内のindex.tsを開いて、下記のように記述しましょう。
import axios from "axios";
const myApi = axios.create({
baseURL: "http://localhost:5000/meibo",
responseType: "json"
});
export default {
async getMeiboData() {
try {
const response = await myApi.get("");
return response.data;
} catch (error) {
console.log(error);
}
},
async getIdMeiboData(id: string) {
try {
const response = await myApi.get(`/${id}`);
return response.data;
} catch (error) {
console.log(error);
}
},
async postMeiboData(data: any) {
try {
await myApi.post("", data);
} catch (error) {
console.error(error);
}
},
async putMeiboData(data: any, id: string) {
try {
await myApi.put(`/${id}`, data);
} catch (error) {
console.error(error);
}
},
//追加
async deleteMeiboData(id: string) {
try {
await myApi.delete(`/${id}`);
} catch (error) {
console.error(error);
}
}
};
上記のようにdeleteMeiboData関数を追加しました。
パスパラメーターとしてidを渡して、APIを実行します。
続いて、テーブルに「削除」ボタンを追加し、実際にボタンをクリックしてデータを削除できるようにしましょう。
「components」フォルダ内のTable.vueを開いて下記のように記述してください。
<template>
<div>
<el-table :data="getTableData" style="width: 100%">
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name" label="Name" width="180"></el-table-column>
<el-table-column prop="intro" label="Intro"></el-table-column>
<el-table-column>
<template slot-scope="scope" label="No">
<el-button @click="changePage(Path.EDIT, scope.$index)">更新</el-button>
<el-button @click="centerDialogVisible = true">削除</el-button>
<el-dialog :visible.sync="centerDialogVisible" width="30%" center>
<span>本当に削除しますか?</span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">キャンセル</el-button>
<el-button type="danger" @click="deleteData(scope.$index)">削除する</el-button>
</span>
</el-dialog>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Vue from "vue";
import { Path } from "~/constants";
import meiboApi from "~/api/index";
export default Vue.extend({
props: {
getTableData: {
type: Array,
default: () => { }
}
},
data () {
return {
dataArray: this.getTableData,
Path: Path,
centerDialogVisible: false
}
},
methods: {
changePage (path, index) {
this.$router.push({ path, query: { id: this.getTableData[index].id } });
},
async deleteMeiboData (id) {
await meiboApi.deleteMeiboData(id);
},
deleteData (index) {
this.deleteMeiboData(this.getTableData[index].id);
location.reload();
}
},
mounted () {
console.log(this.dataArray);
}
});
</script>
まず、template内には「更新」ボタンの横に「削除」ボタンを追加しましょう。
その際に、下記のようにボタンを追加するとともに、削除した際にダイアログを挟んで、削除するようにするために、el-dialogを使いましょう。
<el-table-column>
<template slot-scope="scope" label="No">
<el-button @click="changePage(Path.EDIT, scope.$index)">更新</el-button>
<el-button @click="centerDialogVisible = true">削除</el-button>
<el-dialog :visible.sync="centerDialogVisible" width="30%" center>
<span>本当に削除しますか?</span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">キャンセル</el-button>
<el-button type="danger" @click="deleteData(scope.$index)">削除する</el-button>
</span>
</el-dialog>
</template>
</el-table-column>
methodsには、下記のようにdeleteMeiboData関数を追記しましょう。
idを渡して、削除APIを実行する関数です。
また、deleteData関数を追記して、この中には、削除APIを実行するdeleteMeiboData関数を記述して、その後にページを再読み込みさせる記述をします。
async deleteMeiboData (id) {
await meiboApi.deleteMeiboData(id);
},
deleteData (index) {
this.deleteMeiboData(this.getTableData[index].id);
location.reload();
}
ここまでできたら、試してみましょう。
expressとnuxtを起動して、ブラウザにて「http://localhost:3000」にアクセスしましょう。
試しに「ボブ」のデータを削除してみましょう。
テーブルの「ボブ」の行の「削除」ボタンをクリックすると、下記のように削除ダイアログが表示されます。
「削除する」を押すと、ページがリロードされて下記のように「ボブ」のデータが削除されているのが確認できます。
まとめ
さて、2回に渡って、Expressで作ったREST APIをNuxt.js上で実行してみるということをやってみました。
取得・登録・更新・削除という基本的なAPIを実行することで、今回のようなデータベースを用いた簡易的なアプリケーションを作ることができました。
このようにデータベース、バックエンド開発、フロントエンド開発の一連の開発ができるようになることで、アプリケーション開発の幅がより広がります。
今後、より応用的に知識を深めていけるように筆者も頑張ります!
皆さんも一緒に頑張りましょう!
それでは今回はここまで。
お疲れ様でした。