はじめに
今回は、バックエンドをDjangoRestFrameworkで実装し、
フロントはNext(TypeScript)でreact-oauthというサードパーティライブラリを使用して簡単にWebアプリ開発の土台を作成していきます。
環境
Ububtu 20.04
構成概要
PROJ #作成するプロジェクト
│── back # Django REST framework(以下DRF)のAPI
│ ├── api # モデル、ビュー、APIのルーティングなど
│ ├── env # venv
│ ├── manage.py # DRFのサーバ起動やマイグレーション
│ ├── project # DRFの設定もろもろの中核
│ └── requirements.txt # 必要なPythonパッケージ
│── front # フロントエンド
└── client # Reactアプリケーション
データベース
※SQLiteを使用する場合は無視してください。
DRFはデフォルトでSQLiteです。
(sudo apt update && apt upgrade)
sudo apt install mysql-server
rootユーザのパスワード設定
sudo mysql_secure_installation
mysql -uroot -p
mysql > create database 任意のデータベース名;
mysql > quit
バックエンド
Django REST framework(DRF)を使用します。
Djangoとは別物と考えてください。
sudo apt install python3-django
①必要ライブラリのインストール
python -m venv env
(「env」は任意)
source env/bin/activate
Django
djangorestframework
django-cors-headers
drf_social_oauth2
mysqlclient
※django-cors-headersはポートの異なるフロントエンドからの通信を許可するのに必要です。
pip install -r requirements.txt
後から追加ライブラリがあればrequirements.txtを更新します。
pip freeze > requirements.txt
②Djangoプロジェクトを作成
django-admin startproject project .
(project名「project」は任意)
③appを作成
python3 [manage.py](http://manage.py/) startapp api
(app名「api」は任意)
④設定ファイルを修正
- 使用するライブラリと上で作成したapp名を登録
- db設定(dbエンジン, host, user, password)
- 言語、地域設定(日本・アジア・東京)
以下にスニペットを示します。
INSTALLED_APPS = [
'app',
'rest_framework',
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware'
]
DATABASES = {
#デフォのSQLite設定はコメントアウトまたは削除
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 上で作成した任意のDB名,
'USER': 'root',
'PASSWORD': 上で設定したrootのパスワード,
}
}
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]
⑤管理者を作成
python3 manage.py createsuperuser
上で設定したdbのauth_userテーブルに作成されます。
※以下api直下での作業です。
⑥モデルを定義
models.pyに作成するテーブルを記述します。
以下、例を示します。
from django.db import models
# Create your models here.
class User(models.Model):
email = models.EmailField(
verbose_name='Eメールアドレス',
max_length=255,
unique=True,
)
name = models.CharField(max_length=100)
family_name = models.CharField(max_length=100)
given_name = models.CharField(max_length=100)
picture = models.CharField(max_length=200)
active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name # 管理画面での一覧に表示する値。なくてもいいし別の値でもいい。
⑦マイグレート
python3 manage.py makemigrations api
python3 manage.py migrate
appのモデルにテーブルを新しく定義する場合は再度上記2コマンド実行してください。
⑧管理画面で操作できるようにする
管理したいモデルを追加します。
以下、Userテーブルを追加する例です。
from django.contrib import admin
from .models import User
# ここに使用するモデルを設定してください
admin.site.register(User)
⑨リクエストを受けてCRUD操作をするviewsを作成
serializer.py
まずシリアライザを設定します。
Djangoにはない機能。DRF独自なのでファイルは新規作成してください。
シリアライザは複雑なデータをDBレコード⇔モデル間で橋渡ししてくれます。
以下、例です。
from .models import User
from rest_framework import serializers
# from django.db.models import fields
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','email','name','family_name','given_name','picture','active','created_at','updated_at')
views.py
以下、クラスベースのビューを採用する場合の例です。(関数ベースでも定義可能)
DRF公式によると以下のメリットがある。
・ 特定の HTTP メソッド (GET、POSTなど) に関連するコードの集まりを、条件分岐を使ってかき分けるのではなく、それぞれに独立したメソッドを割り当てることができる。
・ ミックスイン (多重継承) などのオブジェクト指向のテクニックを使って、コードを再利用可能なコンポーネントに分解できる。
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import get_object_or_404
from .models import User
from .serializer import UserSerializer
class UserListCreateAPIView(APIView): # 全データ取得とデータ追加についてのクラス
def get(self, request): # 全データ取得
articles = User.objects.filter(active=True)
serializer = UserSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request): # データ追加
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class UserDetailAPIView(APIView): # idをもとに個別データ取得
err_msg = {
"error": {
"code": 404,
"message": "Article not found",
}}
def get_object(self, pk):
user = get_object_or_404(User, pk=pk)
return user
def get(self, request, pk):
user = self.get_object(pk)
serializer = UserSerializer(user)
return Response(serializer.data)
def put(self, request, pk):
user = self.get_object(pk)
serializer = UserSerializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
user = self.get_object(pk)
user.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
⑩APIのエンドポイントと管理画面のルーティング
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('app.urls')) # APIのバージョンを表記するのがREST界隈での慣習らしいです。
]
from django.urls import path
from .views import (
UserListCreateAPIView,
UserDetailAPIView
)
urlpatterns = [
path("user/", UserListCreateAPIView.as_view(), name="article-list"),
path("user/<int:pk>", UserDetailAPIView.as_view(), name="article-detail"),
]
⑪起動
python3 [manage.py](http://manage.py) runserver
でサーバを起動して、
localhost:8000/admin
の管理画面でテーブルを直接変更したり、
localhost:8000/api/v1/user
localhost:8000/api/v1/user/(ユーザid)
でhttp通信をしてみてください。
(get, post, put, deleteメソッドすべてやってみてください。)
あとでReact側からaxiosというhttp通信ライブラリでhttpリクエストをして、
レスポンスが帰ってくる感覚が簡単に実感できるかと思います。
フロントエンド
※googleアカウントで認証してDRFにpostメソッドでユーザ追加できるようにするところまでの環境構築方法
筆者のnode環境
node -v
v18.12.1
npm -v
8.19.2
npx -v
8.19.2
①アプリ作成
npx create-react-app client
or
npx create-next-app client
next.jsを使用すればルーティングがpages直下のフォルダ構成と連動するので楽です。
しかし今回はまだnext.jsの特徴であるバックエンド機能は使用しません。
create-appがうまく行かなければキャッシュクリア&.npm削除してみてください。
npm cache clean --force
rm -rf ~/.npm
②googleAOuth認証⇒DRFにリクエスト に必要なnpmパッケージをインストール
npm i @react-oauth/google@latest axios jwt-decode
-
react-oauth
ReactでGoogleOAuth認証するためのライブラリ。
react-google-loginというライブラリもあるが、非推奨。 -
axios
javascriptでのhttp通信を簡単に実装できるライブラリ。
Promissベース(処理が完了するまで次の処理に移行しない。) -
jwt-decode
react-oauthで認証成功した際のレスポンスにcredentialというキーがある。
JWTという符号化やデジタル署名の仕組みを規定した標準規格であるためデコードする必要がある。
デコードするとユーザ名、メアド、プロフィール写真のURLなどを取得可能。
③OAuthクライアントIDの取得
以下の記事を見れば簡単に行うことができます。
ReactとDjangoでGoogle OAuthログイン【前編】Google Developer ConsoleからクライアントIDとクライアントシークレットを取得する
④画面実装
以下、Next.js + TypeScriptで実装する場合の例です。
import { GoogleOAuthProvider } from '@react-oauth/google';
import { GoogleLogin } from '@react-oauth/google';
import axios from "axios";
import jwt_decode from 'jwt-decode'
const googleClientId: string = クライアントID;
const baseURL: string = "localhost:8000/api/v1";
const handleGoogleLogin = (response: any) => {
console.log("response",response)
var decoded: any = jwt_decode(response.credential)
console.log("decoded",decoded)
const body = {
"email": decoded.email,
"name": decoded.name,
"family_name": decoded.family_name,
"given_name": decoded.given_name,
"picture": decoded.picture
}
axios.post(`${baseURL}/user/`, body)
.then((res) => {
console.log("Success Google login", res)
window.location.href = "/"
})
.catch((err) => {
console.log("Error Google login", err);
});
};
export default function Login() {
return (
<div>
<GoogleOAuthProvider clientId={googleClientId}>
<GoogleLogin
onSuccess={(response) => handleGoogleLogin(response)}
onError={() => {
console.log('Login Failed');
}}
/>
</GoogleOAuthProvider>
</div>
)
}
⑤起動&GoogleOAuth認証
npm run dev
認証してDBを確認してください。
api_userテーブルにユーザが追加されていればOKです。
参考