apeescape2.com
  • メイン
  • 仕事の未来
  • プロセスとツール
  • Webフロントエンド
  • その他
バックエンド

Laravel APIチュートリアル:RESTfulAPIを構築してテストする方法

モバイル開発とJavaScriptフレームワークの台頭により、RESTful APIを使用することは、データとクライアントの間に単一のインターフェースを構築するための最良のオプションです。

Laravel で開発されたPHPフレームワークです PHP開発者 生産性を念頭に置いて。テイラーオトウェルによって書かれ、維持されているフレームワークは非常に意見が高く、設定より規約を優先することで開発者の時間を節約しようと努めています。このフレームワークは、Webとともに進化することも目的としており、ジョブキュー、すぐに使用できるAPI認証、リアルタイム通信など、Web開発の世界にいくつかの新しい機能やアイデアがすでに組み込まれています。

LaravelAPIチュートリアル-RESTfulWebサービスの構築



このチュートリアルでは、認証付きのLaravelを使用して堅牢なAPIを構築およびテストする方法について説明します。 Laravel 5.4を使用します。すべてのコードは、 GitHub 。

RESTfulAPI

まず、RESTfulAPIと正確に見なされるものを理解する必要があります。 RESTはの略です 代表的なStateTransfer また、アプリケーション間のネットワーク通信のアーキテクチャスタイルであり、相互作用をステートレスプロトコル(通常はHTTP)に依存します。

HTTP動詞はアクションを表します

RESTful APIでは、アクションとしてHTTP動詞を使用し、エンドポイントは作用を受けるリソースです。意味的な意味にはHTTP動詞を使用します。

  • GET:リソースを取得する
  • POST:リソースを作成する
  • PUT:リソースを更新します
  • DELETE:リソースを削除します

HTTP動詞:GET、POST、PUT、およびDELETEはRESTfulAPIのアクションです

更新アクション:PUTとPOST

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つ覚えておくべきことは、すべてのリソースに対してすべてのアクションを実装する必要はないということです。

LaravelWebサービスプロジェクトの設定

最新のすべての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を開くと、Laravelのサンプルページが表示されます。

開くと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); } }

HTTPステータスコードと応答形式に関する注記

response()->json()も追加しましたエンドポイントを呼び出します。これにより、JSONデータを明示的に返すだけでなく、クライアントが解析できるHTTPコードを送信できます。返される最も一般的なコードは次のとおりです。

  • 200:わかりました。標準の成功コードとデフォルトのオプション。
  • 201:オブジェクトが作成されました。 storeに役立ちます行動。
  • 204:コンテンツなし。アクションが正常に実行されたが、返すコンテンツがない場合。
  • 206:部分的なコンテンツ。リソースのページ付けされたリストを返す必要がある場合に便利です。
  • 400:リクエストが正しくありません。検証に合格しなかったリクエストの標準オプション。
  • 401:無許可。ユーザーを認証する必要があります。
  • 403:禁止されています。ユーザーは認証されていますが、アクションを実行するための権限がありません。
  • 404:見つかりません。リソースが見つからない場合、これはLaravelによって自動的に返されます。
  • 500:内部サーバーエラー。理想的には、これを明示的に返すことはありませんが、予期しない何かが壊れた場合、これはユーザーが受け取るものです。
  • 503:サービスを利用できません。かなり自明ですが、アプリケーションによって明示的に返されることのない別のコードもあります。

正しい404応答を送信する

存在しないリソースをフェッチしようとすると、例外がスローされ、次のようにスタックトレース全体を受け取ります。

NotFoundHttpExceptionスタックトレース

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にはすぐに認証が付属していますが、必要な応答を返すために少し調整する必要があります。

APIが英語の場合、これはAPI認証の会話がどのように聞こえるかです。

コントローラーは特性を利用します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

そして、次のような結果が得られます。

InvalidArgumentExceptionスタックトレース

これは、現在の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。 1

基本を理解する

Laravelとは何ですか?

Laravelは意見の分かれたPHPフレームワークです。これは、生産性、保守、および上位互換性を促進するために、Webアプリケーションを構築する際の細かな点を抽象化します。

RESTとは何ですか?

REpresentational State Transfer(REST)およびRESTful Webサービスは、ステートレスプロトコル(HTTPなど)を介してアプリケーションの状態を転送するための、アプリケーション間のネットワーク通信のスタイルを表します。

JSONとXMLの違いは何ですか?

JSONとXMLはテキストデータ形式です。 JSON(JavaScript Object Notation)はJavaScript構文を使用してデータを表現し、データを解析可能にしますが、XML(eXtensible Markup Language)はマークアップのタグ付けとネストを使用して同じことを実現します。

Composerとは何ですか?

Composerは、アプリケーションレベルでソフトウェアの依存関係を管理するPHPのパッケージマネージャーです。

より良いUXのためのUIスタイルガイドの作成

Uiデザイン

より良いUXのためのUIスタイルガイドの作成
COVID-19のスモールビジネスリソース:ローン、助成金、クレジット

COVID-19のスモールビジネスリソース:ローン、助成金、クレジット

収益性と効率性

人気の投稿
PHPおよびMySQLでのUTF-8エンコーディングのガイド
PHPおよびMySQLでのUTF-8エンコーディングのガイド
ミニチュートリアル–設計プロセス全体でFigmaの機能を活用
ミニチュートリアル–設計プロセス全体でFigmaの機能を活用
ACRAとCloudantを使用した自動Androidクラッシュレポート
ACRAとCloudantを使用した自動Androidクラッシュレポート
デザインにおけるAIの現在と未来(インフォグラフィック付き)
デザインにおけるAIの現在と未来(インフォグラフィック付き)
UIとUX:ユーザーインターフェイスデザインの重要なガイド
UIとUX:ユーザーインターフェイスデザインの重要なガイド
 
効果的なデザインフレームワークを作成する方法(無料のSketchユーザーインターフェイスフレームワークを含む)
効果的なデザインフレームワークを作成する方法(無料のSketchユーザーインターフェイスフレームワークを含む)
スキャン性を向上させるためのUIデザインのベストプラクティス
スキャン性を向上させるためのUIデザインのベストプラクティス
言語サーバープロトコルチュートリアル:VSCodeからVimへ
言語サーバープロトコルチュートリアル:VSCodeからVimへ
事業運営部長
事業運営部長
ブランディングは死に、CXデザインは王様
ブランディングは死に、CXデザインは王様
人気の投稿
  • ApacheSparkはどのように機能しますか
  • デザイン思考が重要な理由
  • ブートストラップテンプレートの使用方法
  • trello vs asana vs jira
  • cで書かれたPythonです
  • これらのうち、ユーザビリティの例を最もよく表しているのはどれですか?
カテゴリー
トレンド 製品の担当者とチーム プロセスとツール デザイナーライフ 投資家と資金調達 リモートの台頭 バックエンド 分散チーム プロジェクト管理 エンジニアリング管理

© 2021 | 全著作権所有

apeescape2.com