پروژه لاراول را ایجاد می کنیم.
به فایل .env می رویم و یک نام برای دیتابیس انتخاب میکنیم. مثلا :
DB_DATABASE=laravel_api
به phpMyAdmin می رویم و دیتابیس را می سازیم.
یک مدل ایجاد می کنیم بطور مثال برای پست ها :
php artisan make:model Post -m
m- برای این است که migration هم برای آن ساخته شود.
در داخل مدل Post اضافه می کنیم :
class Post extends Model { use HasFactory; protected $table = 'posts'; protected $guarded = []; }
در قسمت migrations فایل create_post_table را باز میکنیم و فیلدهای جدول post را وارد می کنیم. به طور مثال :
public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('body'); $table->string('image'); $table->foreignId('user_id'); $table->foreign('user_id')-> references('id')->on('users')->onDelete('cascade'); $table->timestamps(); }); }
با استفاده از دستور زیر جداول را میسازیم :
php artisan migrate
اگر هنگام ساختن جداول به ارور بر خوردیم در فایل AppServiceProvider در تابع register خط زیر را اضافه می کنیم :
public function register() { Schema::defaultStringLength(191); }
به پوشه routes رفته و فایل api را باز می کنیم و روت زیر را اضافه میکنیم.
Route::get('/posts',[PostController::class,'index']);
حالا باید PostController را با دستور زیر ایجاد کنیم :
php artisan make:controller PostController
فایل PostController را باز کرده و تابع index را می سازیم :
class PostController extends ApiController { public function index() { return response()->json(Post::all(), 200); } }
این تابع تمامی پست ها را بر می گرداند.
در پوشه App یک پوشه درست می کنیم به نام Traits و یک فایل به نام ApiResponser.php در داخل آن ایجاد می کنیم و کدهای زیر را در داخل آن قرار می دهیم :
<?php namespace App\Traits; trait ApiResponser { protected function successResponse($data, $code, $message = null) { return response()->json([ 'status' => 'success', 'message' => $message, 'data' => $data, ], $code); } protected function errorResponse($message = null, $code) { return response()->json([ 'status' => 'error', 'message' => $message, 'data' => '', ], $code); } }
یک کنترلر ایجاد می کنیم :
php artisan make:controller ApiController
در داخل آن :
<?php namespace App\Http\Controllers; use App\Traits\ApiResponser; use Illuminate\Http\Request; class ApiController extends Controller { use ApiResponser; }
حالا در داخل PostController می توانیم آن را از ApiController بصورت extends کنیم:
حالا ما به دو تابع successResponse و errorResponse در تمامی پروژه دسترسی داریم و بصورت زیر از آنها استفاده می کنیم.
class PostController extends ApiController { public function index() { return $this->successResponse(Post::all(), 200); // return $this->errorResponse('Error', 500); } }
در api یک روت تعریف می کنیم :
Route::post('/posts',[PostController::class,'store']);
در PostController تابع store را ایجاد میکنیم:
public function store(Request $request) { $post = Post::create([ 'title' => $request->title, 'body' => $request->body, 'image' => $request->image, 'user_id' => $request->user_id, ]); return $this->successResponse($post, 201); // return $this->errorResponse('Error', 500); }
در داخل تابع store به صورت زیر از validator استفاده می کنیم :
$validator = Validator::make($request->all(), [ 'title' => 'required|string', 'body' => 'required|string', 'image' => 'required', 'user_id' => 'required', ]); if ($validator->fails()) { return $this->errorResponse($validator->messages(), 422); }
که اگر باارور مواجه شدیم و fails شد برای ما ارور بر می گرداند.
یک روت دیگر می سازیم برای نمایش یک پست با آی دی مشخص :
Route::get('/posts/{post}',[PostController::class,'show']);
و در PostController تابع show را ایجاد می کنیم:
public function show(Post $post) { return $this->successResponse($post, 200); // return $this->errorResponse('Error', 500); }
نکته مهم :
ما چون داریم restfull کار میکنیم اگر این api کال شود مثلا بصورت زیر:
http://localhost:8000/api/posts/14
اگر پست با آیدی 14 وجود نداشته باشد بصورت html ریسپانس برمیگرداند در صورتی که ما میخواهیم بصورت json برگرداند.
پس در داخل فایل Handler.php در پوشه Exceptions تابع render را به این صورت وارد می کنیم:
public function render($request, Throwable $e) { if ($e instanceof ModelNotFoundException) { return $this->errorResponse($e->getMessage(), 404); } return $this->errorResponse($e->getMessage(), 500); }
باید توجه داشته باشیم که ApiResponser را باید use کنیم
use App\Traits\ApiResponser;
حالا ارورهای 404 با ریسپانس زیر مواجه می شود :
{ "status": "error", "message": "No query results for model [App\\Models\\Post]", "data": "" }
در تابع store برای image بصورت زیر اضافه میکنیم. یعنی حتما image باشد
$validator = Validator::make($request->all(), [ 'title' => 'required|string', 'body' => 'required|string', 'image' => 'required|image', 'user_id' => 'required', ]);
تا اینجا حتما باید یک فایل image ارسال شود در غیر اینصورت با ارور مواجه می شوی.
حالا برای ذخیره عکس و برای اینکه اسامی تکراری برای عکس ها انتخاب نشود یک اسم یکتا برای ان انتخاب می کنیم.
$imageName = Carbon::now()->microsecond . '.' . $request->image->extension();
حالا میخواهیم بعد از اینکه یک اسم یکتا برای فایل انتخاب کردیم انرا در storage ذخیره کنیم :
$request->image->storeAs('images/posts', $imageName, 'public');
اسم public یعنی عکسها و فایلها در پوشه app/storage/app/public ذخیره می شود. البته در پوشه images/posts .
نکته : ما بعد از build شدن پروژه به این پوشه دسترسی نداریم. برای اینکه بهد از ساخته شدن پروژه به عکسها و فایلها دسترسی داشته باشیم از دستور زیر استفاده می کنیم:
php artisan storage:link
این کار باعث لینک شدن پوشه ما در public به پوشه public بعد از build می شود.
حالا ما می توانیم از طریق لینکی شبیه لینک زیر به فایل مربوطه دسترسی داشته باشیم:
http://localhost:8000/storage/images/posts/498535.jpg
روت را می سازیم :
Route::put('/posts/{post}',[PostController::class,'update']);
در PostController تابع update را ایجاد می کنیم :
public function update(Request $request, Post $post) { $validator = Validator::make($request->all(), [ 'title' => 'required|string', 'body' => 'required|string', 'image' => 'image', 'user_id' => 'required', ]); if ($validator->fails()) { return $this->errorResponse($validator->messages(), 422); } if ($request->has('image')) { $imageName = Carbon::now()->microsecond . '.' . $request->image->extension(); $request->image->storeAs('images/posts', $imageName, 'public'); } $post ->update([ 'title' => $request->title, 'body' => $request->body, 'image' => $request->has('image') ? $imageName : $post->image, 'user_id' => $request->user_id, ]); return $this->successResponse($post, 200); // return $this->errorResponse('Error', 500); }
برای delete هم بصورت مشابه روت را می سازیم :
Route::delete('/posts/{post}',[PostController::class,'delete']);
در PostController تابع delete را ایجاد می کنیم :
public function delete(Post $post) { $post = $post->delete(); return $this->successResponse($post, 200); // return $this->errorResponse('Error', 500); }
یک کنترلر می سازیم :
php artisan make:controller UserController --api
عبارت api- باعث می شود تا درون کنترلر توابع مورد نیاز ساخته شود.
حالا به فایل api می رویم و روت زیر را اضافه میکنیم:
Route::apiResource('users',UserController::class);
حالا ااگر دستورزیر را وارد کنیم می بین که تمامی روت های به لیست روتهای ما اضافه شده است.
php artisan route:list