Advertisement
  1. Code
  2. PHP
  3. Yii

Programming With Yii2: Building a RESTful API

Scroll to top
Read Time: 7 min
This post is part of a series called How to Program With Yii2.
How to Program With Yii2: Running Cron Services
Programming With Yii2: Building Community With Voting, Comments, and Sharing
Final product imageFinal product imageFinal product image
What You'll Be Creating

In this Programming With Yii2 series, I'm guiding readers in use of the Yii2 Framework for PHP. You may also be interested in my Introduction to the Yii Framework, which reviews the benefits of Yii and includes an overview of what's new in Yii 2.x.

In today's tutorial, I will review how to build a REST API in Yii to connect your application to the cloud, mobile apps, and other services. I'll guide you through Yii's REST API quick start guide and provide context and examples of common requests.

Getting Started With Yii REST APIs

Building REST APIs in Yii is actually fairly straightforward. You can leverage the existing MVC framework, but you're creating a distinct access point that you intend to be accessed by different kinds of services (not website visitors).

The Benefits of the Yii REST Framework

The Yii Framework provides broad support and detailed documentation for building APIs. Here are some of the built-in capabilities when building APIs:

  • Quick prototyping with support for common APIs for Active Record. This allows you to quickly and easily expose data model CRUD functionality via an API.
  • Response format negotiation (supporting JSON and XML by default). There's built-in support for returning data in common output formats.
  • Customizable object serialization with support for selectable output fields. It's easy to modify what data is returned.
  • Proper formatting of collection data and validation errors.
  • Support for Hypermedia As The Engine Of Application State (HATEOAS)
  • Efficient routing with proper HTTP verb check.
  • Built-in support for the OPTIONS and HEAD verbs.
  • Authentication and authorization.
  • Data caching and HTTP caching.
  • Rate limiting.

I won't have a chance to touch on all of this today.

My Interest in REST APIs

In this episode, I'll build an API to let us manipulate the Item table I created in the Twixxr service from this Twitter API tutorial. But I'm also planning to build an API for our startup tutorial series focus, Meeting Planner. A secure API will be necessary for building an iOS application for the service. The API will enable communication between the mobile app and the cloud service.

Building the REST Controller

With Yii's REST framework, we'll create an endpoint for our API and organize controllers for each type of resource.

The resources are essentially our application's data models. These extend yii\base\Model

The yii\rest\UrlRule class provides ready-made routing mapping our data model to API CRUD endpoints:

Programming Yii2 REST API UrlRule Documentation of CRUD API endpointsProgramming Yii2 REST API UrlRule Documentation of CRUD API endpointsProgramming Yii2 REST API UrlRule Documentation of CRUD API endpoints

Creating a Tree to Act as an API Endpoint

In the Yii2 Advanced template, there is a front-end and back-end tree, and this is extensible. To separate out the API features, we'll create a third tree to act purely as an API endpoint. 

Yii developer Alex Makarov provides this helpful guide to creating additional trees which I followed to create my third tree:

1
$ cp -R backend api
2
$ cp -R environments/dev/backend/ environments/dev/api
3
$ cp -R environments/prod/backend/ environments/prod/api

Then, I used the Atom editor to do a global find and replace of "backend" with "api" in the new api tree.

And I added the api alias to /common/config/bootstrap.php:

1
<?php
2
Yii::setAlias('@common', dirname(__DIR__));
3
Yii::setAlias('@frontend', dirname(dirname(__DIR__)) . '/frontend');
4
Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend');
5
Yii::setAlias('@api', dirname(dirname(__DIR__)) . '/api');
6
Yii::setAlias('@console', dirname(dirname(__DIR__)) . '/console');
7
Yii::setAlias('@twixxr', dirname(dirname(__DIR__)) . '/twixxr');

Configuring the URL Routing for Incoming Requests

In /api/config/main.php, we need to add the request[] to parse setup JSON parsing and the UrlRule to associate methods for the models and their endpoints:

1
return [
2
    'id' => 'app-api',
3
    'basePath' => dirname(__DIR__),
4
    'controllerNamespace' => 'api\controllers',
5
    'bootstrap' => ['log'],
6
    'modules' => [],
7
    'components' => [
8
      'request' => [
9
        'parsers' => [
10
          'application/json' => 'yii\web\JsonParser',
11
        ],
12
      ],
13
      'urlManager' => [
14
        'enablePrettyUrl' => true,
15
        'enableStrictParsing' => true,
16
        'showScriptName' => false,
17
        'rules' => [
18
          ['class' => 'yii\rest\UrlRule', 'controller' => 'item'],
19
          ['class' => 'yii\rest\UrlRule', 'controller' => 'user'],
20
        ],
21
      ],

That's basically all it takes to enable some rich API functionality for these models.

Examples With cURL

Let's begin making requests.

Requesting OPTIONS

Show me available API methods:

1
curl -i -H "Accept: application/json" 
2
    -X OPTIONS "http://localhost:8888/api/items"

Here is the response (GET, POST, HEAD, OPTIONS):

1
HTTP/1.1 200 OK
2
Date: Tue, 25 Oct 2016 20:23:10 GMT
3
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
4
X-Powered-By: PHP/7.0.10
5
Allow: GET, POST, HEAD, OPTIONS
6
Content-Length: 0
7
Content-Type: application/json; charset=UTF-8

GET Requests

Request: How much data is there?

1
curl -i --head  "http://localhost:8888/api/items"

Answer: 576 records across 29 pages...

1
HTTP/1.1 200 OK
2
Date: Tue, 25 Oct 2016 23:17:37 GMT
3
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
4
X-Powered-By: PHP/7.0.10
5
X-Pagination-Total-Count: 576
6
X-Pagination-Page-Count: 29
7
X-Pagination-Current-Page: 1
8
X-Pagination-Per-Page: 20
9
Link: <http://localhost:8888/api/items?page=1>; rel=self, <http://localhost:8888/api/items?page=2>; rel=next, <http://localhost:8888/api/items?page=29>; rel=last
10
Content-Type: application/json; charset=UTF-8

Request: Show me record 15:

1
curl -i  "http://localhost:8888/api/items/15"

Response:

1
HTTP/1.1 200 OK
2
Date: Tue, 25 Oct 2016 23:19:27 GMT
3
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
4
X-Powered-By: PHP/7.0.10
5
Content-Length: 203
6
Content-Type: application/json; charset=UTF-8
7
8
{"id":15,"title":"Jeff Reifman","path":"jeffreifman",
9
"detail":"","status":0,"posted_by":1,"image_url":"",
10
"favorites":0,"stat_1":0,"stat_2":0,"stat_3":0,"created_at":1477277956,"updated_at":1477277956}

Request: Show me all the data on page 3:

1
curl -i -H "Accept:application/json"
2
    "http://localhost:8888/api/items?page=3"

Response:

1
HTTP/1.1 200 OK
2
Date: Tue, 25 Oct 2016 23:30:21 GMT
3
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
4
X-Powered-By: PHP/7.0.10
5
X-Pagination-Total-Count: 575
6
X-Pagination-Page-Count: 29
7
X-Pagination-Current-Page: 3
8
X-Pagination-Per-Page: 20
9
Link: <http://localhost:8888/api/items?page=3>; rel=self, <http://localhost:8888/api/items?page=1>; rel=first, <http://localhost:8888/api/items?page=2>; rel=prev, <http://localhost:8888/api/items?page=4>; rel=next, <http://localhost:8888/api/items?page=29>; rel=last
10
Content-Length: 3999
11
Content-Type: application/json; charset=UTF-8
12
13
[{"id":43,"title":"_jannalynn","path":"_jannalynn",
14
"detail":"","status":0,"posted_by":1,"image_url":"",
15
"favorites":0,"stat_1":0,"stat_2":0,"stat_3":0,
16
...
17
...
18
...
19
{"id":99,"title":"alibrown","path":"alibrown","detail":"",
20
"status":0,"posted_by":1,"image_url":"","favorites":0,
21
"stat_1":0,"stat_2":0,"stat_3":0,"created_at":1477277956,
22
"updated_at":1477277956}]

DELETE Requests

Here's an example of a GET request followed by a DELETE request and then a follow-up failed GET attempt:

1
$ curl -i -H "Accept: application/json" "http://localhost:8888/api/items/8"
2
HTTP/1.1 200 OK
3
Date: Tue, 25 Oct 2016 23:32:17 GMT
4
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
5
X-Powered-By: PHP/7.0.10
6
Content-Length: 186
7
Content-Type: application/json; charset=UTF-8
8
9
{"id":8,"title":"aaker","path":"aaker","detail":"","status":0,"posted_by":1,"image_url":"","favorites":0,"stat_1":0,"stat_2":0,"stat_3":0,"created_at":1477277956,"updated_at":1477277956}
10
11
$ curl -i -H "Accept: application/json" -X DELETE "http://localhost:8888/api/items/8"
12
HTTP/1.1 204 No Content
13
Date: Tue, 25 Oct 2016 23:32:26 GMT
14
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
15
X-Powered-By: PHP/7.0.10
16
Content-Length: 0
17
Content-Type: application/json; charset=UTF-8
18
19
$ curl -i -H "Accept: application/json" "http://localhost:8888/api/items/8"
20
HTTP/1.1 404 Not Found
21
Date: Tue, 25 Oct 2016 23:32:28 GMT
22
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
23
X-Powered-By: PHP/7.0.10
24
Content-Length: 115
25
Content-Type: application/json; charset=UTF-8
26
27
{"name":"Not Found","message":"Object not found: 8","code":0,"status":404,"type":"yii\\web\\NotFoundHttpException"}

Requests for a deleted record return a 404 error.

POST Requests

For my post requests, I switched over to the Chrome Postman app:

Programming With Yii2  Chrome Directory Postman Extension Landing PageProgramming With Yii2  Chrome Directory Postman Extension Landing PageProgramming With Yii2  Chrome Directory Postman Extension Landing Page

Signing up for Postman was easy:

Programming With Yii2 Postmand Sign UpProgramming With Yii2 Postmand Sign UpProgramming With Yii2 Postmand Sign Up

And then I was able to submit requests to my localhost API in a more friendly GUI:

Programming With Yii2 POST Request Shown in Postman UXProgramming With Yii2 POST Request Shown in Postman UXProgramming With Yii2 POST Request Shown in Postman UX

Then, I retrieved the data via curl, record 577:

1
$ curl -i -H "Accept: application/json" "http://localhost:8888/api/items/577"
2
HTTP/1.1 200 OK
3
Date: Tue, 25 Oct 2016 23:40:44 GMT
4
Server: Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.12 PHP/7.0.10 mod_ssl/2.2.31 OpenSSL/1.0.2h DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
5
X-Powered-By: PHP/7.0.10
6
Content-Length: 219
7
Content-Type: application/json; charset=UTF-8
8
9
{"id":577,"title":"Jeff Reifman","path":"reifman",
10
"detail":"A programmer on earth.","status":0,
11
"posted_by":1,"image_url":"","favorites":0,
12
"stat_1":0,"stat_2":0,"stat_3":0,"created_at":1477436477,
13
"updated_at":1477436477}

Postman proved essential to round out my testing as command line curl was not easy to configure for POST submissions.

Looking Ahead

In addition to its REST quickstart overview, the Yii 2.0 documentation provides detail on an array of other aspects of API creation:

I hope to have the chance to explore more of these in future episodes. But certainly, one of the next steps is to create an API for Meeting Planner in the startup series.

In closing, building a basic REST API with the Yii MVC framework is quite simple. The Yii team has done a great job standardizing functionality for a very important requirement, REST APIs. I hope you've enjoyed learning about them.

If you have any questions or suggestions, please post them in the comments. If you'd like to keep up on my future Envato Tuts+ tutorials and other series, please visit my instructor page or follow @reifman. Definitely check out my startup series and Meeting Planner.

Related Links

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.