やりたいこと
- Railsで作ったAPIに対してNuxt.js側から投稿する(前回の記事の続編です)
開発環境
ruby 2.6.5
Rails 6.0.3.4
node v14.7.0
yarn 1.22.4
フロント(Nuxt.js)のローカルサーバーのport番号は8000
API(Rails)のローカルサーバーのport番号は3000
投稿画面のマークアップ
- sendボタンがクリックされたら、Postmanで投稿ができることを確認できたURI
http://localhost:3000/api/v1/posts
にPOSTリクエスト
を送るような処理を実装
<template>
<div class="container">
<h4>新規投稿</h4>
<div class="form-control">
<span>Title</span>
<input
type="text"
v-model="title"
>
</div>
<div class="form-control">
<span>Body</span>
<input
type="text"
v-model="body"
>
</div>
<div class="form-control">
<button @click="postMessage">send</button>
</div>
</div>
</template>
<script>
export default {
data: () => ({
title: null,
body: null,
}),
methods: {
postMessage() {
const url = 'http://localhost:3000/api/v1/posts';
const post = {
title: this.title,
body: this.body,
};
this.$axios.post(url, { post })
.then(res => console.log(res.status))
.catch(error => console.log(error));
},
}
}
</script>
<style>
.container {
width: 60%;
max-width: 600px;
margin: 0 auto;
}
.form-control {
margin: 20px 0;
}
h4 {
text-align: center;
}
span {
width: 4em;
display: inline-block;
}
input[type="text"] {
width: calc(100% - 6em);
}
button {
margin: auto;
display: block;
}
</style>
CORSでのエラーになる時の解決方法
- 上記で実装すると、console.logに下記が出力される
Access to XMLHttpRequest at 'http://localhost:3000/' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
なぜ正しくリクエストが送れていないのか?
結論
Nuxt側(フロント側)からそのままURIを指定してしまうと CORSの制限がかかっているため 正しくリクエストが送れていない
CORSとは
オリジン間リソース共有Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
ウェブアプリケーションは、自分とは異なるオリジン (ドメイン、プロトコル、ポート番号) にあるリソースをリクエストするとき、オリジン間 HTTP リクエストを実行します。
MDNより抜粋
CORS (オリジン間リソース共有) の問題を解決する
Nuxt公式ページに書いてある方法をそのまま実施します
※ 公式ページではnpmでインストールしていますが、今回はyarnで開発しているので下記コマンドを使います(npmやyarnのコマンドについてはこちらも参照ください)
// @nuxtjs/proxyのインストール
$ yarn add @nuxtjs/proxy
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {
'^/api' : '/api/v1'
}
}
},
pathRewrite
の '^/api' : '/api/v1'
の記述は、 @nuxtjs/proxyのgithubを参考にしています
上記では、vue側でリクエストとして指定している /api
がつく接頭辞を /api/v1
にリライト(書き換え)て、http://localhost:3000
に送ってね、と指定しています
proxyやpathRewriteについての記述方法はこのサイトも参考になりました
Nuxt側の修正
上記でProxyを設定してCORSの問題を解決する設定をしたので、NuxtのファイルでリクエストをPOSTしている箇所を修正します
// 上の部分は省略
methods: {
postMessage() {
const url = '/api/posts';
const post = {
title: this.title,
body: this.body,
};
this.$axios.post(url, { post })
.then(res => console.log(res.status))
.catch(error => console.log(error));
},
}
// 以下省略
const url = '/api/posts';
と訂正する
※ Proxyの設定、pathRewriteの設定により、http://localhost:3000/api/v1/posts
にリクエストして、と変換される
Rails側の修正
# 上の部分は省略
private
def set_post
@post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :body)
end
end
送られてくるパラメーターは、Nuxt側でこのようなオブジェクト型で指定しているため、require(:post)
をする必要がある
const post = {
title: this.title,
body: this.body,
};
※このオブジェクト名がhogeだったら、require(:hoge)
となる