モバイル開発とJavaScriptフレームワークの台頭により、RESTful APIを使用することは、データとクライアントの間に単一のインターフェースを構築するための最良のオプションです。
Laravel で開発されたPHPフレームワークです PHP開発者 生産性を念頭に置いて。テイラーオトウェルによって書かれ、維持されているフレームワークは非常に意見が高く、設定より規約を優先することで開発者の時間を節約しようと努めています。このフレームワークは、Webとともに進化することも目的としており、ジョブキュー、すぐに使用できるAPI認証、リアルタイム通信など、Web開発の世界にいくつかの新しい機能やアイデアがすでに組み込まれています。
このチュートリアルでは、認証付きのLaravelを使用して堅牢なAPIを構築およびテストする方法について説明します。 Laravel 5.4を使用します。すべてのコードは、 GitHub 。
まず、RESTfulAPIと正確に見なされるものを理解する必要があります。 RESTはの略です 代表的なStateTransfer また、アプリケーション間のネットワーク通信のアーキテクチャスタイルであり、相互作用をステートレスプロトコル(通常はHTTP)に依存します。
RESTful APIでは、アクションとしてHTTP動詞を使用し、エンドポイントは作用を受けるリソースです。意味的な意味にはHTTP動詞を使用します。
GET
:リソースを取得するPOST
:リソースを作成するPUT
:リソースを更新しますDELETE
:リソースを削除します
RESTful APIは多くの議論の的であり、POST
、PATCH
、またはPUT
で更新するのが最善かどうか、または作成アクションを残すのが最善かどうかについては多くの意見がありますPUT
へ動詞。この記事では、PUT
を使用しますHTTP RFCによると、更新アクションの場合、PUT
特定の場所でリソースを作成/更新することを意味します。 PUT
のもう1つの要件動詞はべき等です。この場合、基本的には、その要求を1、2、または1000回送信でき、結果は同じになります。つまり、データベース内の1つの更新されたリソースです。
リソース(この場合は記事とユーザー)がアクションのターゲットになり、独自のエンドポイントがあります。
/articles
/users
このlaravelapiチュートリアルでは、リソースはデータモデル上で1:1の表現になりますが、それは必須ではありません。リソースを複数のデータモデルで表す(またはデータベースでまったく表さない)ことができ、モデルはユーザーの立ち入りが完全に禁止されています。最終的には、アプリケーションに適した方法でリソースとモデルを設計する方法を決定できます。
RESTなどの一連の規則を使用する最大の利点は、APIの使用と開発がはるかに簡単になることです。一部のエンドポイントは非常に単純であり、その結果、GET /get_article?id_article=12
などのエンドポイントを使用する場合とは対照的に、APIの使用と保守がはるかに簡単になります。およびPOST /delete_article?number=40
。私は過去にそのようなひどいAPIを構築しましたが、今でもそれを嫌っています。
ただし、作成/取得/更新/削除スキーマへのマッピングが難しい場合があります。 URLには動詞を含めるべきではなく、リソースは必ずしもテーブルの行である必要はないことに注意してください。もう1つ覚えておくべきことは、すべてのリソースに対してすべてのアクションを実装する必要はないということです。
最新のすべてのPHPフレームワークと同様に、 作曲 依存関係をインストールして処理します。ダウンロード手順に従った後(そしてパス環境変数に追加した後)、次のコマンドを使用してLaravelをインストールします。
$ composer global require laravel/installer
インストールが完了したら、次のような新しいアプリケーションをスキャフォールディングできます。
$ laravel new myapp
上記のコマンドでは、~/composer/vendor/bin
が必要です。あなたの$PATH
で。これに対処したくない場合は、Composerを使用して新しいプロジェクトを作成することもできます。
$ composer create-project --prefer-dist laravel/laravel myapp
Laravelをインストールすると、サーバーを起動して、すべてが機能しているかどうかをテストできるはずです。
$ php artisan serve Laravel development server started:
localhost:8000
ブラウザに、このサンプルページが表示されます。最初の移行を実際に作成する前に、このアプリ用にデータベースが作成されていることを確認し、その資格情報を.env
に追加してください。プロジェクトのルートにあるファイル。
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret
Laravel用に特別に作成されたVagrantボックスであるHomesteadを使用することもできますが、それはこの記事の範囲外です。詳細を知りたい場合は、 Homesteadのドキュメントを参照してください 。
最初のモデルと移行であるArticleから始めましょう。記事には、タイトルと本文フィールド、および作成日が必要です。 Laravelは、Artisan(Laravelのコマンドラインツール)を介していくつかのコマンドを提供します。これらのコマンドは、ファイルを生成して正しいフォルダーに配置するのに役立ちます。 Articleモデルを作成するには、次のコマンドを実行します。
$ php artisan make:model Article -m
-m
オプションは--migration
の略ですそして、Artisanにモデル用に作成するように指示します。生成された移行は次のとおりです。
increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('articles'); } }
これを少し分析してみましょう。
up()
およびdown()
メソッドは、それぞれ移行およびロールバック時に実行されます。$table->increments('id')
id
という名前の自動インクリメント整数を設定します。$table->timestamps()
タイムスタンプを設定します— created_at
およびupdated_at
ですが、デフォルトの設定について心配する必要はありません。Laravelが必要に応じてこれらのフィールドを更新します。Schema::dropIfExists()
もちろん、テーブルが存在する場合は削除します。それが邪魔にならないように、up()
に2行追加しましょう方法:
public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('body'); $table->timestamps(); }); }
string()
メソッドはVARCHAR
を作成します同等の列text()
TEXT
同等のものを作成します。それが終わったら、先に進んで移行しましょう。
$ php artisan migrate
--step
を使用することもできますここでオプションを選択すると、各移行が独自のバッチに分割されるため、必要に応じて個別にロールバックできます。
箱から出してすぐに使えるLaravelには、2つの移行が付属していますcreate_users_table
およびcreate_password_resets_table
。 password_resets
は使用しませんテーブルですが、users
があります私たちのために用意されたテーブルが役に立ちます。
それでは、モデルに戻って、それらの属性を$fillable
に追加しましょう。 Article::create
で使用できるようにフィールドおよびArticle::update
モデル:
class Article extends Model { protected $fillable = ['title', 'body']; }
$fillable
内のフィールドプロパティは、Eloquentのcreate()
を使用して一括割り当てできます。およびupdate()
メソッド。$guarded
を使用することもできますプロパティ。一部を除くすべてのプロパティを許可します。
データベースシードは、データベースをテストに使用できるダミーデータでデータベースを埋めるプロセスです。 Laravelには フェイカー 、ダミーデータの正しい形式を生成するための優れたライブラリです。それでは、最初のシーダーを作成しましょう。
$ php artisan make:seeder ArticlesTableSeeder
シーダーは/database/seeds
に配置されますディレクトリ。いくつかの記事を作成するように設定した後の様子は次のとおりです。
class ArticlesTableSeeder extends Seeder { public function run() { // Let's truncate our existing records to start from scratch. Article::truncate(); $faker = FakerFactory::create(); // And now, let's create a few articles in our database: for ($i = 0; $i $faker->sentence, 'body' => $faker->paragraph, ]); } } }
それでは、seedコマンドを実行しましょう。
$ php artisan db:seed --class=ArticlesTableSeeder
このプロセスを繰り返して、ユーザーシーダーを作成しましょう。
class UsersTableSeeder extends Seeder { public function run() { // Let's clear the users table first User::truncate(); $faker = FakerFactory::create(); // Let's make sure everyone has the same password and // let's hash it before the loop, or else our seeder // will be too slow. $password = Hash::make('toptal'); User::create([ 'name' => 'Administrator', 'email' => ' [email protected] ', 'password' => $password, ]); // And now let's generate a few dozen users for our app: for ($i = 0; $i $faker->name, 'email' => $faker->email, 'password' => $password, ]); } } }
シーダーをメインに追加することで簡単にできますDatabaseSeeder
database/seeds
内のクラスフォルダ:
class DatabaseSeeder extends Seeder { public function run() { $this->call(ArticlesTableSeeder::class); $this->call(UsersTableSeeder::class); } }
このようにして、$ php artisan db:seed
を実行するだけです。そして、run()
で呼び出されたすべてのクラスを実行します方法。
アプリケーションの基本的なエンドポイントを作成しましょう。リストの作成、取得、単一のリストの取得、更新、削除です。 routes/api.php
についてファイルの場合、これを簡単に行うことができます。
Use AppArticle; Route::get('articles', function() { // If the Content-Type and Accept headers are set to 'application/json', // this will return a JSON structure. This will be cleaned up later. return Article::all(); }); Route::get('articles/{id}', function($id) { return Article::find($id); }); Route::post('articles', function(Request $request) { return Article::create($request->all); }); Route::put('articles/{id}', function(Request $request, $id) { $article = Article::findOrFail($id); $article->update($request->all()); return $article; }); Route::delete('articles/{id}', function($id) { Article::find($id)->delete(); return 204; })
api.php
内のルートプレフィックスは/api/
になりますAPIスロットリングミドルウェアはこれらのルートに自動的に適用されます(プレフィックスを削除する場合は、RouteServiceProvider
の/app/Providers/RouteServiceProvider.php
クラスを編集できます)。
次に、このコードを独自のコントローラーに移動しましょう。
$ php artisan make:controller ArticleController
ArticleController.php:
use AppArticle; class ArticleController extends Controller { public function index() { return Article::all(); } public function show($id) { return Article::find($id); } public function store(Request $request) { return Article::create($request->all()); } public function update(Request $request, $id) { $article = Article::findOrFail($id); $article->update($request->all()); return $article; } public function delete(Request $request, $id) { $article = Article::findOrFail($id); $article->delete(); return 204; } }
routes/api.php
ファイル:
Route::get('articles', ' [email protected] '); Route::get('articles/{id}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{id}', ' [email protected] '); Route::delete('articles/{id}', ' [email protected] ');
暗黙的なルートモデルバインディングを使用して、エンドポイントを改善できます。このようにして、LaravelはArticle
を注入しますメソッド内のインスタンスであり、見つからない場合は自動的に404を返します。ルートファイルとコントローラーを変更する必要があります。
角度4フォーム送信例
Route::get('articles', ' [email protected] '); Route::get('articles/{article}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{article}', ' [email protected] '); Route::delete('articles/{article}', ' [email protected] ');
class ArticleController extends Controller { public function index() { return Article::all(); } public function show(Article $article) { return $article; } public function store(Request $request) { $article = Article::create($request->all()); return response()->json($article, 201); } public function update(Request $request, Article $article) { $article->update($request->all()); return response()->json($article, 200); } public function delete(Article $article) { $article->delete(); return response()->json(null, 204); } }
response()->json()
も追加しましたエンドポイントを呼び出します。これにより、JSONデータを明示的に返すだけでなく、クライアントが解析できるHTTPコードを送信できます。返される最も一般的なコードは次のとおりです。
200
:わかりました。標準の成功コードとデフォルトのオプション。201
:オブジェクトが作成されました。 store
に役立ちます行動。204
:コンテンツなし。アクションが正常に実行されたが、返すコンテンツがない場合。206
:部分的なコンテンツ。リソースのページ付けされたリストを返す必要がある場合に便利です。400
:リクエストが正しくありません。検証に合格しなかったリクエストの標準オプション。401
:無許可。ユーザーを認証する必要があります。403
:禁止されています。ユーザーは認証されていますが、アクションを実行するための権限がありません。404
:見つかりません。リソースが見つからない場合、これはLaravelによって自動的に返されます。500
:内部サーバーエラー。理想的には、これを明示的に返すことはありませんが、予期しない何かが壊れた場合、これはユーザーが受け取るものです。503
:サービスを利用できません。かなり自明ですが、アプリケーションによって明示的に返されることのない別のコードもあります。存在しないリソースをフェッチしようとすると、例外がスローされ、次のようにスタックトレース全体を受け取ります。
app/Exceptions/Handler.php
にある例外ハンドラークラスを編集してJSON応答を返すことで、これを修正できます。
public function render($request, Exception $exception) { // This will replace our 404 response with // a JSON response. if ($exception instanceof ModelNotFoundException) { return response()->json([ 'error' => 'Resource not found' ], 404); } return parent::render($request, $exception); }
返品の例は次のとおりです。
{ data: 'Resource not found' }
Laravelを使用して他のページを提供している場合は、Accept
で機能するようにコードを編集する必要がありますヘッダー、それ以外の場合、通常のリクエストからの404エラーもJSONを返します。
public function render($request, Exception $exception) { // This will replace our 404 response with // a JSON response. if ($exception instanceof ModelNotFoundException && $request->wantsJson()) { return response()->json([ 'data' => 'Resource not found' ], 404); } return parent::render($request, $exception); }
この場合、APIリクエストにはヘッダーAccept: application/json
が必要です。
LaravelでAPI認証を実装する方法はたくさんあります(そのうちの1つは パスポート 、OAuth2)を実装するための優れた方法ですが、この記事では、非常に単純化されたアプローチを採用します。
開始するには、api_token
を追加する必要がありますusers
へのフィールドテーブル:
$ php artisan make:migration --table=users adds_api_token_to_users_table
そして、移行を実装します。
public function up() { Schema::table('users', function (Blueprint $table) { $table->string('api_token', 60)->unique()->nullable(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn(['api_token']); }); }
その後、以下を使用して移行を実行します。
$ php artisan migrate
RegisterController
を利用します(Auth
フォルダー内)登録時に正しい応答を返します。 Laravelにはすぐに認証が付属していますが、必要な応答を返すために少し調整する必要があります。
コントローラーは特性を利用しますRegistersUsers
登録を実装します。仕組みは次のとおりです。
public function register(Request $request) { // Here the request is validated. The validator method is located // inside the RegisterController, and makes sure the name, email // password and password_confirmation fields are required. $this->validator($request->all())->validate(); // A Registered event is created and will trigger any relevant // observers, such as sending a confirmation email or any // code that needs to be run as soon as the user is created. event(new Registered($user = $this->create($request->all()))); // After the user is created, he's logged in. $this->guard()->login($user); // And finally this is the hook that we want. If there is no // registered() method or it returns null, redirect him to // some other URL. In our case, we just need to implement // that method to return the correct response. return $this->registered($request, $user) ?: redirect($this->redirectPath()); }
registered()
を実装する必要がありますRegisterController
のメソッド。メソッドは$request
を受け取りますそして$user
なので、本当に必要なのはそれだけです。コントローラ内でのメソッドの外観は次のとおりです。
protected function registered(Request $request, $user) { $user->generateToken(); return response()->json(['data' => $user->toArray()], 201); }
そして、ルートファイルにリンクできます。
Route::post('register', 'Auth [email protected] ');
上記のセクションでは、Userモデルのメソッドを使用してトークンを生成しました。これは、トークンを生成する方法が1つしかない場合に役立ちます。次のメソッドをユーザーモデルに追加します。
class User extends Authenticatable { ... public function generateToken() { $this->api_token = str_random(60); $this->save(); return $this->api_token; } }
以上です。これでユーザーが登録され、Laravelの検証とすぐに使用できる認証のおかげで、name
、email
、password
、password_confirmation
が登録されました。フィールドは必須であり、フィードバックは自動的に処理されます。 validator()
をチェックアウトしてくださいRegisterController
内のメソッドルールがどのように実装されているかを確認します。
そのエンドポイントに到達すると、次のようになります。
$ curl -X POST http://localhost:8000/api/register -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{'name': 'John', 'email': ' [email protected] ', 'password': 'toptal123', 'password_confirmation': 'toptal123'}'
{ 'data': { 'api_token':'0syHnl0Y9jOIfszq11EC2CBQwCfObmvscrZYo5o2ilZPnohvndH797nDNyAT', 'created_at': '2017-06-20 21:17:15', 'email': ' [email protected] ', 'id': 51, 'name': 'John', 'updated_at': '2017-06-20 21:17:15' } }
登録エンドポイントと同様に、LoginController
を編集できます。 (Auth
フォルダー内)API認証をサポートします。 login
AuthenticatesUsers
のメソッドAPIをサポートするために、トレイトをオーバーライドできます。
public function login(Request $request) { $this->validateLogin($request); if ($this->attemptLogin($request)) { $user = $this->guard()->user(); $user->generateToken(); return response()->json([ 'data' => $user->toArray(), ]); } return $this->sendFailedLoginResponse($request); }
そして、ルートファイルにリンクできます。
Route::post('login', 'Auth [email protected] ');
さて、シーダーが実行されたと仮定すると、POST
を送信すると次のようになります。そのルートへのリクエスト:
$ curl -X POST localhost:8000/api/login -H 'Accept: application/json' -H 'Content-type: application/json' -d '{'email': ' [email protected] ', 'password': 'toptal' }'
{ 'data': { 'id':1, 'name':'Administrator', 'email':' [email protected] ', 'created_at':'2017-04-25 01:05:34', 'updated_at':'2017-04-25 02:50:40', 'api_token':'Jll7q0BSijLOrzaOSm5Dr5hW9cJRZAJKOzvDlxjKCXepwAeZ7JR6YP5zQqnw' } }
リクエストでトークンを送信するには、属性api_token
を送信してトークンを送信できます。ペイロード内、またはリクエストヘッダー内のベアラートークンとしてAuthorization: Bearer Jll7q0BSijLOrzaOSm5Dr5hW9cJRZAJKOzvDlxjKCXepwAeZ7JR6YP5zQqnw
の形式で。
現在の戦略では、トークンが間違っているか欠落している場合、ユーザーは認証されていない応答を受け取るはずです(これは次のセクションで実装します)。したがって、単純なログアウトエンドポイントの場合、トークンを送信すると、データベースから削除されます。
routes/api.php
:
Route::post('logout', 'Auth [email protected] ');
AuthLoginController.php
:
public function logout(Request $request) { $user = Auth::guard('api')->user(); if ($user) { $user->api_token = null; $user->save(); } return response()->json(['data' => 'User logged out.'], 200); }
この戦略を使用すると、ユーザーが持っているトークンはすべて無効になり、APIはアクセスを拒否します(次のセクションで説明するように、ミドルウェアを使用します)。これは、ユーザーがコンテンツにアクセスせずにログに記録されたままにならないように、フロントエンドと調整する必要があります。
api_token
で作成されたら、routesファイルで認証ミドルウェアを切り替えることができます。
Route::middleware('auth:api') ->get('/user', function (Request $request) { return $request->user(); });
$request->user()
を使用して現在のユーザーにアクセスできますメソッドまたはAuthファサードを介して
Auth::guard('api')->user(); // instance of the logged user Auth::guard('api')->check(); // if a user is authenticated Auth::guard('api')->id(); // the id of the authenticated user
そして、次のような結果が得られます。
これは、現在のunauthenticated
を編集する必要があるためです。 Handlerクラスのメソッド。現在のバージョンは、リクエストにAccept: application/json
がある場合にのみJSONを返しますヘッダーなので、変更しましょう。
protected function unauthenticated($request, AuthenticationException $exception) { return response()->json(['error' => 'Unauthenticated'], 401); }
これを修正したら、記事のエンドポイントに戻って、それらをauth:api
でラップできます。ミドルウェア。ルートグループを使用してこれを行うことができます。
Route::group(['middleware' => 'auth:api'], function() { Route::get('articles', ' [email protected] '); Route::get('articles/{article}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{article}', ' [email protected] '); Route::delete('articles/{article}', ' [email protected] '); });
このように、ルートごとにミドルウェアを設定する必要はありません。今のところ多くの時間を節約することはできませんが、プロジェクトが成長するにつれて、ルートをドライに保つのに役立ちます。
Laravelには、すぐに使用できるPHPUnitとの統合が含まれていますphpunit.xml
すでに設定されています。このフレームワークは、特にAPIのテストにおいて、私たちの生活をはるかに楽にするいくつかのヘルパーと追加のアサーションも提供します。
APIのテストに使用できる外部ツールは多数あります。ただし、Laravel内でのテストは、はるかに優れた代替手段です。データベースの完全な制御を維持しながら、API構造と結果をテストすることのすべての利点を得ることができます。たとえば、リストエンドポイントの場合、いくつかのファクトリを実行し、応答にそれらのリソースが含まれていると主張できます。
開始するには、インメモリSQLiteデータベースを使用するためにいくつかの設定を微調整する必要があります。これを使用すると、テストが非常に高速に実行されますが、トレードオフとして、一部の移行コマンド(制約など)がその特定のセットアップで正しく機能しないことがあります。移行エラーが発生し始めたとき、またはパフォーマンスの高い実行ではなく、より強力なテストセットが必要な場合は、テストでSQLiteから離れることをお勧めします。
また、各テストの前に移行を実行します。この設定により、テストごとにデータベースを構築してから破棄できるため、テスト間の依存関係を回避できます。
私たちのconfig/database.php
ファイルの場合、database
を設定する必要がありますsqlite
のフィールド:memory:
への構成:
... 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], ... ]
次に、phpunit.xml
でSQLiteを有効にします環境変数DB_CONNECTION
を追加する:
TestCase
それが邪魔にならないので、あとはベースを構成するだけですDatabaseMigrations
移行を使用し、各テストの前にデータベースをシードするクラス。そのためには、Artisan
を追加する必要があります特性を追加してから、setUp()
を追加しますuse IlluminateFoundationTestingDatabaseMigrations; use IlluminateFoundationTestingTestCase as BaseTestCase; use IlluminateSupportFacadesArtisan; abstract class TestCase extends BaseTestCase { use CreatesApplication, DatabaseMigrations; public function setUp() { parent::setUp(); Artisan::call('db:seed'); } }
に電話してください方法。変更後のクラスは次のとおりです。
composer.json
最後にやりたいことは、テストコマンドを 'scripts': { 'test' : [ 'vendor/bin/phpunit' ], ... },
に追加することです。
$ composer test
テストコマンドは次のように使用できます。
database/factories
工場では、テストに適したデータを使用してオブジェクトをすばやく作成できます。それらはUser
にありますフォルダ。 Laravelは、Article
用のファクトリーを備えた箱から出てきますクラスなので、$factory->define(AppArticle::class, function (FakerGenerator $faker) { return [ 'title' => $faker->sentence, 'body' => $faker->paragraph, ]; });
に1つ追加しましょうクラス:
$ php artisan make:test Feature/LoginTest
ザ・ フェイカー モデルのランダムデータの正しい形式を作成するために、ライブラリはすでに挿入されています。
Laravelのassertメソッドを使用して、エンドポイントに簡単にヒットし、その応答を評価できます。次のコマンドを使用して、最初のテストであるログインテストを作成しましょう。
class LoginTest extends TestCase { public function testRequiresEmailAndLogin() { $this->json('POST', 'api/login') ->assertStatus(422) ->assertJson([ 'email' => ['The email field is required.'], 'password' => ['The password field is required.'], ]); } public function testUserLoginsSuccessfully() { $user = factory(User::class)->create([ 'email' => ' [email protected] ', 'password' => bcrypt('toptal123'), ]); $payload = ['email' => ' [email protected] ', 'password' => 'toptal123']; $this->json('POST', 'api/login', $payload) ->assertStatus(200) ->assertJsonStructure([ 'data' => [ 'id', 'name', 'email', 'created_at', 'updated_at', 'api_token', ], ]); } }
そして、これが私たちのテストです:
json()
これらのメソッドは、いくつかの単純なケースをテストします。 assertJson()
メソッドはエンドポイントにヒットし、他のアサートはかなり自明です。 assertJson()
に関する1つの詳細:このメソッドは、応答を配列に変換して引数を検索するため、順序が重要です。複数の$ php artisan make:test RegisterTest
をチェーンできますその場合は呼び出します。
それでは、レジスタエンドポイントテストを作成し、そのエンドポイントのカップルを作成しましょう。
class RegisterTest extends TestCase { public function testsRegistersSuccessfully() { $payload = [ 'name' => 'John', 'email' => ' [email protected] ', 'password' => 'toptal123', 'password_confirmation' => 'toptal123', ]; $this->json('post', '/api/register', $payload) ->assertStatus(201) ->assertJsonStructure([ 'data' => [ 'id', 'name', 'email', 'created_at', 'updated_at', 'api_token', ], ]);; } public function testsRequiresPasswordEmailAndName() { $this->json('post', '/api/register') ->assertStatus(422) ->assertJson([ 'name' => ['The name field is required.'], 'email' => ['The email field is required.'], 'password' => ['The password field is required.'], ]); } public function testsRequirePasswordConfirmation() { $payload = [ 'name' => 'John', 'email' => ' [email protected] ', 'password' => 'toptal123', ]; $this->json('post', '/api/register', $payload) ->assertStatus(422) ->assertJson([ 'password' => ['The password confirmation does not match.'], ]); } }
$ php artisan make:test LogoutTest
そして最後に、ログアウトエンドポイント:
class LogoutTest extends TestCase { public function testUserIsLoggedOutProperly() { $user = factory(User::class)->create(['email' => ' [email protected] ']); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; $this->json('get', '/api/articles', [], $headers)->assertStatus(200); $this->json('post', '/api/logout', [], $headers)->assertStatus(200); $user = User::find($user->id); $this->assertEquals(null, $user->api_token); } public function testUserWithNullToken() { // Simulating login $user = factory(User::class)->create(['email' => ' [email protected] ']); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; // Simulating logout $user->api_token = null; $user->save(); $this->json('get', '/api/articles', [], $headers)->assertStatus(401); } }
TokenGuard
テスト中、Laravelアプリケーションは新しいリクエストで再度インスタンス化されないことに注意することが重要です。つまり、認証ミドルウェアにアクセスすると、現在のユーザーが
class ArticleTest extends TestCase { public function testsArticlesAreCreatedCorrectly() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; $payload = [ 'title' => 'Lorem', 'body' => 'Ipsum', ]; $this->json('POST', '/api/articles', $payload, $headers) ->assertStatus(200) ->assertJson(['id' => 1, 'title' => 'Lorem', 'body' => 'Ipsum']); } public function testsArticlesAreUpdatedCorrectly() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; $article = factory(Article::class)->create([ 'title' => 'First Article', 'body' => 'First Body', ]); $payload = [ 'title' => 'Lorem', 'body' => 'Ipsum', ]; $response = $this->json('PUT', '/api/articles/' . $article->id, $payload, $headers) ->assertStatus(200) ->assertJson([ 'id' => 1, 'title' => 'Lorem', 'body' => 'Ipsum' ]); } public function testsArtilcesAreDeletedCorrectly() { $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; $article = factory(Article::class)->create([ 'title' => 'First Article', 'body' => 'First Body', ]); $this->json('DELETE', '/api/articles/' . $article->id, [], $headers) ->assertStatus(204); } public function testArticlesAreListedCorrectly() { factory(Article::class)->create([ 'title' => 'First Article', 'body' => 'First Body' ]); factory(Article::class)->create([ 'title' => 'Second Article', 'body' => 'Second Body' ]); $user = factory(User::class)->create(); $token = $user->generateToken(); $headers = ['Authorization' => 'Bearer $token']; $response = $this->json('GET', '/api/articles', [], $headers) ->assertStatus(200) ->assertJson([ [ 'title' => 'First Article', 'body' => 'First Body' ], [ 'title' => 'Second Article', 'body' => 'Second Body' ] ]) ->assertJsonStructure([ '*' => ['id', 'body', 'title', 'created_at', 'updated_at'], ]); } }
内に保存されます。データベースに再度アクセスしないようにするためのインスタンス。ただし、賢明な選択です。この場合、以前にキャッシュされたユーザーの問題を回避するために、ログアウトテストを2つに分割する必要があります。githubページはいくつ持つことができますか
Articleエンドポイントのテストも簡単です。
|_+_|
これですべてです。間違いなく改善の余地があります。OAuth2を実装できます。 パスポート パッケージ化、ページ付けと変換レイヤーを統合します(私はお勧めします フラクタル )、リストは続きますが、外部パッケージを使用せずにLaravelでAPIを作成してテストするための基本を学びたかったのです。
Laravelの開発 確かに私の経験を改善しました PHP そして、それを使ったテストの容易さは、フレームワークへの私の興味を固めました。完璧ではありませんが、問題を回避するのに十分な柔軟性があります。
パブリックAPIを設計している場合は、チェックアウトしてください 優れたWebAPI設計のための5つのゴールデンルール 。
関連: 完全なユーザー認証とアクセス制御– Laravel Passportチュートリアル、Pt。 1Laravelは意見の分かれたPHPフレームワークです。これは、生産性、保守、および上位互換性を促進するために、Webアプリケーションを構築する際の細かな点を抽象化します。
REpresentational State Transfer(REST)およびRESTful Webサービスは、ステートレスプロトコル(HTTPなど)を介してアプリケーションの状態を転送するための、アプリケーション間のネットワーク通信のスタイルを表します。
JSONとXMLはテキストデータ形式です。 JSON(JavaScript Object Notation)はJavaScript構文を使用してデータを表現し、データを解析可能にしますが、XML(eXtensible Markup Language)はマークアップのタグ付けとネストを使用して同じことを実現します。
Composerは、アプリケーションレベルでソフトウェアの依存関係を管理するPHPのパッケージマネージャーです。