diff --git a/README.md b/README.md index db8fcea..e9ed0a4 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,26 @@ class RecipeController extends Controller Take a look at [swisnl/json-api-client](https://github.com/swisnl/json-api-client) for more usage information. +### Laravel HTTP Client + +You can also use the built-in [HTTP Client](https://laravel.com/docs/http-client) of Laravel if you prefer. Please note this requires Laravel 7+. + +``` php +use Illuminate\Support\Facades\Http; +use Swis\JsonApi\Client\Facades\DocumentFactoryFacade; +use Swis\JsonApi\Client\Item; + +$recipe = (new Item()) + ->setType('recipes') + ->fill([ + 'title' => 'Frankfurter salad with mustard dressing', + ]); + +$document = Http::asJsonApi() // Sets the Content-Type and Accept headers to 'application/vnd.api+json'. + ->post('https://cms.contentacms.io/api/recipes', DocumentFactoryFacade::make($recipe)) + ->jsonApi(); // Parses the response into a JSON:API document. +``` + ## Service Provider diff --git a/src/Providers/ServiceProvider.php b/src/Providers/ServiceProvider.php index 917ef08..f376da7 100644 --- a/src/Providers/ServiceProvider.php +++ b/src/Providers/ServiceProvider.php @@ -4,11 +4,16 @@ namespace Swis\JsonApi\Client\Providers; +use Illuminate\Http\Client\PendingRequest; +use Illuminate\Http\Client\Response; +use Illuminate\Support\Facades\Http; use Illuminate\Support\ServiceProvider as BaseServiceProvider; use Swis\JsonApi\Client\Client; use Swis\JsonApi\Client\DocumentClient; +use Swis\JsonApi\Client\Facades\ResponseParserFacade; use Swis\JsonApi\Client\Interfaces\ClientInterface; use Swis\JsonApi\Client\Interfaces\DocumentClientInterface; +use Swis\JsonApi\Client\Interfaces\DocumentInterface; use Swis\JsonApi\Client\Interfaces\DocumentParserInterface; use Swis\JsonApi\Client\Interfaces\ResponseParserInterface; use Swis\JsonApi\Client\Interfaces\TypeMapperInterface; @@ -28,6 +33,8 @@ public function register() $this->registerSharedTypeMapper(); $this->registerParsers(); $this->registerClients(); + + $this->registerLaravelHttpClientMacros(); } public function boot() @@ -65,4 +72,28 @@ static function (ClientInterface $client) { $this->app->bind(ClientInterface::class, Client::class); $this->app->bind(DocumentClientInterface::class, DocumentClient::class); } + + protected function registerLaravelHttpClientMacros(): void + { + if (!class_exists(Http::class)) { + // N.B. The HTTP Client was introduced in Laravel 7. + return; + } + + if (!PendingRequest::hasMacro('asJsonApi')) { + PendingRequest::macro('asJsonApi', function (): PendingRequest { + /* @var \Illuminate\Http\Client\PendingRequest $this */ + return $this->bodyFormat('json') + ->contentType('application/vnd.api+json') + ->accept('application/vnd.api+json'); + }); + } + + if (!Response::hasMacro('jsonApi')) { + Response::macro('jsonApi', function (): DocumentInterface { + /* @var \Illuminate\Http\Client\Response $this */ + return ResponseParserFacade::parse($this->toPsrResponse()); + }); + } + } } diff --git a/tests/Providers/ServiceProviderTest.php b/tests/Providers/ServiceProviderTest.php new file mode 100644 index 0000000..1b89698 --- /dev/null +++ b/tests/Providers/ServiceProviderTest.php @@ -0,0 +1,55 @@ +markTestSkipped('The Laravel HTTP Client is not available.'); + } + + parent::setUp(); + } + + /** + * @test + */ + public function itRegistersHttpFacadeMacroForRequest(): void + { + // arrange + Http::fake(); + + // act + Http::asJsonApi()->get('https://example.com'); + + // assert + Http::assertSent(static function (Request $request) { + return $request->hasHeader('Content-Type', 'application/vnd.api+json') && + $request->hasHeader('Accept', 'application/vnd.api+json'); + }); + } + + /** + * @test + */ + public function itRegistersHttpFacadeMacroForResponse(): void + { + // arrange + Http::fake(); + + // act + $data = Http::get('https://example.com')->jsonApi(); + + // assert + $this->assertInstanceOf(Document::class, $data); + } +}