質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

1回答

841閲覧

Laravel POSTリクエストが正しく動作しない

aniki2

総合スコア4

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2024/02/01 08:08

編集2024/02/02 01:05

実現したいこと

POSTリクエストで、フロント側から受け取ったJSON形式のデータをDBに保存したいです。

発生している問題・分からないこと

POSTリクエストを送信すると、LaravelのバージョンがJSON形式で返ってくる

Postmanで、body内にJSON形式のデータを入力、header内にContent-Typeをapplication/jsonと設定して、POSTリクエストを送信しました。

※laravel.logに出力されたログ
イメージ説明
※定義した配列はddメソッドが動作しているか確認するために記述しています。
イメージ説明
※GETリクエストの結果
イメージ説明
※POSTリクエストの結果
イメージ説明

エラーメッセージ

error

1local.ERROR: Debugbar exception: Attempt to read property "cookies" on null

該当のソースコード

Laravel

1<-- api.php --> 2<?php 3 4use Illuminate\Http\Request; 5use Illuminate\Support\Facades\Route; 6 7/* 8|-------------------------------------------------------------------------- 9| API Routes 10|-------------------------------------------------------------------------- 11| 12| Here is where you can register API routes for your application. These 13| routes are loaded by the RouteServiceProvider within a group which 14| is assigned the "api" middleware group. Enjoy building your API! 15| 16*/ 17 18Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) { 19 return $request->user(); 20}); 21 22Route::middleware('auth:sanctum')->post('/tokens/create', function (Request $request) { 23 $token = $request->user()->createToken($request->token_name); 24 25 return ['token' => $token->plainTextToken]; 26}); 27 28Route::prefix('v1')->group(function () { 29 Route::post('/register', [\App\Http\Controllers\Api\V1\AuthController::class, 'register']); 30 Route::post('/login', [\App\Http\Controllers\Api\V1\AuthController::class, 'login']); 31 Route::delete('/logout', [\App\Http\Controllers\Api\V1\AuthController::class, 'logout']); 32 33 Route::prefix('products')->group(function () { 34 Route::get('/', [\App\Http\Controllers\Api\V1\ProductsController::class, 'index']); 35 Route::get('/{id}', [\App\Http\Controllers\Api\V1\ProductsController::class, 'show']); 36 Route::get('/{productId}/reviews', [\App\Http\Controllers\Api\V1\ReviewsController::class, 'index']); 37 Route::post('/{productId}/reviews', [\App\Http\Controllers\Api\V1\ReviewsController::class, 'store']); 38 }); 39 40 Route::get('/tax_rates', [\App\Http\Controllers\Api\V1\TaxRatesController::class, 'index']); 41 42 Route::post('/check', [\App\Http\Controllers\Api\V1\AuthController::class, 'check']); 43 44 Route::group(['middleware' => 'auth:sanctum'], function () { 45 Route::prefix('carts')->group(function () { 46 Route::get('/', [\App\Http\Controllers\Api\V1\CartsController::class, 'index']); 47 Route::post('/', [\App\Http\Controllers\Api\V1\CartsController::class, 'store']); 48 Route::patch('/{id}', [\App\Http\Controllers\Api\V1\CartsController::class, 'update']); 49 Route::delete('/{id}', [\App\Http\Controllers\Api\V1\CartsController::class, 'delete']); 50 }); 51 52 Route::prefix('orders')->group(function () { 53 Route::get('/', [\App\Http\Controllers\Api\V1\OrdersController::class, 'index']); 54 Route::post('/', [\App\Http\Controllers\Api\V1\OrdersController::class, 'create']); 55 }); 56 }); 57}); 58 59 60<-- Controller --> 61<?php 62 63namespace App\Http\Controllers\Api\V1; 64 65use Illuminate\Http\JsonResponse; 66use Illuminate\Http\Request; 67use App\Interfaces\Services\ReviewServiceInterface; 68use App\Models\Review; 69use App\Services\ReviewService; 70use Illuminate\Support\Facades\Auth; 71use App\Http\Requests\Review\ReviewsRequest; 72use App\Http\Resources\ReviewResource; 73use App\Interfaces\Repositories\ReviewRepositoryInterface; 74use Illuminate\Support\Facades\Log; 75 76/** 77 * レビュー関連コントローラ 78 */ 79class ReviewsController extends BaseController 80{ 81 private ReviewServiceInterface $reviewService; 82 private ReviewRepositoryInterface $reviewRepository; 83 84 public function __construct(ReviewServiceInterface $reviewService, ReviewRepositoryInterface $reviewRepository) 85 { 86 $this->reviewService = $reviewService; 87 88 $this->middleware('reviews.request')->only('store'); 89 } 90 91 public function index(int $productId): JsonResponse 92 { 93 Log::info("called index method"); 94 95 $response = $this->reviewService->getReviewByProductId($productId); 96 return response()->json($response); 97 } 98 99 public function store(ReviewsRequest $request, int $productId) 100 { 101 Log::info("called store method"); 102 103 $reviewData = $request->all(); 104 $response = $this->reviewService->saveReviewByProductId($reviewData, $productId); 105 106 return response()->json($response, 201); 107 } 108} 109 110<-- Service --> 111<?php 112 113namespace App\Services; 114 115use App\Http\Requests\ReviewsRequest; 116use App\Http\Resources\ReviewResource; 117use App\Interfaces\Repositories\ReviewRepositoryInterface; 118use App\Interfaces\Services\ReviewServiceInterface; 119 120class ReviewService implements ReviewServiceInterface 121{ 122 protected ReviewRepositoryInterface $reviewRepository; 123 124 public function __construct(ReviewRepositoryInterface $reviewRepository) 125 { 126 $this->reviewRepository = $reviewRepository; 127 } 128 129 public function getReviewByProductId(int $productId) 130 { 131 return $this->reviewRepository->getReview($productId); 132 } 133 134 public function saveReviewByProductId(array $reviewsData, int $productId) 135 { 136 return $this->reviewRepository->saveReview($reviewsData, $productId); 137 } 138} 139 140 141<-- Repository --> 142<?php 143 144namespace App\Repositories; 145 146use Illuminate\Database\Eloquent\Builder; 147 148use App\Interfaces\Repositories\ReviewRepositoryInterface; 149use App\Models\Review; 150use Illuminate\Support\Facades\DB; 151 152class ReviewRepository extends BaseRepository implements ReviewRepositoryInterface 153{ 154 protected Review $review; 155 156 public function __construct(Review $review) 157 { 158 $this->review = $review; 159 } 160 161 public function all(string $column = 'created_at', string $direction = 'asc'): Builder 162 { 163 return $this->review::orderBy($column, $direction); 164 } 165 public function getReview(int $productId) 166 { 167 return $this->review::where('product_id', $productId)->get(); 168 } 169 170 public function saveReview(array $reviewData, int $productId): Review 171 { 172 return DB::transaction(function () use ($reviewData, $productId) { 173 try { 174 return $this->review::where('product_id', $productId)->create($reviewData); 175 } catch (\Exception $e) { 176 DB::rollBack(); 177 throw new \Exception("Failed to save review: " . $e->getMessage()); 178 } 179 }); 180 } 181} 182

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

local.ERROR: Debugbar exception: Attempt to read property "cookies" on null

上記で検索して、middlewareに問題があると認識しました。

storeメソッド内のddメソッドでrequestの値を確認しようとしましたが、dd自体が処理されていません。

補足

PHP 8.2.14
Laravel 9.52.16

パッケージ管理ツール:Composer
運用環境:Ubuntu, Docker

コンテナ:
meilisearch-1 (Exited)
mysql-1    (Running)
mailpit-1    (Running)
laravel.test-1 (Running)
redis-1    (Running)
selenium-1  (Running)
front-1    (Running)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aniki2

2024/02/01 09:08

.envのAPP_DEBUGをfalseにすることで、上記のエラーは解消しました。 しかし、ddメソッドは処理されません。
退会済みユーザー

退会済みユーザー

2024/02/01 23:44

routes/api.phpを全部書かないと他人には分からない。質問者が「この辺が原因なはず」と思い込んで必要な箇所だけ書いても本当の原因は別なことがほとんど。
aniki2

2024/02/02 01:08

ご提案ありがとうございます。 api.phpに加えて他ファイルも全文記載いたしました。
guest

回答1

0

試していたらすみません、おそらくですがセキュリティに使うcsrfトークンのやりとりがないのではないでしょうか。
postリクエストだとcsrf攻撃を防ぐためにcsrfトークンをリクエストに含めてフロントからリクエストをもらわないと、laravel側のセキュリティーに弾かれるのではと思います。

質問者さんはフロントエンドとバックエンド分けて製作していると見受けられます。
この場合の通信の流れとしては、本命のリクエストの前にlaravel側にcsrfトークンを発行してくれというプリフライトリクエストというのが先に実行されてcsrfトークンを取得し、それを本命のpostリクエストのリクエストヘッダーに付与して実行される流れがあります。

本来はフロントからプリフライトリクエストが行われて、返却されてきたcsrfトークンはcookieにいったん保存され、それをpostリクエストのリクエストheaderに付与することでcsrf対策の取れた通信が行われます。

postmanを使って検証していると思われるので、このプリフライトリクエストがデフォルトでは行われていない状態です。また、一時的にcsrfトークンを保管する場所がpostmanの環境変数として保存し、それをリクエストヘッダーに含める必要があります。

下記サイトなどを参考にしてはどうでしょうか。
https://qiita.com/b95oss/items/8478c99583d72812d313

見当違いだったらすみません。。

投稿2024/02/01 10:44

ryuichi-works

総合スコア40

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aniki2

2024/02/02 01:28

ご回答くださりありがとうございます。 ご提案頂けるだけでも嬉しいです。 CSRFトークン発行後postリクエストに付与する点を踏まえて、 一度確認してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問