Mar 14 2018

How to use a CakePHP 3 REST API

In this follow-up post to How to build a CakePHP 3 REST API in minutes we explore the inner workings of our new API.

Run in Postman

We will address the most common use cases by:

  1. Adding some tasty cocktail data to our application (already listening at http://cake3api.app)
  2. Accessing the cocktail resources through our API using the:
    • index action (GET)
    • view action (GET)
    • add action (POST)
    • edit/update action (PUT)
    • delete action (DELETE)
  3. Configuring Pagination
  4. Testing Querystring Parameters

Before We Begin

This is part two of the CakePHP 3 REST API tutorial series:

  1. How to build a CakePHP 3 REST API in minutes
  2. How to use a CakePHP 3 REST API
  3. How to prefix route a CakePHP 3 REST API
  4. How to add JWT Authentication to a CakePHP 3 REST API
  5. How to make your CakePHP 3 API produce JSON API
  6. How to use a CakePHP API as the data backend for Ember in 30 minutes

Before starting this tutorial either:

1. Adding The Cocktails

Populate the database

Download this CakePHP database migration file to your config/Migrations directory.

Now run the following command inside your application’s root directory to create and popuplate the cocktails table:

1
bin/cake migrations migrate

Create the controller

Create a new file named src/Controller/CocktailsController.php with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
namespace App\Controller;

use App\Controller\AppController;

class CocktailsController extends AppController
{
public $paginate = [
'page' => 1,
'limit' => 10,
'maxLimit' => 100,
'fields' => [
'id', 'name', 'description'
],
'sortWhitelist' => [
'id', 'name', 'description'
]
];
}

Generate the entity and table

Generate the required entity and model by running the following command inside your application’s root directory:

1
bin/cake bake model Cocktails

Create html views

Even though your API does not need/use views to output JSON and XML (that part is handled for you by the CRUD plugin) we will still generate some html views for easy browsing the cocktails and to prepare for the follow-up tutorials.

Generate the views by by running the following command inside your application’s root directory:

1
bin/cake bake template Cocktails

If things went well browsing to http://cake3api.app/cocktails should display something similar to:

2. Accessing API Resources

Your API supports accessing resources with or without extensions and we will test both where applicable.

If you don’t have a client capable of testing Request Headers you might consider using:

Note: for brevity we will only test JSON responses.

Index action (GET)

Retrieve the first JSON page with cocktails from your API by either:

  • retrieving directly from http://cake3api.app/cocktails.json
  • querying http://cake3api.app/cocktails using:
    • HTTP Method GET
    • Accept Header application/json

Should return Status Code 200 (Success) with a JSON response body similar to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"success": true,
"data": [
{
"id": 1,
"name": "Cosmopolitan",
"description": "Vodka based"
},
{
"id": 2,
"name": "Margarita",
"description": "Tequila based"
},
{
"id": 3,
"name": "Mojito",
"description": "Rum based"
}
],
"pagination": {
"page_count": 5,
"current_page": 1,
"has_next_page": true,
"has_prev_page": false,
"count": 21,
"limit": null
}
}

View action (GET)

Specify a record id to retrieve JSON details for a single cocktail by either:

  • retrieving directly from e.g. http://cake3api.app/cocktails/5.json
  • querying http://cake3api.app/cocktails/5 using:
    • HTTP Method GET
    • Accept Header application/json

Should return Status Code 200 (Success) with a JSON response body similar to:

1
2
3
4
5
6
7
8
9
10
{
"success": true,
"data": {
"id": 5,
"name": "Caipirinha",
"description": "Rum based",
"created": "2015-04-11T09:33:37+0000",
"modified": null
}
}

Add action (POST)

Create a new cocktail record by posting JSON data to your API using:

  • The index URL http://cake3api.app/cocktails
  • HTTP Method POST
  • Accept Header application/json
  • Content-Type Header application/json
  • Body data in (absolutely) correct JSON format

Should return Status Code 201 (Created) with a JSON response body containing the id of the created cocktail similar to:

1
2
3
4
5
6
{
"success": true,
"data": {
"id": 22
}
}

Edit/Update action (PUT)

Change an existing cocktail by posting JSON data to our API using:

  • The view URL for the specific recipe, e.g. http://cake3api.app/cocktails/5
  • HTTP Method PUT
  • Accept Header application/json
  • Content-Type Header application/json
  • Partial or full body data in (absolutely) correct JSON format

Should return Status Code 200 (Success) with a JSON response body similar to:

1
2
3
4
{
"success": true,
"data": []
}

Delete action (DELETE)

Delete an existing cocktail through your API by using:

  • The view URL for the specific cocktail, e.g. http://cake3api.app/cocktails/5
  • HTTP Method DELETE
  • Accept Header application/json

Should return Status Code 200 (Success) on success with a JSON response body similar to:

1
2
3
4
{
"success": true,
"data": []
}

3. Configuring Pagination

The Paginator settings in src/Controller/CocktailsController.php are used by your API to format the outputted JSON/XML. Let’s change some of the settings below in preparation for querystring parameter testing.

1
2
3
4
5
6
7
8
9
10
11
public $paginate = [
'page' => 1,
'limit' => 10,
'maxLimit' => 100,
'fields' => [
'id', 'name', 'description'
],
'sortWhitelist' => [
'id', 'name', 'description'
]
];

Show all cocktail details/fields

To show all record details completely remove the fields array (used earlier to keep the JSON output examples readable).

Querying http://cake3api.app/cocktails.json?limit=2 should now produce more detailed JSON similar to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"success": true,
"data": [
{
"id": 1,
"name": "Cosmopolitan",
"description": "Vodka based",
"created": "2015-04-10T15:56:23+0000",
"modified": null
},
{
"id": 2,
"name": "Margarita",
"description": "Tequila based",
"created": "2015-04-10T15:59:39+0000",
"modified": null
}
],
"pagination": {
"page_count": 11,
"current_page": 1,
"has_next_page": true,
"has_prev_page": false,
"count": 21,
"limit": 2
}
}

Show less cocktails per page

To show only show 5 cocktails per page change limit => 10 to limit => 5.

Set maximum number of cocktails per page

To never show more than 15 cocktails change 'maxLimit' => 100 to 'maxLimit' => 15.

Prevent sorting by description

To prevent users from sorting by the description field remove description from the sortWhitelist array.

Default page

Do NOT change the default page used for the index resultset to prevent frustrating further tests.

4. Testing Querystring Parameters

Your API comes with support for querystring parameters that clients can use to manipulate the output produced by your API.

Limiting results

Clients can use the limit parameter to manipulate the number of records returned by your API.

To verify the parameter works as expected query http://cake3api.app/cocktails.json?limit=3.

The result should list three cocktails instead of (the now default) five.

Rate limiting

To verify your API is respecting the maxLimit Paginator setting query http://cake3api.app/cocktails.json?limit=20.

The result should only list 15 cocktails.

Sorting by field

Clients can use the sort parameter to specify which field should be used to sort the results produced by your API.

To verify the parameter is working as expected query http://cake3api.app/cocktails.json?sort=name.

The results should be sorted by cocktail name.

Sorting ascending/descending

Clients can use the direction parameter in combination with the sort parameter to specify the direction in which results are sorted by your API (either asc or desc).

To verify the parameter is working as expected query http://cake3api.app/cocktails.json?sort=name&direction=desc.

The results should be reverse-sorted by cocktail name.

Sort whitelist

To verify your API is respecting the sortWhitelist Paginator setting query http://cake3api.app/cocktails.json?sort=description.

The result should show the default (non-sorted) index results since we removed description from the sortWhitelist array.

Additional reading

Hat tip to CakePHP Core Developers jose_zap and ADmad for helping create this post.