45
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue 3 + TypeScript + axiosでAPI接続

Last updated at Posted at 2021-08-31

概要

Vue 3 + TypeScript + axiosでAPIへ接続する方法の基礎となる部分をまとめた。
(axiosとはブラウザやnode.js上で動くPromiseベースのHTTPクライアント)

Vue初心者がハマりがちなCORSのエラーについても後述する。

環境

  • Vue 3.0.0
  • TypeScript 4.1.6
  • axios 0.21.1

Install vue/cli

$ yarn global add @vue/cli

Create App

Vueのアプリケーションを作成する。

$ vue create sample-app

TypeScriptとRouterを有効にする。

Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Choose Vue version
 ◉ Babel
 ◉ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

Vueのversionは3.xを選ぶこと。それ以外はお好みで。

Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
  TSLint (deprecated)

axiosをインストール

$ yarn add axios

axiosの共通設定

src/の下にhttp-common.tsという名前のファイルを作成し、axiosを使う際のheadersなどの共通設定を定義する。baseURLにはAPIのURIを定義している。

src/http-common.ts
import axios, { AxiosInstance } from "axios";

const apiClient: AxiosInstance = axios.create({
  // APIのURI
  baseURL: "http://localhost:3000",
  // リクエストヘッダ
  headers: {
    "Content-type": "application/json",
  },
});

export default apiClient;

APIへのエンドポイント

services/SampleApiService.tsというファイルを作成し、APIの各エンドポイントの定義をする。先程作成したhttp-common.tsをimportして使う。

services/SampleApiService.ts
import http from "@/http-common";

class SampleApiService {
  getAll(): Promise<any> {
    return http.get("/api/books");
  }

  get(id: any): Promise<any> {
    return http.get(`/api/books/${id}`);
  }

  create(data: any): Promise<any> {
    return http.post("/api/books", data);
  }

  update(id: any, data: any): Promise<any> {
    return http.put(`/api/books/${id}`, data);
  }

  delete(id: any): Promise<any> {
    return http.delete(`/api/books/${id}`);
  }

  deleteAll(): Promise<any> {
    return http.delete(`/api/books`);
  }

  findByDescription(title: string): Promise<any> {
    return http.get(`/api/books?title=${title}`);
  }
}

export default new SampleApiService();

componenetから利用する

各componentからこんな感じで呼び出して利用できるようになる。

components/sample.vue
import SampleApiService from "@/services/SampleApiService";

SampleApiService.getAll();
SampleApiService.get(1);
SampleApiService.deleteAll();

CORSのエラー

Vue.jsのサーバーと、APIのサーバーのOriginが異なる場合、APIアクセス時に以下のようなエラーが出ることがある。

Access to XMLHttpRequest at 'http://localhost:3000/api' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

例えば、Vue.jsのサーバーが http://localhost:8080 、APIサーバーが http://localhost:3000 のようにそれぞれのOriginが異なる場合、単純リクエスト(GET, HEAD, POST)以外のリクエスト時にこのエラーが起きる場合がある。

単純リクエスト以外、つまりDELETE、PUTなどのリクエスト時には、リクエスト送信前にpreflightリクエストというものが飛び、そのHTTPメソッドが相手先サーバーで許可されているかどうかの確認を行う。相手先サーバーで許可されていない場合にこのエラーが発生する。

解決策は以下の2つがあるが、2のproxyを使った方法が簡単であり、そちらを取る場合が多いようなので、ここでもproxyの設定方法を説明する。

  1. 相手先サーバー(今回の場合はAPIサーバー)でOriginの許可設定をする
  2. Vue.jsサーバーでproxyを利用する

proxyの設定

root階層、package.jsonのある階層にvue.config.jsを作成し、proxyの設定をする。

以下の設定をすることで、devServer(vue-cli-service serveで動くサーバー)上で、http://localhost:8080 へのアクセスで且つ、URIに/apiを含むリクエストが発行された場合、宛先を http://localhost:3000 に書き換えてアクセスするようになる。

つまり、Vue.jsサーバーがhttp://localhost:8080 、APIサーバーがhttp://localhost:3000の場合、 http://localhost:8080/api/** にアクセスすると、 http://localhost:3000/api/** にリクエストが書き換えられアクセスされる。

これにより、ブラウザ上では http://localhost:8080/api/** へアクセスしていることになるので、CORSのエラーを回避することができる。

vue.config.js
module.exports = {
  devServer: {
    proxy: {
      "^/api*": {
        target: "http://localhost:3000",
        pathRewrite: { "^/api": "" },
        changeOrigin: true,
        logLevel: "debug",
      }
    }
  }
};

baseURLを削除

http-common.tsのbaseURLがあるとproxyが効かなくなるので削除する。

src/http-common.ts
import axios, { AxiosInstance } from "axios";

const apiClient: AxiosInstance = axios.create({
- // APIのURI
- baseURL: "http://localhost:3000",
  // リクエストヘッダ
  headers: {
    "Content-type": "application/json",
  },
});

export default apiClient;

これでCORSのエラーを回避できる。

参考

45
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?