Materi API

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 93

REST API Development

PART I

Designing REST API Using


Swagger (Open API)
Open API (Swagger)

What Is Swagger?
Swagger is an open-source framework for designing and describing
APIs. Swagger’s journey started in 2010 when it was developed by Reverb
Technologies (formerly called Wordnik) to solve the need for keeping the API
design and documentation in sync.
Fast forward 6 years and Swagger has become the de-facto standard
for designing and describing RESTful APIs used by millions of developers and
organizations for developing their APIs, be it internal or client facing.

A simple Swagger definition looks like this:

swagger: '2.0'
info:
version: 1.0.0
title: Simple example API
description: An API to illustrate Swagger
paths:
/list:
get:
description: Returns a list of stuff
responses:
200:
description: Successful response

The syntax above will make sense once we finish this walkthrough.

Why Swagger?
There are a lot of factors that contributed to Swagger’s meteoric adoption for
building RESTful APIs. We have listed the most important ones as to why use
Swagger for designing APIs. Design and document APIs simultaneously, thus
keeping the blueprint and documentation in sync.

Both human and machine readable, with an interactive API


documentation automatically generated to see the API in action.

Large comprehensive tooling ecosystem around the framework, which


lets you go beyond just design, from SDK generation to testing and debugging.

Strong open source community supporting and spearheading the framework.

We recommend using SwaggerHub’s built-in editor and validator to


quickly write and visualize the Swagger definition described in the tutorial.
SwaggerHub is free with loads of features to get you started quickly, so give it
a whirl!
Create an API
We will be designing an API for a record label. Let’s assume that the
record label has a database of artists with the following information:

Artist name
Artist genre
Number of albums published under the label
Artist username
The API will let consumers obtain the list of artists stored in the database and
add a new artist to the database.

The Swagger definition of an API can be divided into 3 different sections –

The Meta Information


The Path Items:
Parameters
Responses
Reusable components:
Definitions
Parameters
Responses
Meta information
The meta information section is where you can give information about your
overall API. Information like what the API does, what the base URL of the API
is and what web-based protocol it follows can be defined in this section.

All Swagger defined APIs start with the swagger: 2.0 declaration. The info
object is then specified with additional, required metadata like the version and
title. The description is optional.

The base URL is what any application or end user will call in order to
consume the API. In this case, it is https://example.io/v1, which is defined by
the schemes, host and basePath objects respectively.

We can also add a basic authentication which only lets authorized users
consume the API. For more advanced security, see here.

Let’s start with a simple meta information section:

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []

paths: {}
Path Items
The path items are the endpoints of your API under which you can specify
HTTP verbs for manipulating the resources in the desired manner. These
endpoints are relative to the base URL (which in our case is
http://example.io/v1). In this example, we have listed the /artists endpoint
under which is the GET method.

Thus, a client would use GET http://example.io/v1/artists to obtain a list of


artists.

swagger: '2.0'
info:
version: 0.0.0
title: Simple API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
# ----- Added lines -----------------------------------
-----
paths:
/artists:
get:
description: Returns a list of artists
# ---- /Added lines ----------------------------------

Responses
The GET method, under the artists endpoint, lets the consumer of the
API obtain the details of a list of artists from the http://example.io/v1 database.

Every response would need at least one HTTP status code to describe
the kind of responses a consumer is likely to expect. The description gives
details on what the responses of the API would be. In our sample code, we
have specified 200, which is a successful client request, while 400 is an
unsuccessful request. You can find more information about HTTP status
codes here. A successful response will return the artist name, genre,
username and albums recorded. An unsuccessful request is described under
the 400 HTTP code, with a corresponding error message detailing why the
response is invalid.

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https

host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
# ----- Added lines -----------------------------
-----------
responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ---- /Added lines -----------------------------
See here for more information on responses.

Parameters
RESTful parameters specify the variable part of the resource a user works
with. If you want to get some advanced information on parameters, read here.

Query parameters
Query parameters are the most common type of parameters. They appear at
the end of a URL following a question mark. Query parameters are optional
and non unique, so they can be specified multiple times in the URL. It is a
non-hierarchical component of the URL.

In our example, it would make sense to let the client limit the information
required instead of returning the entire list of artists from the database, which
would lead to unnecessary load on the server. The client could describe the
page number (offset) and the amount of information on the page (limit), for
example:

GET http://example.com/v1/artists?limit=20&offset=3
These variables are defined under the parameters object in the Swagger
definition. Thus, the definition would now look as follows –

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
# ----- Added lines -----------------------------
-----------
parameters:
- name: limit
in: query
type: integer
description: Limits the number of items on a
page
- name: offset
in: query
type: integer
description: Specifies the page number of the
artists to be displayed
# ---- /Added lines -----------------------------
-----------
responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string

Body parameters
Body parameters are stated in the body of the request. A key principle of such
a parameter is that resources are sent in the message body. Body parameters
are great for POST and PUT requests. It is not advisable to use these
parameters in GET and DELETE actions.

For this API, let’s add the ability for a user to post an artist to our database.
This would be under the /artists resource. Note the inclusion of a parameter
which is specified in the body of the request from the in:body description.

The API would now look as follows:

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
parameters:
- name: limit
in: query
type: integer
description: Limits the number of items on a
page
- name: offset
in: query
type: integer
description: Specifies the page number of the
artists to be displayed

responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ----- Added lines -------------------------------
---------
post:
description: Lets a user post a new artist
parameters:
- name: artist
in: body
description: creates a new artist in our
database
schema:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
responses:
200:
description: Successfully created a new artist
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ---- /Added lines -------------------------------

Path parameters
The path parameters can be used to isolate a specific component of
the data that the client is working with, for example,
http://example.io/v1/{userrole}. Path parameters are part of the hierarchical
component of the URL, and are thus stacked sequentially.

Let’s create a new endpoint which returns a specific artist’s information


based on the username provided. The path parameter here would be the
username of the artist whose info we need. Path parameters (username in
this case) have to be mandatorily described in the parameters object under
the method.

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
parameters:
- name: limit
in: query
type: integer
description: Limits the number of items on a
page
- name: offset
in: query
type: integer
description: Specifies the page number of the
artists to be displayed

responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
post:
description: Lets a user post a new artist
parameters:
- name: artist
in: body
description: creates a new artist in our
database
schema:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
responses:
200:
description: Successfully created a new artist
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ----- Added lines ---------------------------------
-------
/artists/{username}:
get:
description: Obtain information about an artist
from his or her unique username
parameters:
- name: username
in: path
type: string
required: true
responses:
200:
description: Successfully returned an artist
schema:
type: object
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ---- /Added lines ------------------------------

Here, we have specified the username as a path parameter. The thing


to note is that path parameters have to have a true property set to the
required parameter, for the spec to be valid.

If you followed through till here, then congratulation! You have just
designed a simple API for a record label!
Reusable components
What we have just described are just 2 endpoints and 3 actions. This
was 83 lines of API definition, and the spec will only get longer as the API
gets bigger. One of the things you may notice in the spec we have so far is
that we have the same Artist schema (artist name, genre, username and
albums published) that gets repeated in various 200 and 400 responses.
Bigger APIs would involve rewriting and reusing a lot of the same specs, so it
would be a tedious task writing a more complex API.

The Swagger Specification has a solution – defining reusable


components. These components can be reused across multiple endpoints,
parameters and responses in the same API.

There are 3 different types of reusable components of an API definition:

Definitions
Responses
Parameters
Path Items can also be reused with the help of applications like SwaggerHub,
which store your reusable components to be referenced across multiple APIs.

Definitions
The global definitions section can contain various data models consumed and
returned by the API. Here is how we can use definitions to store the schema
for an HTTP 200 OK response:

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
parameters:
- name: limit
in: query
type: integer
description: Limits the number of items on a
page
- name: offset
in: query
type: integer
description: Specifies the page number of the
artists to be displayed

responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
# ----- Added line ----------------------
------------------
$ref: '#/definitions/Artist'
# ---- /Added line ----------------------
------------------
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
post:
description: Lets a user post a new artist
parameters:
- name: artist
in: body
description: creates a new artist in our
database
schema:
# ----- Added line ------------------------
----------------
$ref: '#/definitions/Artist'
# ---- /Added line ------------------------
----------------
responses:
200:
description: Successfully created a new artist
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
/artists/{username}:
get:
description: Obtain information about an artist
from his or her unique username
parameters:
- name: username
in: path
type: string
required: true
responses:
200:
description: Successfully returned an artist
schema:
type: object
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
400:
description: Invalid request
schema:
type: object
properties:
message:
type: string
# ----- Added lines -----------------------------------
definitions:
Artist:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
# ---- /Added lines -----------------------------------

The spec is not only shorter, but anytime a new endpoint with the same
schema is needed, the designer does not need to spend time writing the piece.
See here for more information on Definitions.

To jump to an object definition, simply click the $ref link.

Parameters and responses


We can also define a separate section under the reusable components
for storing parameters and responses that could be referenced across
multiple endpoints in the same API.

In the API definitiion below, we have, under the reusable parameters, the
PageLimit and PageNumber parameters, which define the query parameters
we used under the /artists endpoint. They are referenced under the /artists
endpoint.

We also have a 400Error reusable response defined, which specifies the 400
response we used under all the endpoints, which are then appropriately
referenced.

swagger: '2.0'
info:
version: 1.0.0
title: Simple Artist API
description: A simple API to understand the Swagger
Specification in greater detail
schemes:
- https
host: example.io
basePath: /v1
securityDefinitions:
UserSecurity:
type: basic
security:
- UserSecurity: []
paths:
/artists:
get:
description: Returns a list of artists
parameters:
- $ref: '#/parameters/PageLimit'
- $ref: '#/parameters/PageNumber'
responses:
200:
description: Successfully returned a list of
artists
schema:
type: array
items:
$ref: '#/definitions/Artist'
400:
# ----- Added line --------------------------
--------------
$ref: '#/responses/400Error'
# ---- /Added line --------------------------
--------------
post:
description: Lets a user post a new artist
parameters:
- name: artist
in: body
description: creates a new artist in our
database
schema:
$ref: '#/definitions/Artist'
responses:
200:
description: Successfully created a new artist
400:
# ----- Added line --------------------------
--------------
$ref: '#/responses/400Error'
# ---- /Added line --------------------------
--------------
/artists/{username}:
get:
description: Obtain information about an artist
from his or her unique username
parameters:
- name: username
in: path
type: string
required: true
responses:
200:
description: Successfully returned an artist
schema:
type: object
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
400:
# ----- Added line --------------------------
--------------
$ref: '#/responses/400Error'
# ---- /Added line --------------------------
--------------
definitions:
Artist:
type: object
required:
- username
properties:
artist_name:
type: string
artist_genre:
type: string
albums_recorded:
type: integer
username:
type: string
# ----- Added lines -----------------------------------
-----
parameters:
PageLimit:
name: limit
in: query
type: integer
description: Limits the number of items on a page
PageNumber:
name: offset
in: query
type: integer
description: Specifies the page number of the artists
to be displayed
responses:
400Error:
description: Invalid request
schema:
type: object
properties:
message:
type: string

Summary
We have successfully designed a RESTful API which exposes the artists
present in the database of a record label! We have only covered the basics of
Swagger, as the specification can be anything you want it to be (mostly). If
you want to become a Swagger expert, you can refer to the official
specification and to the syntax guide, or try out our certification courses!
PART II

Implement REST API in PHP


1.0 Project Overview
1.1 What is REST API?
1.2 Why do we need REST API?
1.3 Where REST API is used?
1.4 REST API in our tutorials

2.0 File structure

3.0 Setup the database


3.1 Create categories table
3.2 Dump data for categories table
3.3 Products table
3.4 Dump data for products table
3.5 Connect to database

4.0 Read products


4.1 Product object
4.2 Create a le to read products
4.3 Connect to database and products table
4.4 Read products from the database
4.5 Add Product "read()" method
4.6 Tell the user no products found
4.7 Output

5.0 Create Product


5.1 Create create.php le
5.2 Product create() method
5.3 Output

6.0 Read One Product


6.1 Create read_one.php le
6.2 Product readOne() method
6.3 Output
7.0 Update product
7.1 Create “update.php” le
7.2 Product update() method
7.3 Output

8.0 Delete Product


8.1 Create “delete.php” le
8.2 Product delete() method
8.3 Output

9.0 Search Products


9.1 Create "search.php" le
9.2 Create "search()" method
9.3 Output

10.0 Paginate Products


10.1 Create "read_paging.php" le
10.2 Create "core.php" le
10.3 Create "readPaging()" method
10.4 Create "count()" method
10.5 Get "paging" array
10.6 Output

11.0 Read Categories


11.1 Category object
11.2 Create "read.php" le
11.3 Category "read()" method
11.4 Output

12.0 Download Source Codes


13.0 What's Next?
14.0 Related Tutorials
15.0 Notes
Before we start, we want to let you know that your feedback is
important to us!

If you have a positive feedback about our work, please let us know. If
there's a section in this tutorial that is confusing or hard to
understand, we consider it as a problem. Please let us know as well.

Write your positive feedback or detailed description of the problem in


the comments section below. Before you write a comment, please
read this guide [https://www.codeofaninja.com/how-to-write-a-great-
comment-on-codeofaninja-com] and our code of conduct
[https://www.codeofaninja.com/code-of-conduct] . Thank you!

1.0 PROJECT OVERVIEW


1.1 What is REST API?
To de ne "REST API", we have to know what is "REST" and what is "API"
rst. I'll do my best to explain it in simple terms because REST has a lot of
concepts inside of it that could mean a lot of things
[https://stackover ow.com/questions/4663927/what-is-rest-slightly-
confused] .

REST stands for "REpresentational State Transfer". It is a concept or


architecture for managing information over the internet. REST concepts
are referred to as resources. A representation of a resource must be
stateless. It is usually represented by JSON
[https://stackover ow.com/questions/383692/what-is-json-and-why-
would-i-use-it] . This post is worth reading: How I Explained REST to My
Wife? [http://www.looah.com/source/view/2284]

API stands for "Application Programming Interface". It is a set of rules


that allows one piece of software application to talk to another. Those
In many applications, REST API is a need because this is the lightest way
to create, read, update or delete information between di erent
applications over the internet or HTTP protocol. This information is
presented to the user in an instant especially if you use JavaScript to
render the data on a webpage.

1.3 Where REST API is used?

REST API can be used by any application that can connect to the
internet. If data from an application can be created, read, updated or
deleted using another application, it usually means a REST API is used.

1.4 REST API in our tutorials


A REST API is needed for our AJAX CRUD Tutorial
[https://www.codeofaninja.com/2015/06/php-crud-with-ajax-and-
oop.html] . But don't mind it for now. We will do it one step at a time. You
don't need to learn all of it as well. Just choose what you need to learn.

Also, please note that this PHP REST API is not yet in its nal form. We
still have some work to do with .htaccess for better URLs and more.

But one thing is for sure, this source code is good enough and works for
our JavaScript tutorials.

2.0 FILE STRUCTURE


At the end of this tutorial, we will have the following folders and les.
├─ api/
├─── con g/
├────── core.php - le used for core con guration
├────── database.php - le used for connecting to the database.
├─── objects/
├────── product.php - contains properties and methods for
"product" database queries.
├────── category.php - contains properties and methods for
"category" database queries.
├─── product/
├────── create.php - a le that will accept posted product data to
be saved to the database.
├────── delete.php - a le that will accept a product ID to delete a
database record.
├────── read.php - a le that will output JSON data based on
"products" database records.
├────── read_paging.php - a le that will output "products" JSON
data with pagination.
├────── read_one.php - a le that will accept product ID to read a
record from the database.
├────── update.php - a le that will accept a product ID to update
a database record.
├────── search.php - a le that will accept keywords parameter to
search "products" database.
├─── category/
├────── read.php - a le that will output JSON data based on
"categories" database records.
├─── shared/
├────── utilities.php - a le that will return pagination array.

3.0 SETUP THE DATABASE

Using PhpMyAdmin, create a new api_db database. Yes, api_db is


the database name. After that, run the following SQL queries to create
new tables with sample data.
3.1 Create categories table

CREATE TABLE IF NOT EXISTS `categories` (


  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `description` text NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=19 ;

3.2 Dump data for categories table

INSERT INTO `categories` (`id`, `name`, `description`, `c


(1, 'Fashion', 'Category for anything related to fashion.
(2, 'Electronics', 'Gadgets, drones and more.', '2014-06-
(3, 'Motors', 'Motor sports and more', '2014-06-01 00:35:
(5, 'Movies', 'Movie products.', '0000-00-00 00:00:00', '
(6, 'Books', 'Kindle books, audio books and more.', '0000
(13, 'Sports', 'Drop into new winter gear.', '2016-01-09

3.3 Products table

CREATE TABLE IF NOT EXISTS `products` (


  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `description` text NOT NULL,
  `price` decimal(10,0) NOT NULL,
  `category_id` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=65

3.4 Dump data for products table

INSERT INTO `products` (`id`, `name`, `description`, `pri


(1, 'LG P880 4X HD', 'My first awesome phone!', '336', 3,
(2, 'Google Nexus 4', 'The most awesome phone of 2013!',
(3, 'Samsung Galaxy S4', 'How about no?', '600', 3, '2014
(6, 'Bench Shirt', 'The best shirt!', '29', 1, '2014-06-0
(7, 'Lenovo Laptop', 'My business partner.', '399', 2, '2
(8, 'Samsung Galaxy Tab 10.1', 'Good tablet.', '259', 2,
(9, 'Spalding Watch', 'My sports watch.', '199', 1, '2014
(10, 'Sony Smart Watch', 'The coolest smart watch!', '300
(11, 'Huawei Y300', 'For testing purposes.', '100', 2, '2
(12, 'Abercrombie Lake Arnold Shirt', 'Perfect as gift!',
(13, 'Abercrombie Allen Brook Shirt', 'Cool red shirt!',
(26, 'Another product', 'Awesome product!', '555', 2, '20
(28, 'Wallet', 'You can absolutely use this one!', '799',
(31, 'Amanda Waller Shirt', 'New awesome shirt!', '333',
(42, 'Nike Shoes for Men', 'Nike Shoes', '12999', 3, '201
(48, 'Bristol Shoes', 'Awesome shoes.', '999', 5, '2016-0
(60, 'Rolex Watch', 'Luxury watch.', '25000', 1, '2016-01

3.5 Connect to database

The code below shows the database credentials and a method to get a
database connection using PDO. If you're not yet familiar with PDO,
please learn from our PHP OOP CRUD Tutorial
[https://www.codeofaninja.com/2014/06/php-object-oriented-crud-
example-oop.html] rst.

Create api folder. Open api folder.

Create config folder. Open config folder.

Create a database.php le. Place the following code inside it.

<?php
class Database{
  
    // specify your own database credentials
    private $host = "localhost";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "";
    public $conn;
  
    // get the database connection
    public function getConnection(){
  
        $this->conn = null;
  
        try{
            $this->conn = new PDO("mysql:host=" . $this->
            $this->conn->exec("set names utf8");
        }catch(PDOException $exception){
            echo "Connection error: " . $exception->getMe
        }
  
        return $this->conn;
    }
}
?>

4.0 READ PRODUCTS


4.1 Product object

The code below shows a class named Product with several of its
properties. It also shows a constructor method that will accept the
database connection.

We will use this class to read data from the database.

Open api folder.

Create objects folder.

Open objects folder.

Create product.php le.

Place the following code inside it.

<?php
class Product{
  
    // database connection and table name
    private $conn;
    private $table_name = "products";
  
    // object properties
    public $id;
    public $name;
    public $description;
    public $price;
    public $category_id;
    public $category_name;
    public $created;
  
    // constructor with $db as database connection
    public function __construct($db){
        $this->conn = $db;
    }
}
?>

4.2 Create le to read products


The code below shows headers about who can read this le and which
type of content it will return.

In this case, our read.php the le can be read by anyone (asterisk *


means all) and will return a data in JSON format [https://www.json.org/] .

Open api folder.

Create product folder.

Open product folder.

Create read.php le.

Place the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
  
// database connection will be here

4.3 Connect to database and products table

In the code below, we included the database.php and product.php


les. These are the les we created earlier.

We need to use the getConnection() method of the Database class


to get a database connection. We pass this connection to the Product
class.
Replace of // database connection will be here comment of
read.php le with the following code.

// include database and object files


include_once '../config/database.php';
include_once '../objects/product.php';
  
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
  
// initialize object
$product = new Product($db);
  
// read products will be here

4.4 Read products from the database

In the code below, we used the read() method of Product class to


read data from the database. Through the $num variable, we check if
there are records found.

If there are records found, we loop through it using the while loop, add
each record to the $products_arr array, set a 200 OK response code
and show it to the user in JSON format.

Replace of // read products will be here comment of


read.php le with the following code.

// query products
$stmt = $product->read();
$num = $stmt->rowCount();
  
// check if more than 0 record found
if($num>0){
  
    // products array
    $products_arr=array();
    $products_arr["records"]=array();
  
    // retrieve our table contents
    // fetch() is faster than fetchAll()
    // http://stackoverflow.com/questions/2770630/pdofetc
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // extract row
        // this will make $row['name'] to
        // just $name only
        extract($row);
  
        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($descript
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );
  
        array_push($products_arr["records"], $product_ite
    }
  
    // set response code - 200 OK
    http_response_code(200);
  
    // show products data in json format
    echo json_encode($products_arr);
}
  
// no products found will be here

4.5 Add product "read()" method

We used the read() method in the previous section but it does not
exist yet in the Product class. We need to add this read() method.
The code below shows the query to get records from the database.

Open objects folder.

Open product.php le.

Place the following code inside the Product class.

To make sure you added it correctly, place the code before the last
closing curly brace.

// read products
function read(){
  
    // select all query
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            ORDER BY
                p.created DESC";
  
    // prepare query statement
    $stmt = $this->conn->prepare($query);
  
    // execute query
    $stmt->execute();
  
    return $stmt;
}

4.6 Tell the user no products found

If the $num variable has a value of zero or negative, it means there are
no records returned from the database. We need to tell the user about
this.

On the code below, we set the response code to 404 - Not found
and a message that says No products found.

Replace of // no products found will be here comment of


read.php le with the following code.

else{
  
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user no products found
    echo json_encode(
        array("message" => "No products found.")
    );
}
4.7 Output
You need to use POSTMAN [https://www.getpostman.com/] to test our
API. Download your version of POSTMAN here
[https://www.getpostman.com/apps] .

Launch POSTMAN. Enter the following as the request URL.

http://localhost/api/product/read.php [http://localhost/a

Click the blue "Send" button.

Output if there are product data.

[https://i1.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-products-200.jpg?ssl=1]

Output if there are no product data.


[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-products-404.jpg?ssl=1]

5.0 CREATE PRODUCT


5.1 Create create.php le
Open product folder.

Create a new create.php le.

Open that le and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Acces
  
// get database connection
include_once '../config/database.php';
  
// instantiate product object
include_once '../objects/product.php';
  
$database = new Database();
$db = $database->getConnection();
  
$product = new Product($db);
  
// get posted data
$data = json_decode(file_get_contents("php://input"));
  
// make sure data is not empty
if(
    !empty($data->name) &&
    !empty($data->price) &&
    !empty($data->description) &&
    !empty($data->category_id)
){
  
    // set product property values
    $product->name = $data->name;
    $product->price = $data->price;
    $product->description = $data->description;
    $product->category_id = $data->category_id;
    $product->created = date('Y-m-d H:i:s');
  
    // create the product
    if($product->create()){
  
        // set response code - 201 created
        http_response_code(201);
  
        // tell the user
        echo json_encode(array("message" => "Product was
    }
  
    // if unable to create the product, tell the user
    else{
  
        // set response code - 503 service unavailable
        http_response_code(503);
  
        // tell the user
        echo json_encode(array("message" => "Unable to cr
    }
}
  
// tell the user data is incomplete
else{
  
    // set response code - 400 bad request
    http_response_code(400);
  
    // tell the user
    echo json_encode(array("message" => "Unable to create
}
?>

5.2 Product create() method


Open objects folder.
Open product.php le.

The previous section will not work without the following code inside
the Product (objects/product.php) class.

// create product
function create(){
  
    // query to insert record
    $query = "INSERT INTO
                " . $this->table_name . "
            SET
                name=:name, price=:price, description=:de
  
    // prepare query
    $stmt = $this->conn->prepare($query);
  
    // sanitize
    $this->name=htmlspecialchars(strip_tags($this->name))
    $this->price=htmlspecialchars(strip_tags($this->price
    $this->description=htmlspecialchars(strip_tags($this-
    $this->category_id=htmlspecialchars(strip_tags($this-
    $this->created=htmlspecialchars(strip_tags($this->cre
  
    // bind values
    $stmt->bindParam(":name", $this->name);
    $stmt->bindParam(":price", $this->price);
    $stmt->bindParam(":description", $this->description);
    $stmt->bindParam(":category_id", $this->category_id);
    $stmt->bindParam(":created", $this->created);
  
    // execute query
    if($stmt->execute()){
        return true;
    }
  
    return false;
      
}

5.3 Output

To test for the successful creation of a product, open POSTMAN. Enter


the following as the request URL
http://localhost/api/product/create.php [http://localhost

Click the "Body" tab.

Click "raw".

Enter this JSON value:

{
    "name" : "Amazing Pillow 2.0",
    "price" : "199",
    "description" : "The best pillow for amazing programm
    "category_id" : 2,
    "created" : "2018-06-01 00:35:07"
}

It should look like this:

[https://i1.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/create-product-201.jpg?ssl=1]

If the system is unable to create the product, it should look like this:
[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/create-product-503.jpg?ssl=1]

If the sent data is incomplete, for example, it is missing the price data,
the output should look like this:

6.0 READ ONE PRODUCT


6.1 Create read_one.php le
Open product folder.

Create a w read_one.php le.

Open that le and put the following code.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Credentials: true");
header('Content-Type: application/json');
  
// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';
  
// get database connection
$database = new Database();
$db = $database->getConnection();
  
// prepare product object
$product = new Product($db);
  
// set ID property of record to read
$product->id = isset($_GET['id']) ? $_GET['id'] : die();
  
// read the details of product to be edited
$product->readOne();
  
if($product->name!=null){
    // create array
    $product_arr = array(
        "id" =>  $product->id,
        "name" => $product->name,
        "description" => $product->description,
        "price" => $product->price,
        "category_id" => $product->category_id,
        "category_name" => $product->category_name
  
    );
  
    // set response code - 200 OK
    http_response_code(200);
  
    // make it json format
    echo json_encode($product_arr);
}
  
else{
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user product does not exist
    echo json_encode(array("message" => "Product does not
}
?>

6.2 Product readOne() method


Open objects folder.
Open product.php le.

The previous section will not work without the following code inside
the Product class.

// used when filling up the update product form


function readOne(){
  
    // query to read single record
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            WHERE
                p.id = ?
            LIMIT
                0,1";
  
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
  
    // bind id of product to be updated
    $stmt->bindParam(1, $this->id);
  
    // execute query
    $stmt->execute();
  
    // get retrieved row
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
  
    // set values to object properties
    $this->name = $row['name'];
    $this->price = $row['price'];
    $this->description = $row['description'];
    $this->category_id = $row['category_id'];
    $this->category_name = $row['category_name'];
}

6.3 Output
First, we will test for a product that exists. Open POSTMAN. Enter the
following as the request URL. Click the blue "Send" button.
http://localhost/api/product/read_one.php?id=60 [http://l

[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-one-200.jpg?ssl=1]

Next, we will test for a product that does not exist. Enter the following
as the request URL. Click the blue "Send" button.

http://localhost/api/product/read_one.php?id=999 [http://

[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-one-404.jpg?ssl=1]

7.0 UPDATE PRODUCT


7.1 Create "update.php" le
Open product folder.

Create a new update.php le.


Open that le and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Acces
  
// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';
  
// get database connection
$database = new Database();
$db = $database->getConnection();
  
// prepare product object
$product = new Product($db);
  
// get id of product to be edited
$data = json_decode(file_get_contents("php://input"));
  
// set ID property of product to be edited
$product->id = $data->id;
  
// set product property values
$product->name = $data->name;
$product->price = $data->price;
$product->description = $data->description;
$product->category_id = $data->category_id;
  
// update the product
if($product->update()){
  
    // set response code - 200 ok
    http_response_code(200);
  
    // tell the user
    echo json_encode(array("message" => "Product was upda
}
  
// if unable to update the product, tell the user
else{
  
    // set response code - 503 service unavailable
    http_response_code(503);
  
    // tell the user
    echo json_encode(array("message" => "Unable to update
}
?>

7.2 Product update() method


Open objects folder.

Open product.php le.

The previous section will not work without the following code inside
the Product class.

// update the product


function update(){
  
    // update query
    $query = "UPDATE
                " . $this->table_name . "
            SET
                name = :name,
                price = :price,
                description = :description,
                category_id = :category_id
            WHERE
                id = :id";
  
    // prepare query statement
    $stmt = $this->conn->prepare($query);
  
    // sanitize
    $this->name=htmlspecialchars(strip_tags($this->name))
    $this->price=htmlspecialchars(strip_tags($this->price
    $this->description=htmlspecialchars(strip_tags($this-
    $this->category_id=htmlspecialchars(strip_tags($this-
    $this->id=htmlspecialchars(strip_tags($this->id));
  
    // bind new values
    $stmt->bindParam(':name', $this->name);
    $stmt->bindParam(':price', $this->price);
    $stmt->bindParam(':description', $this->description);
    $stmt->bindParam(':category_id', $this->category_id);
    $stmt->bindParam(':id', $this->id);
  
    // execute the query
    if($stmt->execute()){
        return true;
    }
  
    return false;
}

7.3 Output
Open POSTMAN. Enter the following as the request URL.

http://localhost/api/product/update.php [http://localhost

Click the "Body" tab.

Click "raw".

Enter the following JSON value.

Make sure the ID exists in your database.

Click the blue "Send" button.

{
    "id" : "106",
    "name" : "Amazing Pillow 3.0",
    "price" : "255",
    "description" : "The best pillow for amazing programm
    "category_id" : 2,
    "created" : "2018-08-01 00:35:07"
}

The product ID 106, is just an example. You need to specify a product ID


that exists in your database.

If you specify an ID that does not exist in the database, it might still say
that the product was updated. It does not update anything on the
database but the query was executed successfully without any syntax
errors.
To prevent this, you need an extra validation where you check if an ID
exists in the database. This feature is not yet part of our tutorial.

If updating a product is successful, it should look like this:

[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/update-product-200.jpg?ssl=1]

If the system fails to update the product, the output will look like this:
[https://i1.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/update-product-503.jpg?ssl=1]

8.0 DELETE PRODUCT


8.1 Create "delete.php" le
Open product folder.

Create new delete.php le.

Open that le and put the following code inside it.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Acces
  
// include database and object file
include_once '../config/database.php';
include_once '../objects/product.php';
  
// get database connection
$database = new Database();
$db = $database->getConnection();
  
// prepare product object
$product = new Product($db);
  
// get product id
$data = json_decode(file_get_contents("php://input"));
  
// set product id to be deleted
$product->id = $data->id;
  
// delete the product
if($product->delete()){
  
    // set response code - 200 ok
    http_response_code(200);
  
    // tell the user
    echo json_encode(array("message" => "Product was dele
}
  
// if unable to delete the product
else{
  
    // set response code - 503 service unavailable
    http_response_code(503);
  
    // tell the user
    echo json_encode(array("message" => "Unable to delete
}
?>

8.2 Product delete() method


Open objects folder.

Open product.php le.

The previous section will not work without the following code inside
the Product class.

// delete the product


function delete(){
  
    // delete query
    $query = "DELETE FROM " . $this->table_name . " WHERE
  
    // prepare query
    $stmt = $this->conn->prepare($query);
  
    // sanitize
    $this->id=htmlspecialchars(strip_tags($this->id));
  
    // bind id of record to delete
    $stmt->bindParam(1, $this->id);
  
    // execute query
    if($stmt->execute()){
        return true;
    }
  
    return false;
}

8.3 Output
Open POSTMAN. Enter the following as the request URL.

http://localhost/api/product/delete.php [http://localhost

Click the "Body" tab.

Click "raw".

Enter the following JSON value.

Make sure the ID exists in your database.

Click the blue "Send" button.

{
    "id" : "106"
}

If a product was successfully deleted, it should look like this:


[https://i2.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/delete-200.jpg?ssl=1]

If the system fails to delete the product, the output will look like this:

[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/delete-503-1.jpg?ssl=1]

9.0 SEARCH PRODUCTS


9.1 Create "search.php" le
Open product folder.

Create a search.php le.

Open that le and place the following code.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
  
// include database and object files
include_once '../config/core.php';
include_once '../config/database.php';
include_once '../objects/product.php';
  
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
  
// initialize object
$product = new Product($db);
  
// get keywords
$keywords=isset($_GET["s"]) ? $_GET["s"] : "";
  
// query products
$stmt = $product->search($keywords);
$num = $stmt->rowCount();
  
// check if more than 0 record found
if($num>0){
  
    // products array
    $products_arr=array();
    $products_arr["records"]=array();
  
    // retrieve our table contents
    // fetch() is faster than fetchAll()
    // http://stackoverflow.com/questions/2770630/pdofetc
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // extract row
        // this will make $row['name'] to
        // just $name only
        extract($row);
  
        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($descript
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );
  
        array_push($products_arr["records"], $product_ite
    }
  
    // set response code - 200 OK
    http_response_code(200);
  
    // show products data
    echo json_encode($products_arr);
}
  
else{
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user no products found
    echo json_encode(
        array("message" => "No products found.")
    );
}
?>

9.2 Create search() method


Open objects folder.

Open product.php le.

Add the following search() method.

// search products
function search($keywords){
  
    // select all query
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            WHERE
                p.name LIKE ? OR p.description LIKE ? OR
            ORDER BY
                p.created DESC";
  
    // prepare query statement
    $stmt = $this->conn->prepare($query);
  
    // sanitize
    $keywords=htmlspecialchars(strip_tags($keywords));
    $keywords = "%{$keywords}%";
  
    // bind
    $stmt->bindParam(1, $keywords);
    $stmt->bindParam(2, $keywords);
    $stmt->bindParam(3, $keywords);
  
    // execute query
    $stmt->execute();
  
    return $stmt;
}

9.3 Output

Open POSTMAN. Enter the following as the request URL.

http://localhost/api/product/search.php?s=shirt [http://l

Click the blue "Send" button.

If there was a product found, it should look like this:


[https://i2.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/search-200.jpg?ssl=1]

If there are no products found, the output will look like this:

[https://i2.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/search-404.jpg?ssl=1]

10.0 PAGINATE PRODUCTS


10.1 Create "read_paging.php" le
Open product folder.

Create read_paging.php le.


<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
  
// include database and object files
include_once '../config/core.php';
include_once '../shared/utilities.php';
include_once '../config/database.php';
include_once '../objects/product.php';
  
// utilities
$utilities = new Utilities();
  
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
  
// initialize object
$product = new Product($db);
  
// query products
$stmt = $product->readPaging($from_record_num, $records_p
$num = $stmt->rowCount();
  
// check if more than 0 record found
if($num>0){
  
    // products array
    $products_arr=array();
    $products_arr["records"]=array();
    $products_arr["paging"]=array();
  
    // retrieve our table contents
    // fetch() is faster than fetchAll()
    // http://stackoverflow.com/questions/2770630/pdofetc
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // extract row
        // this will make $row['name'] to
        // just $name only
        extract($row);
  
        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($descript
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );
  
        array_push($products_arr["records"], $product_ite
    }
  
  
    // include paging
    $total_rows=$product->count();
    $page_url="{$home_url}product/read_paging.php?";
    $paging=$utilities->getPaging($page, $total_rows, $re
    $products_arr["paging"]=$paging;
  
    // set response code - 200 OK
    http_response_code(200);
  
    // make it json format
    echo json_encode($products_arr);
}
  
else{
  
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user products does not exist
    echo json_encode(
        array("message" => "No products found.")
    );
}
?>

10.2 Create "core.php" le

This le holds our core con guration like the home URL and pagination
variables.

Open the config folder.

Create core.php le.

Open core.php le.

Place the following code.

<?php
// show error reporting
ini_set('display_errors', 1);
error_reporting(E_ALL);
  
// home page url
$home_url="http://localhost/api/ [http://localhost/api/]
  
// page given in URL parameter, default page is one
$page = isset($_GET['page']) ? $_GET['page'] : 1;
  
// set number of records per page
$records_per_page = 5;
  
// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records
?>

10.3 Create "readPaging()" method


Open objects folder.

Open product.php le.

Add the following method inside the product class.

This method will return a list of records limited to what we set in


$records_per_page of the previous section.

// read products with pagination


public function readPaging($from_record_num, $records_per
  
    // select query
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            ORDER BY p.created DESC
            LIMIT ?, ?";
  
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
  
    // bind variable values
    $stmt->bindParam(1, $from_record_num, PDO::PARAM_INT)
    $stmt->bindParam(2, $records_per_page, PDO::PARAM_INT
  
    // execute query
    $stmt->execute();
  
    // return values from database
    return $stmt;
}

10.4 Create "count()" method

Still in the product class ( product.php le), add the following method.
The total rows are needed to build the pagination array. It is included in
the 'paging' computation.

// used for paging products


public function count(){
    $query = "SELECT COUNT(*) as total_rows FROM " . $thi
  
    $stmt = $this->conn->prepare( $query );
    $stmt->execute();
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
  
    return $row['total_rows'];
}

10.5 Get "paging" array


Create shared folder.

Open shared folder.

Create utilities.php le.

Open utilities.php le and place the following code.

<?php
class Utilities{
  
    public function getPaging($page, $total_rows, $record
  
        // paging array
        $paging_arr=array();
  
        // button for first page
        $paging_arr["first"] = $page>1 ? "{$page_url}page
  
        // count all products in the database to calculat
        $total_pages = ceil($total_rows / $records_per_pa
  
        // range of links to show
        $range = 2;
  
        // display links to 'range of pages' around 'curr
        $initial_num = $page - $range;
        $condition_limit_num = ($page + $range)  + 1;
  
        $paging_arr['pages']=array();
        $page_count=0;
          
        for($x=$initial_num; $x<$condition_limit_num; $x+
            // be sure '$x is greater than 0' AND 'less t
            if(($x > 0) && ($x <= $total_pages)){
                $paging_arr['pages'][$page_count]["page"]
                $paging_arr['pages'][$page_count]["url"]=
                $paging_arr['pages'][$page_count]["curren
  
                $page_count++;
            }
        }
  
        // button for last page
        $paging_arr["last"] = $page<$total_pages ? "{$pag
  
        // json format
        return $paging_arr;
    }
  
}
?>

10.6 Output
Open POSTMAN. Enter the following as the request URL.

http://localhost/api/product/read_paging.php [http://loca

Click the blue "Send" button.


If there are products found, scroll down to see the paging node. It
should look like this:

[https://i0.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-paging-200.jpg?ssl=1]

If there are no products found, the output will look like this:

[https://i1.wp.com/www.codeofaninja.com/wp-
content/uploads/2017/02/read-paging-404.jpg?ssl=1]

11.0 READ CATEGORIES


11.1 Create "category.php" le
Open objects folder.

Create new category.php le.

Place the following code inside the category.php le.

<?php
class Category{
  
    // database connection and table name
    private $conn;
    private $table_name = "categories";
  
    // object properties
    public $id;
    public $name;
    public $description;
    public $created;
  
    public function __construct($db){
        $this->conn = $db;
    }
  
    // used by select drop-down list
    public function readAll(){
        //select all data
        $query = "SELECT
                    id, name, description
                FROM
                    " . $this->table_name . "
                ORDER BY
                    name";
  
        $stmt = $this->conn->prepare( $query );
        $stmt->execute();
  
        return $stmt;
    }
}
?>

11.2 Create "read.php" le


Create new category folder.

Open that folder and create new read.php le inside it.


Open read.php le and place the following code.

<?php
// required header
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
  
// include database and object files
include_once '../config/database.php';
include_once '../objects/category.php';
  
// instantiate database and category object
$database = new Database();
$db = $database->getConnection();
  
// initialize object
$category = new Category($db);
  
// query categorys
$stmt = $category->read();
$num = $stmt->rowCount();
  
// check if more than 0 record found
if($num>0){
  
    // products array
    $categories_arr=array();
    $categories_arr["records"]=array();
  
    // retrieve our table contents
    // fetch() is faster than fetchAll()
    // http://stackoverflow.com/questions/2770630/pdofetc
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // extract row
        // this will make $row['name'] to
        // just $name only
        extract($row);
  
        $category_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($descript
        );
  
        array_push($categories_arr["records"], $category_
    }
  
    // set response code - 200 OK
    http_response_code(200);
  
    // show categories data in json format
    echo json_encode($categories_arr);
}
  
else{
  
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user no categories found
    echo json_encode(
        array("message" => "No categories found.")
    );
}
?>

11.3 Add Category "read()" method


Open objects folder.

Open category.php le.

The previous section's code will not work without the following code
inside the category.php le.

Add the following method inside the Category class.

// used by select drop-down list


public function read(){
  
    //select all data
    $query = "SELECT
                id, name, description
            FROM
                " . $this->table_name . "
            ORDER BY
                name";
  
    $stmt = $this->conn->prepare( $query );
    $stmt->execute();
  
    return $stmt;
}
PART III

Managing REST API Using


WSO2 API Manager
Quick Start Guide - API Proxy

This section is a step-by-step guide to create, publish, and invoke an API


using the WSO2 API Manager (WSO2 API-M) Publisher and Developer
Portal.

Before you begin...

1. Install Oracle Java SE Development Kit (JDK)


[http://java.sun.com/javase/downloads/index.jsp] version 11 or 1.8
and set the JAVA_HOME environment variable. For more information
on setting the JAVA_HOME environment variable for different operating
systems, see Setup and Install
[https://apim.docs.wso2.com/en/4.0.0/install-and-
setup/install/installing-the-product/installing-api-m-runtime/].

2. Download version 4.0.0 of WSO2 API-M [https://wso2.com/api-


management/].

3. Start WSO2 API-M by navigating to the <API-M_HOME>/bin directory


using the command-line and execute the following command api-
manager.bat --run (for Windows) or sh api-manager.sh (for
Linux).

What you'll build

1. Creating and publishing an API via the Publisher Portal of WSO2 API-
M.
2. Subscribing to the API via the Developer Portal of WSO2 API-M and
generating keys.

3. Invoking the API with the generated keys.

Let's get started...

Step 1 - Create and publish an API

Follow the instructions below to create and publish an API via the
Publisher Portal of WSO2 API-M.

1. Navigate to the Publisher Portal https://localhost:9443/publisher


[https://localhost:9443/publisher] and sign in with admin/admin as
the credentials (The below home screen will be displayed).

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/api-
publisher-home.png]

2. Create an API.

Let's use a mock REST service to create a REST API from scratch.

A mock service with a JSON response {"hello": "world"} is


provided by default when you use the service URL as
( http://run.mocky.io/v2/5185415ba171ea3a00704eed ) that appears
in the https://designer.mocky.io/ [https://designer.mocky.io/] mock
service. Note that we are using the HTTP protocol instead of HTTPS.

Optionally, to test this service, copy the service URL


http://run.mocky.io/v2/5185415ba171ea3a00704eed
[http://run.mocky.io/v2/5185415ba171ea3a00704eed] and
navigate to it on a new browser. You should see the following
JSON message.

{"hello": "world"}

3. Select REST API from the home screen and then click Start From
Scratch.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/desi
gn-new-rest-api.png]

4. Enter the API details.


Name HelloWorld

Context /hello

Version 1.0.0

Endpoint http://run.mocky.io/v2/5185415ba171ea3a00704eed

 Note

Use the HTTP protocol because to use HTTPS you need to


import the https://designer.mocky.io/
[https://designer.mocky.io/] certificate into WSO2 API-M.

5. Click Create & Publish.

This will publish your first API on the Developer Portal as well as
deploy it on the API Gateway. You now have an OAuth2.0 secured
REST API that is ready to be consumed.

[]
Step 2 - Subscribe to the API

Follow the instructions below to subscribe to the API and generate the
keys via the Developer Portal of WSO2 API-M.

1. Navigate to the Developer Portal.

https://localhost:9443/devportal [https://localhost:9443/devportal]

The published HelloWorld API is listed in the Developer Portal as


shown below.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/dev-
portal-landing-page.png]

2. Click Sign-In and enter admin/admin as your credentials to sign in to


the Developer Portal.

3. Click on the API thumbnail to view the overview of the API.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/api-
overview.png]

4. Register an OAuth2.0 application.

a. Click Subscriptions on the left menu bar of the screen.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
subscriptions-menu.png]
b. Click SUBSCRIPTION & KEY GENERATION WIZARD in the above
screen.

This wizard walks you through 5 steps that will register an


OAuth2.0 application which you will use to consume the
HelloWorld API.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard.png]

c. Create the OAuth2.0 application.

Enter the application name, and click Next without changing any
of the other default values.

Application Name Greetings

Per Token Quota 50PerMin

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard-1.png]

d. Subscribe the application to the API.

This subscribes the Greetings application to the HelloWorld


API on the selected Business Plan. Click Next without changing
any of the default values.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard-2.png]

e. Generate the credentials for the Greetings OAuth2.0 application.

The Grant Types define the various protocols, which will be


allowed by the system, from which your application will be
allowed to request tokens. Click Next.
[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard-3.png]

f. Generate a test access token for the Greetings application to


access the HelloWorld API.

This step allows you to specify the permissions (scopes) for the
token. Click Next without changing any of the default values.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard-4.png]

g. Click the copy icon, as shown below, to copy the generated test
access token to the clipboard.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
key-gen-wizard-5.png]

h. Click Finish.

Voila!!! You can now test the HelloWorld API with the OAuth2.0 token that
you just generated.

[]

Step 3 - Invoke the API

Follow the instructions below to invoke the previously created API with the
generated keys.

1. Click Try Out on the left menu bar.

The resources of the API will be listed.

2. Paste the access token that you previously copied in the Access
Token field.
[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/test-
api.png]

3. If this is the first time you are using the API test console from your
browser, open a new tab and navigate to the https://localhost:8243/
[https://localhost:8243/] URL.

This will prompt your browser to accept the certificate used by the
API Gateway. This is required because by default the API Gateway
uses a self-signed certificate that is not trusted by web browsers.

 Note

This certificate that is used by the API Gateway is replaced when deploying the
system in production.

4. Click on the GET resource of the API to expand the resource and Click
Try It Out.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/expa
nded-get-resource.png]

5. Then click Execute.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/try-
api.png]

You should see the {"hello" : "world"} response from the API.

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/try-
it-success.png]

Congratulations! You have successfully created your first API, subscribed


to it through an OAuth2.0 application, obtained an access token for
testing, and invoked your API with the access token.
Automate API development and deployment

Let's look at how you can use WSO2 API Controller (apictl) which is the
command-line tool to move APIs, API Products, and Applications across
WSO2 API-M environments and to perform CI/CD operations. (For more
information, see Getting Started with WSO2 API Controller (apictl)
[https://apim.docs.wso2.com/en/4.0.0/install-and-setup/setup/api-
controller/getting-started-with-wso2-api-controller/])

Before you begin...

1. Download the apictl version 4.0.0 (or the latest of the 4.x family)
based your operating system from https://wso2.com/api-
management/tooling/ [https://wso2.com/api-management/tooling/]
from under the Dev-Ops Tooling section.

2. Extract the ZIP to a preferred location.

This location will be referred to as the apictl directory.

3. To use the command line tool to navigate to the apictl directory.

 Warn

If you have previously used an apictl old version, backup and remove the
/home/<user>/.wso2apictl directory and reconfigure the environments using the
commands as explained below.

Execute the following command to view the available operations.

./apictl --help

4. Point the apictl to the instance of WSO2 API-M in which you want to
deploy APIs.

Execute the following command to add an environment.


 Note

It is assumed that WSO2 API-M is run locally (localhost) using the default ports.

./apictl add env dev \


--apim https://localhost:9443

For more information on adding environments using different flag


combinations, see Add an environment
[https://apim.docs.wso2.com/en/4.0.0/install-and-setup/setup/api-
controller/getting-started-with-wso2-api-controller/#add-an-
environment].

On successfully executing this command, you should see the


following message.

Default token endpoint


'https://localhost:9443/oauth2/token' is added as the
token endpoint
Successfully added environment 'dev'

Step 1 - Create an API

1. Initialize an API project by providing a name for the project.

Let's use the command below to create an API named PetstoreAPI .


This creates a folder named PetstoreAPI in your current directory.

./apictl init PetstoreAPI --oas


https://apim.docs.wso2.com/en/4.0.0/assets/attachments/ge
t_started/petstore.json

On successfully executing this command, you should see the


following message.

Initializing a new WSO2 API Manager project in <your-


directory-path>/PetstoreAPI
Project initialized
Open README file to learn more

 Note

Use the following command to view the various options related to initializing a
project.

./apictl init --help

2. Update the api.yaml file.

a. Open and explore the PetstoreAPI folder with an IDE (e.g.,


VSCode).

b. Open the api.yaml file. (Alternatively, You can use a text editor
to open this file as well.)

c. Change the values of the following attributes as shown below


and save the file.

lifeCycleStatus: PUBLISHED

production_endpoints:
url: https://petstore.swagger.io/v2
sandbox_endpoints:
url: https://petstore.swagger.io/v2

 Note

Make sure that there are no spaces in-between the context value in the
api.yaml file.

Changing the default lifecycle status of the API from CREATED to


PUBLISHED , will deploy the API directly to the Developer Portal and API
Gateway, when you push this API to WSO2 API-M in the following step.

If you want to push this API to the Publisher Portal only, the status
should be CREATED .
Step 2 - Publish the API

1. Push the API to WSO2 API-M.

Navigate back to the apictl directory and execute the following


command:

 Info

If you are working with a specific environment for the first time, you will be
prompted to enter your account credentials on WSO2 API-M. You can use the
default admin credentials as admin/admin .

./apictl import api --file ./PetstoreAPI --environment


dev

You should now see your API deployed successfully on WSO2 API-M.

2. Browse the Publisher and the Developer Portals to view the API
details.

https://localhost:9443/publisher
[https://localhost:9443/publisher]

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
qsg-publisher.png]

https://localhost:9443/devportal
[https://localhost:9443/devportal]

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/
qsg-devportal.png]

Step 3 - Invoke the API

1. Generate an access token using apictl.


Navigate back to the apictl directory and execute the following
command:

./apictl get keys -e dev -n SwaggerPetstore -v 1.0.0 -r


admin

You will get an access token that can be used to invoke your API. (For
more information on generating keys using apictl, see Get keys for an
API/API Product [https://apim.docs.wso2.com/en/4.0.0/install-and-
setup/setup/api-controller/ci-cd-with-wso2-api-management/#g-get-
keys-for-an-apiapi-product].)

2. Invoke the API

Execute the below cURL command to invoke the resource GET /pet
of your API. (Make sure to enter the access token that you recieved
earlier as the Bearer in thee request)

curl -H "Authorization: Bearer


eyJ0eXAiOiJKV1QiLCJhbGciOiJSUz....RWrACAUNSFBpxz1lRLqFlDi
aVJAg" https://localhost:8243/SwaggerPetstore/1.0.0/pet/5
-k

You will receive the below response.

{"id":5,"category":
{"id":5,"name":"jimmy"},"name":"jimmy","photoUrls":
[],"tags":[{"id":5,"name":"jimmy"}],"status":"pending"}

 Note

Alternatively, you can consume the API as explained in the following sections
using the WSO2 API-M Developer Portal.

Subscribe to the API via the Developer Portal and generate keys [#subscribe]

Invoke the API with the generated keys [#invoke]

[https://apim.docs.wso2.com/en/4.0.0/assets/img/get_started/qsg-
petstore-response.jpg]
Scenario 1 - Create REST API from an
OpenAPI Definition

This tutorial is part of a series that guides you through all the capabilities
of API Manager. This involves creating a REST API from an OpenAPI
Definition. For more details on the scenario and general prerequisites,
please see the scenario overview page
[https://apim.docs.wso2.com/en/4.0.0/tutorials/scenarios/scenario-
overview].

Time to Complete : 10 mins

User story
Coltrain is one of the railway companies that is partnered up with GOGO
Train to provide better service to their customers. Coltrain already has
some internally managed APIs deployed in-house and these are managed
by their internal development team. One of the APIs is a train schedule
retrieval API, which is intended for the public community to get the
Coltrain schedules. Currently, this API is exposed to the public and the
Coltrain development team faces challenges in maintaining and handling
the high load for the API.

By exposing this API through WSO2 API Manager, Coltrain expects to get
the full benefits of an API Management solution such as API lifecycle
management, security, rate limiting, etc. and decouple the maintenance
overhead from the internal teams.

WSO2 API manager provides capability to import OAS definitions and


create the API using that.

Step 1: Testing the backend

Let's first test the backend. You could do following curl command and you
will get a response with schedule items.

curl "http://localhost:8082/train-operations/v1/schedules"

You will receive the following response.


[{"entryId":"1","startTime":"14:50","endTime":"19:59","from":
"London","to":"Glasgow","trainType":"Standard"},
{"entryId":"2","startTime":"14:30","endTime":"19:20","from":"
London","to":"Edinburgh","trainType":"1st class"},
{"entryId":"3","startTime":"11:10","endTime":"12:59","from":"
London","to":"Cardiff","trainType":"Standard"},
{"entryId":"4","startTime":"08:30","endTime":"10:50","from":"
London","to":"Manchester","trainType":"1st class"}]

This indicates that the backend is working fine. Next, let’s expose this API
through WSO2 API Manager.

Step 2: Expose the API through WSO2 API


Manager

1. Log on to https://localhost:9443/publisher/apis using a Coltrain


publisher user. Use user as apiprovider@coltrain.com and
password as user123 .

2. Select Import Open API option under REST API section


3. Select OpenAPI File/Archive radio button and import the coltrain-
public-openapi.yaml definition from /resources location.

4. Add the context (say /coltrain) and create the API. Keep the endpoint
as it is. You could select the checkbox in front of the endpoint to
check the status of the backend URL.

Since this API is intended to be accessed by public users, the Coltrain API
providers want to remove any authentication for this resource. This way
anyone can access the service without any credentials.
Step 3: Remove authentication to the resource

To implement this, follow the steps below.

1. Go to Develop → API Configuration → Resources tab.


2. Expand a resource.

3. Under the Operation Governance section, turn off the radio button for
Security.

4. Save the API.

Before Publishing the API, Coltrain developers want to test this API. WSO2
API Manager provides a Test console to test the API while it is in the
development stage.

Step 4: Deploy the API in the Gateway

Before starting to test the API, you need to deploy the API in the Gateway.
For that, go to Deploy → Deployment section and select Deploy . This will
deploy the API in the Gateway but the API will not be visible to the outside
world.

Step 5: Test the API


Now we are ready to test the API. Go to Test → Try Out . This provides an
API console in the Publisher portal to test the API.

Expand the /schedules resource and invoke the API. You won’t need to
click Generate Key since we have removed the security for this resource.
You will have to generate one if you want to test the /schedules/{id}
resource.
Now testing is done from the publisher end.

Step 6: Publish the API

The API needs to be published in-order to access it from the Developer


portal. For that,

1. Go to Portal Configurations → Subscriptions and select one from


Business Plans. Select a business plan (say “Unlimited”) and save.

2. Go to Lifecycle section and select Publish.

Now the API is published. To view this API go to


https://localhost:9443/devportal/ Dev portal and select Coltrain tenant
domain. This will redirect you to the Coltrain developer portal.
Select the ColTrainScheduleCommunityAPI and select the Try-Out button
from the left menu. This will open up an in-built API console for this API.
You could now try out the API by clicking the resources.

What's next
Try out the next scenario in the series, Access Control
[https://apim.docs.wso2.com/en/4.0.0/tutorials/scenarios/scenario2-
access-control].
Expose a SOAP service as a REST
API

WSO2 API Manager supports the management of an existing SOAP and


WSDL based services exposing as REST APIs. The organizations who
have SOAP/ WSDL based services, can easily bridge their existing
services to REST without the cost of a major migration. WSO2 API
Manager supports two kinds of services as one for performing a "pass
through" of the SOAP message to the backend and other one is generating
a RESTful api from the backend SOAP service
[https://apim.docs.wso2.com/en/4.0.0/design/create-api/generate-rest-
api-from-soap-backend/].

This tutorial will explain the steps to design, publish and invoke a SOAP
service as a RESTful API using Pass Through

Step 1 - Design a SOAP service as a REST API

1. Sign in to the API Publisher and click CREATE API.


[https://apim.docs.wso2.com/en/4.0.0/assets/img/learn/create-
soap-api.jpg]

2. Select Pass Through option and thereafter, select one of the following
options:

WSDL URL - If you select this option, you need to provide an


endpoint URL.

WSDL Archive/File - If you select this option, click Browse and


upload either an individual WSDL file or a WSDL archive, which is
a WSDL project that has multiple WSDLs.

 Note

When uploading a WSDL archive, all the dependent wsdls/xsds that are referred in
the parent WSDL file should reside inside the WSDL archive itself. If not, the
validation will fail at the point of API creation.

This example uses the WSDL


http://ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl from
CDYNE as the endpoint here, but you can use any SOAP backend of
your choice.

3. Click NEXT button to proceed to the next phase and Provide the
information in the table below and click CREATE button.

Field Sample value

Name PhoneVerification

Context /phoneverify

Version 1.0

Endpoint http://ws.cdyne.com/phoneverify/phoneverify.asmx
4. The created API appears in the publisher as follows.

5. API definiton of the Created schema has been displayed at API


Definiton tab.
[https://apim.docs.wso2.com/en/4.0.0/assets/img/learn/api-
definition-of-soap-api-created-by-passthrough-mode.jpg]

 Note

If you wish to add scopes to the resources that were created, navigate to
Resources and expand the resources. Thereafter, creating new scopes and specify
them under operation scope. If you specify a scope, you need to use the same
scope when generating access tokens for the subscribed application to invoke the
API. For more information on working with the scopes, see OAuthscopes
[https://apim.docs.wso2.com/en/4.0.0/design/api-security/oauth2/oauth2-
scopes/fine-grained-access-control-with-oauth-scopes/]
 Note

Note that when creating this API, the default option of Rate limiting level , was
selected to API Level. For more information on setting advanced throttling
policies, see Enforce Throttling and Resource Access Policies
[https://apim.docs.wso2.com/en/4.0.0/design/rate-limiting/setting-throttling-
limits/].

. Navigate to Life Cycle and Click Publish button. You have now
published SOAP API at the Developer portal.

Step 2 - Invoke a SOAP service as a REST API.

1. Log in to the developer portal, navigate to Subscriptions tab and


subscribe to the api using (e.g.,DefaultApplication)

2. Click the MANAGE APP button when prompted View Credentials.

3. Click GENERATED ACCESS TOKEN and then it propmt popupto create


an application access token.
4. Click GENERATE.

The generated JSON Web Token (JWT) appears in the popup. Make
sure to copy it.

Let's invoke the API.

5. Navigate to TryOut tab and paste the token at Access token input
field.
. Expand the POST method and click Try it out . Enter the following,
and click Execute to invoke the API.

SOAP
<soap:Envelope
Request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<CheckPhoneNumber
xmlns="http://ws.cdyne.com/PhoneVerify/query">
<PhoneNumber>18006785432</PhoneNumber>
<LicenseKey>18006785432</LicenseKey>
</CheckPhoneNumber>
</soap:Body>
</soap:Envelope>

SOAP
Action http://ws.cdyne.com/PhoneVerify/query/CheckPhoneNumber
7. Note the API response that appears on the console.

 Note

You can also invoke this API using a third-party tool such as SOAP UI. For more
information on how to invoke an API using a SOAP client, see Invoke an API using
a SOAP Client [https://apim.docs.wso2.com/en/4.0.0/consume/invoke-
apis/invoke-apis-using-tools/invoke-an-api-using-a-soap-client/] .

You might also like