HOME  >  Web開発 >  【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜登録・更新・削除

Web開発

【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜登録・更新・削除

【Nuxt.js + Express】Expressで開発したAPIをNuxt.jsで実行する〜登録・更新・削除

目次

  1. データを登録するAPIを実行する
  2. データを更新するAPIを実行する
  3. データを削除するAPIを実行する
  4. まとめ

前回に引き続き今回も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を実行することで、今回のようなデータベースを用いた簡易的なアプリケーションを作ることができました。

このようにデータベース、バックエンド開発、フロントエンド開発の一連の開発ができるようになることで、アプリケーション開発の幅がより広がります。

今後、より応用的に知識を深めていけるように筆者も頑張ります!

皆さんも一緒に頑張りましょう!

それでは今回はここまで。

お疲れ様でした。

関連記事

関連記事

【Vue + vue-cli】コンポーネントの基本

【Vue + vue-cli】コンポーネ……