LoginSignup
1
0

More than 3 years have passed since last update.

JsfiddleのVue.jsからDRFで作成したapiにアクセスしたい

Posted at

経緯

Vue.jsのプロジェクトをWeb上で手軽に作ることができるjsfiddleで、Django Rest Framework(以下DRF)で作成したapiにアクセスしたいと思い、試しました。

本記事に書くこと

  1. DRFにおけるシンプルなAPIの作成と、シンプルなVue.jsプロジェクトの作成。
  2. Vue.jsからDRFのapiにアクセスする方法と、その際の留意点。

手順

  1. DRFでapiを作成する
  2. Vue.jsからDRFで作成したapiにアクセスする

1. DRFでapiを作成する

環境を作る
mkfir simple_drf
cd simple_drf
python3 -m vena venv
source venv/bin/activate

pip install django
pip install djangorestframework

django-admin startproject config.

-- モデル用のbook API作成用のapiv1 --
python manage.py startapp book
python manage.py startapp apiv1
book/models.py
from django.db import models
import uuid
from django.utils import timezone

# Create your models here.
class Book(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(verbose_name='タイトル', max_length=50)
    price = models.IntegerField(verbose_name='価格')
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title
book/admin,py
from django.contrib import admin

# Register your models here.
from .models import Book


class BookModelAdmin(admin.ModelAdmin):  
    list_display = ('title', 'price', 'id', 'created_at')  
    ordering = ('-created_at',)  
    readonly_fields = ('id', 'created_at')  

admin.site.register(Book, BookModelAdmin) 
apiv1/serializers.py
from rest_framework import serializers  
from book.models import Book  

class BookSerializer(serializers.ModelSerializer):  
    class Meta:  
        model = Book  
        fields = ['id', 'title', 'price'] 
apiv1/views.py
from rest_framework import viewsets  
from rest_framework.permissions import IsAuthenticatedOrReadOnly  
from book.models import Book  
from .serializers import BookSerializer  

class BookViewSet(viewsets.ModelViewSet):  
    queryset = Book.objects.all()  
    serializer_class = BookSerializer 
apiv1/urls.py
from django.urls import path, include
from rest_framework import routers
from apiv1 import views

router = routers.DefaultRouter()
router.register('book', views.BookViewSet)

app_name = 'apiv1'
urlpatterns = [
    path('', include(router.urls))
]
config/urls,py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('apiv1/', include('apiv1.urls')),
]

管理画面で適当に本を追加しました
スクリーンショット 2020-03-28 14.24.55.png

2. Vue.jsからDRFで作成したapiにアクセスする

jsfiddleにアクセスし、各フィールド(html, css, javascript)に以下の通り記載。

HTML
<div id="app">
  {{ results }} 
  <hr>
  {{ results.id }} 
  <hr>
  {{ results.title }} 
  <hr>
  {{ results.price }} 
  <hr>
</div>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axiosをcdnで使えるようにしておく

CSSは適当に
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
Vue
new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted() {
    axios.get('http://127.0.0.1:8000/apiv1/book/d5da82ff-8f63-4718-9ddb-e989832170d1/')
    .then(response => {this.results = response.data})
 }
 },
)

ライフサイクルフックのmountedでapiを使います。
axiosのgetメソッドに、DRFで作った記事のエンドポイントを指定。レスポンスのデータをresultsリストに格納します。
HTMLのMustache構文で{{ results }}などとしているため、getしてきた結果が表示されるはずですが...

スクリーンショット 2020-03-28 14.07.25.png

表示されへん

エラー

コンソール
fiddle.jshell.net/takuto/4vjsdpag/64/show/:1 Access to XMLHttpRequest at
'http://127.0.0.1:8000/apiv1/book/d5da82ff-8f63-4718-9ddb-e989832170d1/'
from origin 'https://fiddle.jshell.net' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Failed to load resource: net::ERR_FAILED

表示されません。コンソールを見ると上記の通りエラーが。
origin 'https://fiddle.jshell.net' has been blocked by CORS policy
https://fiddle.jshell.netがCORSポリシーによってブロックされたと言ってます。

原因は?

同一オリジンポリシーです。
詳しく:https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy

セキュリティの観点から、異なるオリジン同士でリソースをやり取りすることを防ぐものです。
オリジンは、スキーム、ポート、ホストの3つの組み合わせのこと。
これらが一致していない場合は、同一オリジンとは言えません。

オリジンとは:https://www.atmarkit.co.jp/ait/articles/1311/26/news007.html

異なりオリジンへのアクセスを許可するためには、CORSという機能を使います。HTTPヘッダに設定を加える必要があります。

今回エラーが起きているのは、DRFで作成したAPIのオリジンと、Jsfiddleのオリジンが異なるためです。

解決するために...

DRFでdjango-cors-headersを使えば、CORSを設定することができます。

DRFにdjango-cors-headersを入れる

インストール
$ pip install django-cors-headers
DRFのsettings.pyに追記
settings.py
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...

MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
]
CORS_ORIGIN_ALLOW_ALL か CORS_ORIGIN_WHITELISTを設定する
settings.py
CORS_ORIGIN_ALLOW_ALL = True

CORS_ORIGIN_WHITELIST = [
    "https://fiddle.jshell.net", 
]

CORS_ORIGIN_ALLOW_ALLは、他のオリジンをすべて許可する。
CORS_ORIGIN_WHITELISTは、許可するオリジン指定する。

これでもう一度試してみる

スクリーンショット 2020-03-28 14.08.57.png

やったー。睡眠が大事という本の情報を取得できました。

1
0
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
1
0