FYI this is not a guide
Day 6 of 100DaysOfCode
Completed HypeTracker's first and second test case for the Sneaker API using test driven development (TDD).
In this short post, I'll go over how I used test driven development to migrate the get all sneaker API route for project HypeTracker.
Find the project on GitHub here:
jcsho / hype-tracker
Full stack web application to read data from public APIs (Twitter, Reddit) and form visualizations
HypeTracker is a data aggregator application for social media 'impressions' on sneakers bought and sold in the aftermarket.
See my blog detailing what HypeTracker is and why I am refactoring it
Changelog / Goals for V2
-
migrate database schemasee PR #4 -
migrate internal sneakers APIsee PR #7 -
migrate front-end see PR#17 - deploy as demo / push as v2
- add social media api scraping
Getting Started
Requirements
Homestead
- PHP ^7.3
- Composer ^1.10.13
- Vagrant ^2.2.10 (with your choice of virtualization layer)
- (example) VirtualBox ^6.1.14 (with Vagrant's VirtualBox provider)
$ git clone https://github.com/justinhodev/hype-tracker.git
$ cd hype-tracker
# Install Composer Dependencies
$ composer install
# Prepare config for Homestead
$ composer homestead
# Provision the VM
$ vagrant up
# SSH into Vagrant Box
$ vagrant ssh
Docker
coming soon
Database Entity Relationship Model
License
TDD with Laravel
Writing a Test
First, of course, I have to start off with a test case.
Laravel's artisan
CLI tool aids in developer experience because you can just run php artisan make:test SneakerApiUnitTest --unit
and end up with below (without the funtion).
class SneakerApiUnitTest extends TestCase
{
/**
* Get All Sneakers.
*
* @return void
*/
public function testGetAllSneakers()
{
$response = $this->json('GET', '/api/sneakers');
$response->assertStatus(200);
}
}
This is where I felt Laravel's "convention over configuration" philosophy shined as the documentation on testing has clearly sections on how to develop and test REST API routes.
The first test is relatively simple as I will be getting all sneakers and since the database is seeded with random data, I only wanted to make sure I got something back.
Run php artisan test
and the output should be like this:
Yes it's supposed to fail, I haven't built anything yet!
Building the API
Next, to build out a REST API with a JSON response, the minimal amount of coding requires a Model object returning JSON from the api.php
file. However, I am going to split this functionality properly into 2 separate components: the controller and the resource collection.
Controller
// app/Http/Controllers/API/SneakerController.php
class SneakerController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return new SneakerCollection(Sneaker::all());
}
// ...
}
A controller in Laravel helps map specific HTTP routes to the various verbal actions in REST (GET, POST, PUT, DELETE). In this case the index()
function maps to an HTTP GET request without extra parameters (GET '/api/sneakers').
Resource Collection
// app/Http/Resources/SneakerCollection.php
class SneakerCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'total' => $this->count(),
'data' => $this->collection,
];
}
}
A Laravel resource is the data access layer which maps a database object to the return fields you want to retrieve (ex. removing the create_at
field in the JSON response but have access to it in memory). Meanwhile, the resource collection is Laravel's way to modify the final output from many resources (ex. adding a total
field as the first item like I did above).
I am splitting the functionality into its respective groupings as I already have and know the final API and this method is more scalable and easier to manage. If you were starting from scratch, I would recommend just returning JSON from the Model object straight from the API route.
Finally, bind the controller and resource collection to an API route.
// routes/api.php
Route::apiResources([
'sneakers' => SneakerController::class,
]);
Now rerun php artisan test
!
That's it, a simple REST API GET route done with TDD. Of course, this isn't very detailed but its mostly showing my process and progress. I might make a more detailed guide later on once I am further along my project. Still very backlogged on these challenge posts.
In the meantime, feel free to follow me on Twitter @justinhodev to keep up with my journey!
Top comments (0)