JsfiddleのVue.jsからDRFで作成したapiにアクセスしたい
経緯
Vue.jsのプロジェクトをWeb上で手軽に作ることができるjsfiddleで、Django Rest Framework(以下DRF)で作成したapiにアクセスしたいと思い、試しました。
本記事に書くこと
- DRFにおけるシンプルなAPIの作成と、シンプルなVue.jsプロジェクトの作成。
- Vue.jsからDRFのapiにアクセスする方法と、その際の留意点。
手順
- DRFでapiを作成する
- 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')),
]
- DRFでapiを作成する
- 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')),
]
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
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
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)
from rest_framework import serializers
from book.models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title', 'price']
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
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))
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('apiv1/', include('apiv1.urls')),
]
2. Vue.jsからDRFで作成したapiにアクセスする
jsfiddleにアクセスし、各フィールド(html, css, javascript)に以下の通り記載。
<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で使えるようにしておく
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
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してきた結果が表示されるはずですが...
表示されへん
エラー
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 : http://127.0.0.1:8000
- Jsfiddle : https://fiddle.jshell.net
解決するために...
DRFでdjango-cors-headers
を使えば、CORSを設定することができます。
DRFにdjango-cors-headers
を入れる
インストール
$ pip install django-cors-headers
DRFのsettings.pyに追記
INSTALLED_APPS = [
...
'corsheaders',
...
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]
CORS_ORIGIN_ALLOW_ALL か CORS_ORIGIN_WHITELISTを設定する
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = [
"https://fiddle.jshell.net",
]
CORS_ORIGIN_ALLOW_ALLは、他のオリジンをすべて許可する。
CORS_ORIGIN_WHITELISTは、許可するオリジン指定する。
これでもう一度試してみる
やったー。睡眠が大事
という本の情報を取得できました。
Author And Source
この問題について(JsfiddleのVue.jsからDRFで作成したapiにアクセスしたい), 我々は、より多くの情報をここで見つけました https://qiita.com/taku_hito/items/4dc905b3a07fe3aa2503著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .