アプリ開発ナレッジ

アプリ開発のナレッジを掲載します

マッチングアプリを個人開発する~Djangoバックエンドその4 動作確認~

この記事はマッチングアプリを自作してみようと試みている記事です
バックエンドを実装しています

前回までの記事はこちらです
shinseidaiki.hatenablog.com


前回はREST API作成まで終わりました
今回は実装したREST API機能がちゃんと動くかを動作確認していきます

目次

動作確認

それではAPIが想定通り正しく動作するか確認を行っていきましょう
DjangoRest APIのテスト実行環境も用意されておりサポートが手厚いのでここでもDjangoにおんぶに抱っこされながら動作確認をしていきましょう

DjangoREST APIテスト実行環境を使用するにあたって必要なことはサーバーを起動して/api/のエンドポイントにアクセスするだけです

さてそれではPyCharmの△ボタンを押してサーバーを起動しましょう

確認するエンドポイントの整理

確認するエンドポイントの整理をしておきましょう
前回の記事でURL設計を作成しましたが、この動作確認ではそのエンドポイントの各挙動を確認していきます
これらは後でテストケースとしても使用できます

エンドポイント メソッド 確認内容
/api/authen/jwt/create POST ログイン後JWTトークンが返ってくる
/api/users/create/ POST 認証なしでユーザー新規作成ができる
/api/users/{pk}/ GET, PATCH pkで指定したユーザーの情報が取得できることを確認する。pkで指定したユーザーのemailとパスワード更新ができてパスワードはハッシュ化されている。ただしpkは自分自身に限り、他人のpkは使用しても何もできないことも確認する。PATCHのみの使用を想定し、PUTの使用は想定しない
/api/users/profile/{pk} GET, PUT, PATCH pkで指定したユーザーのプロフィール情報の取得ができることを確認する。pkで指定したユーザーのプロフィール情報の更新ができることを確認する。ただしpkは自分自身に限り、他人のpkは使用しても何もできないことも確認する。
/api/profiles/ CREATE, GET ユーザーのプロフィールを作成できることを確認する。すでに自身のプロフィールが作られている場合は作成できないことを確認する。異性だけがフィルタリングされたプロフィール一覧が取得できることを確認する。自分のプロフィールがない状態では誰のプロフィールも取得できないことを確認する
/api/profiles/{pk} GET pkで指定したユーザーのプロフィールが取得できることを確認する。このエンドポイントでは更新(UPDATE)はできないことを確認する
/api/favorite/ CREATE, GET いいねすなわちマッチングレコードが作成できることを確認する。approachingとapproachedが自分であるようにフィルタリングされたマッチングモデルのデータ一覧を取得できることを確認する。
/api/favorite/{pk}/ GET, PATCH approvedをtrue, falseに変更することができることを確認する。PATCHの利用を想定しUPDATEは想定しない
/api/dm-message/ CREATE, GET approavedがTrueでかつapproach"ed"が自分であるマッチングデータが存在する場合にDMデータが作成できることを確認する。senderが自分自身のDMだけが一覧で取得されることを確認する。
/api/dm-message/{pk}/ GET, UPDATE pkで指定したDMを取得できる。DMのメッセージを変更できる。PATCHの利用を想定しUPDATEは想定しない。
/api/dm-inbox/ GET receiverが自分のDM一覧が取得できることを確認する。
/api/dm-inbox/{pk}/ GET pkで指定したDMを取得できる。更新はできないことを確認する


/api/authen/jwt/create/と/api/users/create/以外はJWTトークンなしではアクセスを拒否されることも確認しておく


ユーザー新規作成とJWT認証(/api/authen/jwt/createと/api/users/create/)

サーバ起動後まずはhttp://127.0.0.1:8000/api/にアクセスしましょう
以下のような画面が表示されているはずです
f:id:shinseidaiki:20220212174953p:plain

認証情報が含まれていないといわれて接続を拒否されているのはデフォルトでログインユーザーのみしかAPIにアクセスできないとしているため正しい挙動をしていることが分かります

それではまずはユーザーを作成してそのユーザーのJWTの認証情報を手に入れましょう
手順は以下です

ユーザー新規作成

http://127.0.0.1:8000/api/users/create/
にアクセスします
このエンドポイントはあらゆるアクセスを許可しているのでアクセスできるはずです
以下のように任意のユーザーを作成しましょう

f:id:shinseidaiki:20220212175550p:plain

POSTの送信ボタンを押すとレスポンスが返ってきます

{
    "email": "user1@user.com",
    "username": "user1",
    "id": "uuid-665e........................................."
}

さて管理画面で作成できていることを確認しましょう
http://127.0.0.1:8000/adminのusersを確認しましょう
作成したユーザーがあればよいです

そしてここで、本アプリの特性ですが、作成したユーザーのis_activeはデフォルトでFalseとしていたので管理画面上で今作ったユーザーを使えるようにアクティベーションしておきます
is_activeフィールドを見つけてチェックを入れておいてください

f:id:shinseidaiki:20220212180106p:plain

ログイン認証処理とJWT発行

ではユーザーが作成できたので、先ほど作ったemailとpasswordを使用してJWTトークンを発行しましょう
Djoserのモジュールを今回利用しているので/authen/jwt/create/のエンドポイントに正しいemailとpasswordをリクエストボディに詰めて送信すると認証が成功しJWTトークンがレスポンスのaccessパラメータに格納されて返ってきます
返ってきたaccessのパラメータの値をトークンといい今回はJWTトークンという名前がついています
JWTの認識をつけるためにトークンに接頭辞としてJWT をつけるようにsettings.pyで設定しているのですが、取得した[JWT Token] をその後のリクエストに「JWT [JWT Token]」とした値でくっつけて送信すると認証済みユーザーとしてアクセスを許可する仕組みとなっています
この流れがいわゆる世間でいうログインです

それでは動作確認していきますが、ここで新しいToolを使用します
POSTMANというAPIのテスト実行環境を用意してくれるソフトウェアを利用します
まずはインストールして起動してください
www.postman.com

これはDjangoの用意してくれているREST API実行環境と同じようなものなのですがPostmanの方がより機能が多く代表的な機能としてはリクエストボディにパラメータを詰めてリクエストを投げることができます
それではPostmanの以下のような画面を開きます
f:id:shinseidaiki:20220212181531p:plain

必要な項目を埋めていきます
メソッド:POST
URL:http://127.0.0.1:8000/authen/jwt/create/
body>form-data: email, password の各値
を正しく入力してSendを押します

するとjsonが返ってくるはずです
このaccessの方の値を控えておきます

{
    "refresh": "........................................................",
    "access": "jwttoken........................................."
}

値を控える際は以下のように「JWT」の文字を接頭語に着けて控えておきます
後で使用します
「JWT jwttoken.........................................」

さて、JWTが発行されたので先ほど作成したuser1はログイン済みということになりました
では先ほどアクセスを拒否された/api/エンドポイントに再度アクセスしてみましょう

JWTを使用したアクセス認証

ここでまた別のツールを利用します
今回使用するのはテスト環境で利用するためのトークンであるため、ほかのサービスに使うような本物のトークンと混じってしまうと大変です
しかしそうならないためのサービスがグーグルクローム拡張機能にあります
ModHeaderという拡張機能をインストールしてください
インストールして有効化すると右上に表示されます
これを利用していきます

f:id:shinseidaiki:20220212182355p:plain

RequestHeaderに先ほど控えたJWTトークンを貼り付けてトークンを使用するチェックを付けます
f:id:shinseidaiki:20220212182638p:plain
f:id:shinseidaiki:20220307132017p:plain

これでトークンがリクエストヘッダーにくっついてくるようになりました
ではhttp://127.0.0.1:8000/api/にアクセスしましょう
すると先ほどとは違ってapiの他のエンドポイントを見せてもらえるようになりました
これで認証が通っていることが確認出来ました
成功です

f:id:shinseidaiki:20220212182747p:plain

それではこの認証情報を使いながら他のエンドポイントの動作確認を行っていきましょう

ログイン中のユーザー情報の取得と更新(/api/users/{pk}/)

それでは次にユーザーの情報を取得・更新できるエンドポイントが想定通り動作するか確認していきます
このエンドポイントを利用するためにはユーザーのIDが必要になるのでIDが分からない人は管理者画面にアクセスしてユーザーのIDを引っ張って決ましょう
管理画面の一覧にIDを表示させている場合はこちらから
EMAIL ID パスワード
user1@user.com uuid-......................... hashed-password............

表示させるのを忘れている人は詳細更新画面でのURLからも引っ張ってくることができます
http://127.0.0.1:8000/admin/basicapi/user/[uuid-..........................]/change/

IDを控えたら/api/users/{pk}/のpkに控えたIDを入力してアクセスしましょう
アクセスできていたこのような画面になっているはずです
f:id:shinseidaiki:20220212194831p:plain

下の入力フォームを使っても変更できますが、ユーザー情報はemailもユーザー名もパスワードも別々の画面を経由して編集することが多いと思いますので、差分更新のPATCHを利用して更新できるかを確認してみようと思います

なお差分更新のPATCHはDjango REST FRAMEWORKの画面では起動できないようなので、PATCHに関してはポストマンで動作確認しましょう
ちなみにPATCHの実行はPUTにpatial=trueを引数に持たせて実装しているようなので、Djangoの実行環境でもがんばったらもしかしたらできるかもしれないですね

emailとユーザー名のPATCH変更

まずはemailの変更ができるかを試します
ポストマンで先ほどのように必要な項目を埋めていきます
メソッド:PATCH
URL:http://127.0.0.1:8000/api/users/{pk}
body>form-data: email, username の各値
を正しく入力してSendを押します
すると更新後に再度GETが実行されてユーザー情報が更新されたjsonデータが返ってきます

f:id:shinseidaiki:20220212195637p:plain

管理画面でも更新されていることが確認しておいてください

emailとユーザー名のPATCH変更

次にpasswordの変更ができるかを試します
ポストマンで先ほどのように必要な項目を埋めていきます
メソッド:PATCH
URL:http://127.0.0.1:8000/api/users/{pk}
body>form-data: password の値
を正しく入力してSendを押します
パスワードは書き込み専用なのでjsonでは返ってこないので管理画面で更新されていることを確認します
確認ポイントとしてはちゃんとパスワードがハッシュ化されていることとパスワード変更前のハッシュ値と変更後のハッシュ値が違うことを確認します
また/authen/jwt/create/のJWT認証エンドポイントで新しく変更したemail と passwordで認証が通るかを念のために確認するのもよいでしょう

f:id:shinseidaiki:20220212200243p:plain

他のユーザーのidをpkに入れても見れないことを確認する

APIからでも管理画面からでもどちらでもいいですが、別のユーザーを作成しましょう
ちなみにこういったデータ動作確認作業に管理画面(/admin)は大変重宝します
自分でいろいろいじってみてください

さて実行しましょう

GET /api/users/[別ユーザーuuid]

以下のように404が確認できれば確認OKです

HTTP 404 Not Found
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "detail": "見つかりませんでした。"
}

ログイン中のユーザー情報の取得と更新(/api/users/profile/{pk}/)

それでは次にユーザーの情報を取得・更新できるエンドポイントが想定通り動作するか確認していきます
このエンドポイントを実行するにはプロフィールが存在しないといけないので、管理画面で先ほど作ったユーザーのどちらでもいいので、Profileクラスのデータを作成してください
なお、今回管理画面ではUserにProfileクラスをインクライン(挿入)しているためUserの中でProfile項目を編集できるようにしています
Profileクラスの詳細画面でProfileデータを追加してもいいですが、外部キーを入れるなど誰のデータをいじっているかわからなくなったりするのでadminにインクラインの設定を加えて作業しやすくしておくことは結構大事だったりします

ユーザー情報取得の確認(GET)

さてプロフィールを作成したらユーザーのUUIDをpkに入力して/api/users/profile/{pk}/にアクセスしましょう
なお、ログインしていない方のユーザーを使っている場合は404が出るはずなのでJWT認証の作業をもう一度行ってください

さてアクセスが成功して以下のような結果が返ってくればデータ取得はうまくいっていることが確認できました

HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "user": "uuid-.............................",
    "is_special": false,
    "is_kyc": false,
    "top_image": "http://127.0.0.1:8000/media/images/top_image/[path]",
    "nickname": "ユーザー1_男性",
    "created_at": "2022-02-12 02:26:00",
    "updated_at": "2022-02-12 03:24:18",
    "age": 20,
    "sex": "male",
    "height": null,
    "location": null,
    "work": null,
    "revenue": null,
    "graduation": null,
    "hobby": null,
    "passion": "slowly",
    "tweet": null,
    "introduction": "",
    "send_favorite": 0,
    "receive_favorite": 0,
    "stock_favorite": 1000
}
ユーザー情報更新の確認(UPDATE)

更新ができるかも確認しましょう
/api/users/profile/{pk}/でアクセスしている画面の下にフォームがあるので、そちらを変更してPUTを押して想定通りに変更されているかを確認します
上記と同様に変更後のデータがJSONで返ってくるので変更した内容に書き換わっているかを確認できれば成功です

ログイン中のプロフィール新規作成と異性プロフィール一覧取得(/api/profiles/)

プロフィール新規作成の確認(CREATE)

さてプロフィールの新規作成確認をしましょう
プロフィールをすでに作成してしまっている場合は新しくユーザーを作るなどしましょう
別のユーザーを使って動作確認する場合は別ユーザーのJWTを取得してModHeaderで切り替えて利用していきましょう

http://127.0.0.1:8000/api/profiles/ にアクセスします
プロフィールがない状態では空リストが表示されていることが確認できます

ではプロフィールを埋めていきましょう
ここで年齢などのバリデーションが効いているかも同時に確認しておきましょう
特に未成年チェックは必須です

作成した後にもう一度作成しようとしてみるとエラー(IntegrityError)で返されることも確認する
念のために作成されたユーザーは最初に入力したデータのままで作成されているか管理画面でも確認しておきましょう

異性をフィルタリングしたプロフィール一覧取得の確認(GET)

上記でプロフィールを作成したら再度http://127.0.0.1:8000/api/profiles/にアクセスします
ログインさせているユーザーの性別と違うユーザーだけが表示されていれば確認は完了です
同じことですがデータがない場合は新たに作成して確認みてください

プロフィール取得(/api/profiles/{pk})

プロフィールのあるユーザーを使用して/api/profiles/{異性ユーザーのUUID}にアクセスします
取得できれば成功です
なお、自身と同性ユーザーは取得できないことも確認しておきます

またPUTボタンを押して更新できないことを確認します

マッチングデータ作成・マッチング一覧取得(CREATE, GET /api/favorite/ )

次にマッチング機能(いいね機能)の動作を確認していきます
/api/favorite/にアクセスします
approachedでユーザーを選択してマッチングデータを作成します
ユーザは同性も選べますが異性を選んでおきましょう
POSTで作成が終わると再び同じURLでGETを実行しましょう

他にもマッチングデータを作成して想定通りのデータが取得できているか確認しましょう
自分に関連するデータだけが取得されているかを確認できれば成功です

マッチングデータ取得・更新(GET, PATCH /api/favorite/{pk})

次にマッチング機能(いいね機能)の更新処理の動作を確認していきます
/api/favorite/{自分と関連するマッチングデータのpk}にアクセスします
今回アクセスするマッチングデータのIDはUUIDではなくIntであることに注意します
マッチングデータのIDはhttp://127.0.0.1:8000/api/favorite/にアクセスしたときに表示されているIDから取得するか、管理画面の一覧画面にadmin.pyのlist_displayに'id'を追加するか、詳細画面の○○/{pk}/changeのpkを見ることでも取得できます

正しくアクセスできてPUTで更新処理が行えれば成功です

また/api/favorite/{自分と関連しないマッチングデータのpk}にアクセスすると404 Not Foundがレスポンスされることも確認しておきます

DM送信側処理(/api/dm-message/ )

次にDMの送信側の処理を動作確認します

送信側DM一覧取得(CREATE, GET)

approvedがTrueでapproachedに自分を指定しているマッチングデータのapproachingに対応するユーザーをreceiverに選択してmessageデータを作成するとデータが作成できてsenderに自分自身が入力されていることを確認します
またsenderが自分自身のmessageデータ一覧を取得できることを確認します

DM送信取得・更新取得(GET, PATCH /{pk}/ )

次に/api/dm-message/{自身がsenderになっているDMのpk}/にアクセスして送信済のデータを取得できるかを動作確認します
senderが他人のpkの場合は404 Not Foundであることも確認する
また、POSTMANで/api/dm-message/{自身がsenderになっているDMのpk}に対してPATCHを用いてメッセージの修正を目的とした更新が行えるかを確認する
なおJWTトークンをリクエストヘッダーに含めることを忘れないように

DM受信側一覧取得(GET /api/dm-message/, /api/dm-message/{pk})

次にDMの受信側の処理を動作確認します
まずは/api/dm-message/にアクセスしてreceiverが自分を差しているDMの一覧が取得できるか確認する
次に/api/dm-message/{自分がreceiverであるDMのpk}にアクセスしてDMが取得できるか確認する
receiverが自分ではないDMは404 Not Foundが返ってくることを確認する

トークン期限切れ確認

トークンの有効期限は今回1日に設定しているので期限切れで/api/のエンドポイントにアクセスするとアクセスが拒否されることを確認する

GET /api/

HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: JWT realm="api"

{
    "detail": "Given token not valid for any token type",
    "code": "token_not_valid",
    "messages": [
        {
            "token_class": "AccessToken",
            "token_type": "access",
            "message": "Token is invalid or expired"
        }
    ]
}

これで動作確認は終了です
想定通りの挙動になっていない場合はデバッグを行いましょう

次回予告

動作確認を終えて、これにてバックエンドの機能はほとんど完成しました
ところで本アプリは新規ユーザー作成時にアカウントをデフォルトで非アクティブにしているので次はアカウント作成時にメールを送信し、メール中に記載したURLからクレジットカード決済画面(Stripe)にアクセスして、決済が成功したユーザーをアクティブとする処理を加えていきましょう

なお対面などで年齢確認を行ってユーザーをアクティブにする運用の場合はクレジットカード決済を使用せずにその都度管理者が管理画面でユーザーのアクティベーションを手動で行うという方法もあるかもしれない


続きはこちらです

shinseidaiki.hatenablog.com