Book Image

Building RESTful Web Services with PHP 7

By : Waheed ud din
Book Image

Building RESTful Web Services with PHP 7

By: Waheed ud din

Overview of this book

REST is the most wide spread and effective standard to develop APIs for internet services. With the way PHP and its eco-system has modernized the way code is written by simplifying various operations, it is useful to develop RESTful APIs with PHP 7 and modern tools. This book explains in detail how to create your own RESTful API in PHP 7 that can be consumed by other users in your organization. Starting with a brief introduction to the fundamentals of REST architecture and the new features in PHP 7, you will learn to implement basic RESTful API endpoints using vanilla PHP. The book explains how to identify flaws in security and design and teach you how to tackle them. You will learn about composer, Lumen framework and how to make your RESTful API cleaner, secure and efficient. The book emphasizes on automated tests, teaches about different testing types and give a brief introduction to microservices which is the natural way forward. After reading this book, you will have a clear understanding of the REST architecture and you can build a web service from scratch.
Table of Contents (16 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Case study - RESTful web service endpoints for a blog


To understand RESTful web services, let's consider the case study of a blog where we will discuss resources/entities in a blog. We will start to define the requirements and URLs for the blog's resources and then define responses that we should have against those requests. So these endpoints and response definitions will help us understand how RESTful web services endpoint should look like and what the response should be. In the later chapters, we will talk more about the implementation of these endpoints, so these definitions will act as an API document for the next chapters. However, for simplicity, we will keep it minimal for now and later add more attributes to it.

Note

Although based on HATEOAS, a RESTful web service should return links to the next endpoints and there are conventions that tell us about other endpoints but the API document is still important. API consumers (client-side developers) and API providers (server-side developers) should agree on it so that both can work in parallel without waiting for the other. However, in the real world, we don't have to write API document for basic CRUD operations.

In a typical blog, the most common resources are posts and comments. There are others as well but for now, we will discuss these two resources for the sake of understanding RESTful web services. Note that we are not considering authentication related stuff but will look into that in the later chapters.

Note

If client-side and server-side teams are of the same organization, working on a single app, then it is a good idea to get such document created by the client-side team as the server-side team is just the serving client side.

Blog post

Here, we are listing the requirement a blog post its endpoints. For those endpoints, we will write a request and a response.

Requirements

A blog post can be created, modified, visited, and deleted. There also be a way to list all the blog posts. So we are going to list the blog post's endpoints.

Endpoints

Here are the endpoints blog post:

Creating blog post
  • Request: POST /posts HTTP/1.1
  • Body parameters:

Content: This is an awesome post Title: Awesome Post

  • Response:
{id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" }
  • Response code: 201 Created

Here POST is the method, /posts is the URL (path after the server name) and HTTP 1.1 is the protocol. We will keep using the same way of mentioning requests in examples as well. So, the first part of the request is the HTTP method, the second one is the URL and the third part is the protocol.

The response code tells the client that the resource has been created successfully. If a request parameter is missed by mistake, the response code should be 400, which represents a bad request.

Reading blog post
  • Request: GET /posts/1 HTTP/1.1
  • Response:
{id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" }
  • Response code: 200 OK

Note, if a blog post an ID provided (in the current case, 1) does not exist, it should return 404, which means resource Not Found.

Updating blog post
  • Request: PATCH /posts/1?title=Modified%20Post HTTP/1.1
  • Response:
{id:1, title:"Modified Post", content:"This is an awesome post", link:"posts/1" }
  • Response code: 200 OK

Note, if a blog post with the ID provided (that is 1 in this case) does not exist, it should return the response code 404 that means resource not found.

Also, we have used PATCH instead of PUT for the since PATCH is used to modify all or some attributes of a record while PUT is used for modifying a whole record just like replacing an old record with a new one. So, if we use PUT and pass only one attribute, the other attributes will become empty. In the case of PATCH, it will only update the attribute that is passed and other attributes untouched.

Delete blog post
  • Request: DELETE /posts/1 HTTP/1.1
  • Response:
{success:"True", deleted_id:1 }
  • Response code: 200 OK

Note

Note, if a blog post with an ID provided (in the current case, 1) does not exist, it should return 404, which means resource Not Found.

Listing all blog posts
  • Request: GET /posts HTTP/1.1
  • Response:
{
data:[
  {
   id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" 
  },  
  {
   id:2, title:"Amazing one", content:"This is an amazing post", link: "/posts/2"
  }
 ],
total_count: 2,
limit:10,
pagination: {
    first_page: "/posts?page=1",
    last_page: "/posts?page=1",
    page=1
 }
}
  • Response code:200 OK

Here, data is an array of objects as there are multiple records returning. Other than total_count, there is a pagination object as well, and right now it shows the first last pages because total_count for records is only 2. So, there is no next or previous page. Otherwise, we should also have to show the next and previous in pagination.

As you can see, there are links in the pagination as well as the post's links in post objects. We have included these links in response to being compliant with the HATEOAS constraint, which stated that if the client knows about an entry point, it should be enough to discover relevant endpoints.

Here, we explored the requirements of blog posts and defined the request and response of their endpoints. In the next entity/resource, we are going to define endpoints and responses in comments.

Blog post comments

Here, we are listing the requirements of a post comment and its endpoints. For those endpoints, we will write Request and Response.

Requirements

There will be one, more than one, or comments on posts. So, a comment can be created on a blog post. A blog post's comments can be listed. A comment can be read, modified, or deleted.

Let's define endpoints for these requirements.

Endpoints

Here are the endpoints the post's comments:

Creating the post's comment
  • Request:POST /posts/1/comments HTTP/1.1
  • Body parameters: comment: An Awesome Post
  • Response:
{id:1, post_id:1, comment:"An Awesome Post", link: "/comments/1"}
  • Response code:201 Created

Here in the case of a comment, a comment is against a certain blog post. So, the request URL includes post_id as well.

Reading a comment
  • Request:GET /posts/1/comment/1 HTTP/1.1 or GET /comment/1 HTTP/1.1

The second one seems more reasonable as in that one only to have a comment's ID without worrying about the post ID of that comment. And since a comment's ID is unique, we don't need to have the post's ID to get the comment. So, we will proceed with the second URL that is GET /comment/1 HTTP/1.1.

  • Response:
{id:1, post_id:1, comment:"An Awesome Post", link: "/comments/1"}
  • Response code:200 OK

Since any comment can only exist against some post, the response includes post_id as well.

Updating a comment
  • Request:PATCH /comment/1?comment="Modified%20Awesome%20Comment' HTTP/1.1
  • Response:
{id:1, post_id:1, comment:"Modified Awesome Comment", link: "/comments/1"}
  • Response code:200 OK

Here, we used PATCH as we want to update a single attribute of a that is a comment. Also, you can see %20 passed in a new comment. So, %20 is just a replacement for a space as a URL cannot contain spaces. So with URL encoding, spaces should always be replaced by %20.

Deleting a post comment
  • Request:DELETE /comments/1 HTTP/1.1
  • Response:
{success:"True", deleted_id:1 }
  • Response code:200 OK

Note, if a post comment with an ID provided (in the current case, 1) does exist, it should return 404Not Found.

Listing all comments for a particular post
  • Request:GET /posts/1/comments HTTP/1.1
  • Response:
{
data:[
  {
   id:1, comment:"Awesome Post", post_id:1, link: "/comments/1" 
  }, {
   id:2, comment:"Another post comment", post_id:1, link: "/comments/2"
  } 
 ], 
 total_count: 2,
 limit: 10,
 pagination: {
 first_page: "/posts/1/comments?page=1",
 last_page: "/posts/1/comments?page=1",
 page=1 
 } 
}
  • Response Code:200 OK

As you can see, a post's comments listing is very to a blog post's listing. And it has total_count and pagination in the same way. It shows the first and last page right now because total_count for the records is only 2. So there is no next or previous page. Otherwise, we should also have to show the next and previous links in pagination.

Normally, you don't see pagination with comments on blogs, but it is better to keep it consistent to have pagination in the listing. Because there can be lot of comments for a post, we should apply some limit to it, so we will need pagination.