Let’s Build an API in 15 Minutes

I’m one of the co-organizers of the Vancouver PHP meetup and I had an idea to see if I could pull off writing an (simple) API in 15 minutes. I’ll be the first to admit this is ambitious and also vague.

A good API takes more than 15 minutes to build, we have to contend with security, code-readability, authentication, etc, etc. But the title served a purpose to get people interested and attending this meetup.

Shoutout to my pal Mike Bird for his support. Thank goodness for strong moral support…

After doing the talk I’ve realized that this can probably be turned into an ongoing series that I give in 10–15 minute increments at future Vancouver PHP meetups.

The goal of this article is to share what we did during the talk and provide a basis to work from in the future.

So to get started, my framework of choice is Laravel and I’ve decided to utilize a lot of Laravel’s artisan commands to aid my building of this API.


The goal of this API is to be able to have REST endpoints for Patients and Clinic models.

Since I love to have my models in their own folder instead of running loose in the /app` folder I can build my artisan command like so:

php artisan make:model Models/Clinic

But I’m lazy, and I realized that I can make a command that extends Laravel's own ModelMakeCommand. The following gist shows the code that allows you to change the make:model command use a Models folder space every time.

So we can make this command via:

php artisan make:command ModelMakeCommand

Now all my make:model commands will put my Model files into the my preferred folder.

php artisan make:model Clinic

php artisan make:model Patient

Note: you can extend Laravel’s other make commands in the same way. Give it a shot!


Next step is to create a migration for these two models.

php artisan make:migration create_clinics_table

php artisan make:migration create_patients_table

Now we can run these migrations and populate our database with

php artisan migrate

Seeds & Model Factories

Now to help us with our API we want to populate the database with some seed data. Laravel has some fantastic support via Seeds and Model Factories here.

To start I created a simple ClinicFactory and PatientFactory through artisan.

php artisan make:factory ClinicFactory

php artisan make:factory PatientFactory

By utilizing the Faker library we can populate our DB with fake but correct-ish looking data.

Now that we have these factories, let’s make some the seeders so that we can seed the database with the model factory data.

php artisan make:seed ClinicSeeder

and php artisan make:seed PatientSeeder

So, you can see that by calling the factory() helper it will take the Model and use the Model factory to build the data. We can see in the ClinicSeeder we are creating 20 clinics and in PatientSeeder we are creating 100 patients.

To run this we can do php artisan db:seed --class=ClinicSeeder and php artisan db:seed --class=PatientSeeder. Now we should see our database populated with a bunch of data.

Note: You can change the number of records you make in the seeder if you want a quick way to populate the data with LOTS of data to test the performance of your app with a large data-set.


Now that our data is ready, let’s build the Controllers.

php artisan make:controller ClinicController -r

It’s important to note that the -r auto-populates the Controller with the CRUD resource methods.

To keep this really simple we can start with our index() method and list out all the clinics:

public function index()
$clinics = Clinic::all();

return response()->json($clinics);

That will return all our clinics out in a simple json representation.

What if over time we end up with thousands of clinics? It’s not efficient to list out all these clinics in our API. So let’s make this paginate.

public function index()
$clinics = Clinic::paginate();

return response()->json($clinics);

Pretty simple, eh? We now have pagination and it will tell us next and previous page. The format will look something like:

"total": 50,
"per_page": 15,
"current_page": 1,
"last_page": 4,
"first_page_url": "http://laravel.app?page=1",
"last_page_url": "http://laravel.app?page=4",
"next_page_url": "http://laravel.app?page=2",
"prev_page_url": null,
"path": "http://laravel.app",
"from": 1,
"to": 15,
// Result Object
// Result Object

But what if we want to have more control over our output? By default the data is returning every field in the database. Perhaps we don’t want share that much info.

Note: you can hide/show on the model directly via

protected $visible [
// Visible table fields go here

API Resources

In the actual talk I opted to share information about API Resources. The reason why I chose API Resources over the $visible property is that perhaps some of my API outputs want some items visible and some hidden. The property on the model acts as a catch-all.

php artisan make:resource ClinicIndexResource

Without changing anything in this file, I can change my controller method to the following:

public function index()
return new ClinicIndexResource(Clinic::paginate());

This will return my data in the API format desired, but now I have control on what I can make appear for this endpoint.

In this example I ONLY want to return the name of the clinic. Now I have granular control over the output. Eventually I could build it out to add more properties, relations, and much more.

Another reason I like API Resources is because this allows me to abstract the logic of the controllers output into its own class. This allows me to follow a better Single Responsibility Principle, where this class has a single job in returning the format of the output.


This is where I stopped as I think we had passed the 15 minute mark and were inching close to the 20 minute mark.

I think for what we accomplished in 15 minutes during this talk is quite a fair amount thanks to the Laravel framework.

To recap we’ve been able to accomplish:

  • Database migrations and test data in our database
  • An API endpoint that outputs the Clinic listings in json format with pagination
  • Ability to control the output of the Clinic listing as we see fit

This is a great basis for being able to continue building on some great work, and that is exactly what I will do at the next Vancouver PHP Meetup. Hope to see you there!

Like what you read? Give Shawn Mayzes a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.