Lawman: Pest Architecture Testing for Saloon API Integrations
Photo by Nikola Jovanovic on Unsplash
Introduction
If you've been reading my content for a while, you'll likely know that I love building and testing API integrations in Laravel. They're both really fun tasks that can be rewarding when you get them right.
Using Saloon for building API integrations in my Laravel projects has made this even more fun! It's a really powerful tool that makes it easy to build and test API integrations in Laravel. In fact, a huge amount of my book, Consuming APIs in Laravel, is dedicated to using Saloon to build and test API integrations.
Thanks to a cool package called "Lawman" by Jon Purvis, we can take the testing even further to add some really powerful Pest architecture tests to our Saloon integration code.
In this article, we're going to take a look at some examples of how you might want to use Lawman in your PHP and Laravel projects.
If you're not already familiar with what architecture testing is and what it achieves, you might want to check out my "Architecture Testing in Laravel with Pest" article which explains it in more detail.
Installation
To get started with Lawman, you'll first need to install it. You can do this using Composer by running the following command in your project root:
composer require jonpurvis/lawman --dev
It's worth noting that we're using the --dev flag here to ensure that Lawman is only installed in your development environment. This is because Lawman is a testing tool and you don't want it to be included in your production environment.
Usage Examples
Now that you've got Lawman installed, you can start using it to test your Saloon integrations.
To get a good idea of the architecture testing expectations it provides, let's take a look at some examples.
We'll imagine we've built a simple GitHub API integration in a Laravel application using Saloon. We might have the following files that contain our integration code:
Connector:
app/Http/Integrations/GitHub/GitHubConnector.php
Requests:
app/Http/Integrations/GitHub/Requests/CreateRepoRequest.phpapp/Http/Integrations/GitHub/Requests/GetReposRequest.php
Let's look at a test that we could write for our app/Http/Integrations/GitHub/GitHubConnector.php file using Lawman's expectations:
use App\Http\Integrations\GitHub\GitHubConnector;
test('connectors')
->expect(GitHubConnector::class)
->toBeSaloonConnector()
->toUseAcceptsJsonTrait()
->toUseAlwaysThrowOnErrorsTrait()
->toBeTriedAgainOnFailure()
->toHaveRetryInterval()
->toUseExponentialBackoff()
->toHaveRateLimits();
In the architecture test above, we're asserting that our App\Http\Integrations\GitHub\GitHubConnector meets several criteria:
- It extends the
Saloon\Http\Connectorclass. - It uses the
Saloon\Traits\Plugins\AcceptsJsontrait. - It uses the
Saloon\Traits\Plugins\AlwaysThrowOnErrorstrait. - It has a
triesproperty that is greater than 1 (for retrying requests on failure). - It has a
retryIntervalproperty (used for specifying how long to wait between retries). - It has a
useExponentialBackoffproperty (used for specifying whether to use exponential backoff for the request retries). - It uses the
Saloon\RateLimitPlugin\Traits\HasRateLimitsplugin.
If any of the above criteria aren't met, the test will fail.
You may also want to write a test to ensure that all the PHP files within the App\Http\Integrations\GitHub\Requests directory are Saloon request classes:
test('requests')
->expect('App\Http\Integrations\GitHub\Requests')
->toBeSaloonRequest();
The cool thing about Lawman is that you're not restricted to only using Lawman's expectations - you can still use Pest's default expectations too. For example, we could use some of Pest's default expectations to the update the test above:
test('requests')
->expect('App\Http\Integrations\GitHub\Requests')
->toBeSaloonRequest()
->toHaveSuffix('Request')
->toUseStrictTypes()
->toBeFinal();
In the test above, we're asserting that all the PHP files within the App\Http\Integrations\GitHub\Requests namespace meet the following criteria:
- Must be a Saloon request class
- The classname must end with "Request"
- The files are using strict types
- The files are marked as
final
Lawman also allows you to ensure that given files in a namespace are using the correct HTTP methods. For example, you may want to assert that a request class sends a GET request and also has caching enabled:
use App\Http\Integrations\GitHub\Requests\GetReposRequest;
test('get requests')
->expect(GetReposRequest::class)
->toSendGetRequest()
->toHaveCaching();
Another example might be to assert that a request class sends a POST request and has a JSON body:
use App\Http\Integrations\GitHub\Requests\CreateRepoRequest;
test('post requests')
->expect(CreateRepoRequest::class)
->toSendPostRequest()
->toHaveJsonBody();
Available Expectations
We can't cover all the expectations that Lawman provides (this article would end up being huge!). But here's a list of the other expectations that are available to you:
Authentication
toUseTokenAuthenticationtoUseBasicAuthenticationtoUseCertificateAuthenticationtoUseHeaderAuthentication
Caching
toHaveCaching
Connector
toBeSaloonConnector
Pagination
toUsePagedPaginationtoUseOffsetPaginationtoUseCursorPaginationtoUseCustomPagination
Properties
toSetConnectTimeouttoSetRequestTimeouttoBeTriedAgainOnFailuretoHaveRetryIntervaltoUseExponentialBackofftoThrowOnMaxTries
Rate Limiting
toHaveRateLimits
Requests
toBeSaloonRequesttoHaveRequestMethodtoSendGetRequesttoSendPostRequesttoSendHeadRequesttoSendPutRequesttoSendPatchRequesttoSendDeleteRequesttoSendOptionsRequesttoSendConnectRequesttoSendTraceRequesttoHaveJsonBodytoHaveMultipartBodytoHaveXmlBodytoHaveFormBodytoHaveStringBodytoHaveStreamBody
Response
toBeSaloonResponse
Traits
toUseAcceptsJsonTraittoUseAlwaysThrowOnErrorsTraittoUseTimeoutTraittoUseAuthorisationCodeGrantTraittoUseClientCredentialsGrantTrait
Conclusion
Hopefully, this article has given you an insight into how to use Lawman to add some powerful Pest architecture tests to your Saloon integration code.
If you enjoyed reading this post, you might be interested in checking out my 440+ page ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.
If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter below.
Keep on building awesome stuff! ?
Other articles you might like
Laravel 12 Custom Validation Rules Example
In this Laravel tutorial titled “laravel 12 custom validation rules example”, you will learn how to...
Returning HTTP 404 Responses Instead of 403 for Unauthorised Access
Introduction When building a web application, you typically add authorisation checks to ensure that...
Run PHPUnit and Pest Tests Without Vite Assets in Laravel
Introduction A common way to build your Laravel application's frontend assets is with Vite (by runni...
The Laravel portal for problem solving, knowledge sharing and community building.