zendframework2 restful

65
Building a REST API with Zend Framework 2 January 17, 2014

Upload: tomli

Post on 13-Jul-2015

129 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: zendframework2 restful

Building  a  REST  API    with  Zend  Framework  2  

January  17,  2014  

Page 2: zendframework2 restful

What  we’re  gonna  talk  about…  Overview  of  REST  

•   What  is  the  purpose  of  an  API  

•   Different  API  Techniques  

•   The  REST  Methodology  

•   Components  of  REST  

•   Good  PracIces  

•   Not  so  Good  PracIces  

•   AuthenIcaIon  and  OAuth  

Building  Your  API  

•   SeLng  up  Your  Routes  

•   SeLng  up  Your  Controllers    

•   Handling  Headers  

•   Handling  JSON  

   

Page 3: zendframework2 restful

What  is  an  API?  An  ApplicaIon  Program  Interface  (API)  is  a  set  of  rouInes,  

protocols,  and  tools  for  building  soRware  applicaIons.    A  

good  API  makes  it  easier  to  develop  a  program  by  providing  

all  the  building  blocks,  which  a  developer  can  then  use  to  

put  the  blocks  together.1    Web  APIs  allow  the  transmission  

of  data  and  acIons  across  different  web  applicaIons  and  

sites  securely  and  through  a  language    

agnosIc  interface.  

1  definiIon  by  

Page 4: zendframework2 restful

Code  and  Personal  Data  are  Secure  

Page 5: zendframework2 restful

Different  Types  of  APIs  There  are  several  different  methods  for  building  an  API,  

however  the  three  leading  methods  are  using  

RepresentaIonal  State  Transfer  (REST),    Remote  Procedure  

Calls  (RPC),  and    Simple  Object  Access    Protocol  (SOAP).  

Page 6: zendframework2 restful

An  Overview  of  RPC  Remote  Procedure  Calls  work  in  some  instances,  but  as  an  

API  causes  problems  through  Ight  coupling  that:  

•  Requires  clients  to  know  procedure  names  

•  Has  specific  procedure  parameters  and  order  

•  Requires  a  URI  per  method/  funcIon  (ie  create,  edit,  

delete)  

Page 7: zendframework2 restful

An  Overview  of  SOAP  While  once  widely  popular,  SOAP  has  quickly  lost  ground  to  

REST  based  APIs.    SOAP  based  APIs:  

•  Exposes  operaIons/  method  calls  

•  Larger  packets  of  data,  XML  based  

•  All  calls  sent  through  POST  •  Can  be  stateless  or  stateful  

•  WSDL  –  Web  Service  DefiniIons  

Page 8: zendframework2 restful

SOAP  Sample  Request  

<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"> <soap:Body xmlns:m="http://www.example.org/stock"> <m:GetStockPrice> <m:StockName>IBM</m:StockName> </m:GetStockPrice> </soap:Body> </soap:Envelope>

h`p://www.w3schools.com/soap/soap_example.asp  

Page 9: zendframework2 restful

SOAP  Sample  Response  

<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"> <soap:Body xmlns:m="http://www.example.org/stock"> <m:GetStockPriceResponse> <m:Price>34.5</m:Price> </m:GetStockPriceResponse> </soap:Body> </soap:Envelope>

h`p://www.w3schools.com/soap/soap_example.asp  

Page 10: zendframework2 restful

An  Overview  of  REST  REST  on  the  other  hand  has  gained  in  popularity  due  to  its  

simplicity,  reduced  transfer  requirements,  and  usage  of  JSON.    

REST:  

•  Returns  data,  doesn’t  expose  methods  

•  Supports  XML  and  JSON  

•  Uses  explicit  HTTP  Verbs  

•  Point  to  point  connecIons  

•  Ajax  (JavaScript)  Friendly  

•  Stateless  

Page 11: zendframework2 restful

REST  JSON  Sample  Request  

{"user":{"firstName":"John","lastName":"Smith","email":"[email protected]"}!

REST  JSON  Sample  Response  {"user":{"firstName":"John","lastName":"Smith","email":"[email protected]"},"_links":{"edit":["href","http:\/\/www.mysite.com\/api\/user\/10"],"message":["href","http:\/\/www.mysite.com\/api\/user\/10\/message"]}}!

Page 12: zendframework2 restful

REST  vs.  SOAP  REST  

•  Returns  data  

•  Supports  XML  and  JSON  

•  Uses  CRUD/  HTTP  Verbs  

•  Point  to  point  connecIons  

•  Ajax  (JavaScript)  Friendly  

•  Stateless  

SOAP  

•  Exposes  operaIons/  method  calls  

•  All  calls  sent  through  POST  

•  Larger  packets  of  data,  XML  based  

•  Can  be  stateless  or  stateful  

•  WSDL  Support  

   

Advantage  goes  to…  

Page 13: zendframework2 restful

Arguments  against  REST  •  REST  APIs  are  difficult  to  build  and  maintain  

•  REST  is  not  secure  (anyone  can  access  it)  

•  There  are  no  strict  standards  for  REST  APIs  

•  REST  services  are  not  reliable  

Page 14: zendframework2 restful

Arguments  against  REST  •  REST  APIs  are  difficult  to  build  and  maintain  

Um,  we’re  going  to  build  one  in  thirty  minutes…    And  as  

REST  has  gained  in  popularity  there  are  more  tools  to  help  

keep  documentaIon  up  to  date.    As  long  as  basic  guidelines  

are  followed  REST  APIs  can  be  maintained  and    

provide  backwards  compaIbility.  

Read  how  we  do  it  @  h`p://bit.ly/1cCEYjC  

Page 15: zendframework2 restful

Arguments  against  REST  •  REST  is  not  secure  (anyone  can  access  it)  

There  are  many  precauIons  we  can  take  to  ensure  our  

REST  API  only  serves  those  who  we  want  to  have  access  

to  the  data,  including  OAuth  tokens  and  IP  restricIons.    

However,  it’s  important  to  remember  that  like    

anything,  JavaScript/  AJAX  should  only  be  used  to    

make  calls  to  public  or  insensiIve  data.  

Page 16: zendframework2 restful

Arguments  against  REST  •  There  are  no  strict  standards  for  REST  APIs  

This  is  true  as  there  is  no  governing  body  for  REST.    

However,  we  will  be  going  over  some  general  

guidelines  that  should  be  used  when  building  your  

API  and  as  long  as  these  are  followed  your  

API  should  be  totally  awesome.  

Page 17: zendframework2 restful

Arguments  against  REST  •  REST  services  are  not  reliable  

REST  services  are  just  as  reliable  as  SOAP  APIs  when  the  

proper  checks  are  implemented  on  the  client’s  side.    

These  should  include  checking  the  request  headers  

returned  by  CURL  requests.    For  this  reason  it  is  

important  to  make  sure  you  are  using  the  correct  

response  codes  and  giving  easy  to  understand    

error  messages.  

Page 18: zendframework2 restful

A  Good  REST  API  Offers  •  Generality  –  language  agnosIc  •  Familiarity  –  developers  are  used  to  it  

•  Scalability  –  can  grow  with  usage/  demand  

•  SegmentaIon  –  secIons  can  be  updated  independently  

•  Speed  –  low  data  transfer,  cacheable  •  Security  –  personal  data  remains  protected  

•  EncapsulaIon  –  ability  to  send  data  as  objects  

Page 19: zendframework2 restful

REST  APIs  provide  a  concrete  barrier  

Page 20: zendframework2 restful

A  Good  REST  API  Uses  Explicit  HTTP  Verbs  

Create  –  POST  Read  –  GET  

Update  –  PUT  

Delete  -­‐  DELETE  

Page 21: zendframework2 restful

A  Good  REST  API  

Is  built  for  longevity  and  designed  

to  evolve…  

Page 22: zendframework2 restful

so#ware  design  on  the  scale  of  decades:  every  detail  is  intended  to  promote  so#ware  longevity  and  independent  evolu8on.  Many  of  the  constraints  are  directly  opposed  to  short-­‐term  efficiency.  Unfortunately,  people  are  fairly  good  at  short-­‐term  design,  and  usually  awful  at  long-­‐term  design  

“  

”  

-­‐  Dr.  Roy  Fielding  

Page 23: zendframework2 restful

A  Good  REST  API  Uses  Hypermedia  

As  

The  

Engine  

Of  

ApplicaIon  

State  

Page 24: zendframework2 restful

A  Good  REST  API  Uses  Hypermedia  

As  

The  

Engine  

Of  

ApplicaIon  

State  

HATEOAS  relies  on  the  concept  that  applicaIons  will  change,  data  required  will  change,  and  paths  can  change.    However,  these  changes  should  not  effect  exisIng  clients.    Hypermedia  is  stressed  over  a  server  oriented  architecture.  

Page 25: zendframework2 restful

A  Good  REST  API  Uses  Hypermedia  

As  

The  

Engine  

Of  

ApplicaIon  

State  

In  order  to  accommodate  these  changes  HATEOAS  not  only  sends  back  the  data  requested,  but  the  next  possible  acIons  as  urls,  this  allows  the  client’s  applicaIon  to  be  dynamic  while  accommodaIng  any  updates  to  the  API  itself,  prevenIng  V1,  V2,  V3    endpoints  

Page 26: zendframework2 restful

A  Good  REST  API  Uses  

Hypermedia  

ApplicaIon  

Language  

Hypermedia  ApplicaIon  Language  provides  a  format  for  describing  addiIonal  resources  (ie  links)  using  a  _links -> item -> connection type => url grouping.      

Content  type:  applicaXon/hal+json      

Page 27: zendframework2 restful

Using  HATEOAS  

{"data":{"user":{"fname":"first","lname":"last"}}, "_links":{ "edit":{"href":"/api/user/id/1"}, "message":{"href":"/api/message/id/1"} },"id":"1"}

(Sample  JSON  Response)  

Page 28: zendframework2 restful

A  Good  REST  API  Uses  Hypermedia  

As  

The  

Engine  

Of  

ApplicaIon  

State  

By  sending  back  the  next  possible  acIons  we  are  able  to  modify  the  endpoints  without  breaking  backwards  compaIbility…    Let’s  say  we  now  required  the  last  name  in  the  message  endpoint,  just  to  prevent  accidental    message  from  being    sent…  

Page 29: zendframework2 restful

We  can  update  the  endpoint  in  the  response  for  our  clients,  allowing  them  to  use  the  dynamic  endpoint  to  perform  the  acIon,  prevenIng  any  backwards  compaIbility  breaks!    

Using  HATEOAS  

{"data":{"user":{"fname":"first","lname":"last"}}, "_links":{ "edit":{"href" : "/api/user/id/1"}, "message":{"href" : "/api/message/id/1/lname/last"} },"id":"1"}

Page 30: zendframework2 restful

Use  JSON  instead  of  XML  •  Be`er  Language  Support  

 •  Lightweight  (much  less  code  than  XML)  

           

•  Object  Oriented  by  nature    

•  Simple  to  encode/  decode  To  encode/  decode  JSON  in  PHP  simply  use  the  json_encode()  and    json_decode() funcIons!    Many  frameworks  also  have  JSON  libraries  that  take  care  of  all  of  the  error  checking  for  you  as  well!  

{"object1":{"object":{"string":"rock","string2":"star"}},"object2":{"string":"hello","string2": "world"},"string":"json is cool"}

Page 31: zendframework2 restful

Use  AuthenXcaXon  Tokens  •  Users  should  be  provided  with  a  unique  API  key/  idenIfier  that  allows  you  to  track,  limit,  and  enable  features  

•  An  OAuth  token  should  be  used  to  link  API  keys  to  accounts  instead  of  requesIng  account  usernames  and  passwords  

Page 32: zendframework2 restful

Thro^le  API  Key  Usage  Be  sure  to  place  limits  on  the  number  of  calls/  queries  an  

API  key  can  make  per  hour  or  per  day  to  prevent  your  

applicaIon  from  becoming  bogged  down  and  suscepIble  

to  DOS  a`acks.    

This  risk  can  also  be  reduced  by  ensuring  your  

API  is  operaIng  within  the  cloud  and  has  the  

ability  to  scale  to  increased  traffic  demands.  

Page 33: zendframework2 restful

OAuth  Tokens  Tokens  help  prevent  misuse  of  the  system  and  limit  

access  to  the  control  panel.    Usernames  and  passwords  

allow  hackers  to  go  in  beyond  the  API,  oRen  accessing  

billing  and  profile  informaIon  that  exposes  your  clients  

to  catastrophic  damage  should  this  informaIon    

fall  into  the  wrong  hands  

Page 34: zendframework2 restful

Use  HTTP  Status  Codes  Proper  use  of  HTTP  status  codes  give  your  users  immediate  feedback  on  the  result.    Some  of  the  more  widely  used  Header  codes  include:    

•  200  –  OK  •  201  –  Created  •  304  –  Not  modified  •  400  –  Bad  Request  •  401  –  Not  Authorized  •  403  –  Forbidden  •  404  –  Page/  Resource  Not  Found  •  405  –  Method  Not  Allowed  •  500  –  Internal  Server  Error  

Page 35: zendframework2 restful

Use  HTTP  Status  Codes  You  probably  shouldn’t  use  these…      

•  418  –  I’m  a  teapot  •  420  –  Keep  your  calm  

Status  Code  420  has  gained  popularity  as  it  is  saIrically  returned  by  Twi`er  when  there’s  been  too  many  requests,  however  the  proper  response  code  for  “too  many  requests”  would  be  429.      

Page 36: zendframework2 restful

Use  DescripXve  Error  Messages  Error  messages  should  give  a  clear  descripIon  of  what  went  wrong  and  how  the  client  can  fix  their  code  to  avoid  the  error  in  the  future.    Providing  a  link  to  addiIonal  informaIon  and  live  debugging  examples  is  oRen  extremely  useful  to  developers,  and  allows  your  error  messages  to  be  more  compact,  but  requires  you  to  keep  addiIonal  documentaIon  up  to  date  for  your  users.  

Page 37: zendframework2 restful

Use  DescripXve  Error  Messages  These  are  not  good  error  messages:    

•  Something  went  wrong    

•  Could  not  complete  acIon    

•  Invalid  parameters    

•  Hey  look,  it’s  a  rocket.  

Page 38: zendframework2 restful

Use  DescripXve  Error  Messages  Good  Error  Messages:    

•  The  AuthenIcaIon  token  is  not  recognized,  learn  more  at  h`p://…    

•  A  User  ID  is  required  to  perform  this  acIon,  learn  more  at  h`p://…    

•  Error  Code  313.    Read  more  at  h`p://…  

Page 39: zendframework2 restful

Remember!  DO  NOT  BREAK  BACKWARDS  COMPATIBILITY.    Make  

sure  whatever  updates  you  make  to  your  API  do  not  

cause  problems  for  your  exisIng  clients.  

 

It  is  ideal  to  have  unit  tests  running  against  your  

API  to  ensure  changes  do  not  cause  negaIve    

or  unforeseen  consequences.  

Page 40: zendframework2 restful

Versioning  (ie:  /api/v2/…)  For  this  reason  I  am  not  a  fan  of  “versioning”  your  API.    

All  releases  should  be  backwards  compaIble  so  that  your  

users  do  not  need  to  know  which  version  they  are  trying  

to  access!    Imagine  if  you  versioned  your  website!    

The  excepIon  to  this  is  a  complete  rewrite  of    

your  API,  in  which  case  the  old  API  should  sIll    

be  supported  unIl  clients  are  migrated.  

Page 41: zendframework2 restful

That’s  awesome!      Now  let’s  write    some  code…  

Page 42: zendframework2 restful

Step  1  –  Install  ZF2  On  the  chance  that  you  don’t  already  have  Zend  

Framework  2  installed,  let’s  get  it  up  and  running.    

We’re  going  to  assume  you  have  PHP  (php.net),  Git  

(git-­‐scm.com)  and  Composer  (getcomposer.org)  

already  installed.  

Page 43: zendframework2 restful

Installing  ZF2  

mkdir apiproject cd apiproject

1.  Create  directory  on  your  web  server  and  move  into  it  

git init git remote add https://github.com/zendframework/ZendSkeletonApplication.git source

git pull source master

2.  IniIalize  Git,  add  the  Skeleton  Repository,  and  Download  

3.  Run  Composer  

php composer.phar install

Page 44: zendframework2 restful
Page 45: zendframework2 restful

Setup  the  View  JSON  Strategy  

'view_manager' => array( 'strategies' => array( 'ViewJsonStrategy', ), 'display_not_found_reason' => true, 'display_exceptions' => true, 'doctype' => 'HTML5', /* … */ ),!

Add  the  ViewJsonStrategy  to  the  strategies  array  within  the  view_manager  in  module\ApplicaIon\config\module.config.php  

Page 46: zendframework2 restful

Setup  the  Controller  Add  the  UserController  to  the  invokables  array  within  controllers  in  module\ApplicaIon\config\module.config.php  

'controllers' => array( 'invokables' => array( 'Application\Controller\Index' => 'Application\Controller\IndexController', 'Application\Controller\User' => 'Application\Controller\UserController' ), ),!

Remember  the  alias  (leR)  you  give  your  controller  as  we  will  use  that  to  setup  our  routes!  

Page 47: zendframework2 restful

Sefng  up  Routes  

// Segmented Route for APIs 'user' => array( 'type' => 'Segment', 'options' => array( 'route' => '/api/user[/:id]', 'defaults' => array( 'controller' => 'Application\Controller\User', ),

), ),!

Add  routes  to  module\ApplicaIon\config\module.config.php  where  “ApplicaIon”  is  the  module  that  will  be  the  API  library.  

Segmented  Routes  allow  you  to  have  dynamic  routes.      DO  NOT  include  a  default  AcIon  for  your  REST  API  endpoints  

Page 48: zendframework2 restful

The  AbstractResgulController  Zend  Framework  2  comes  with  an  abstract  controller  for  

creaIng  a  REST  API  built  in.        

The  AbstractRestulController  can  be  found  in  the    vendor/zendframework/zendframework/library/Zend/MVC/Controller/

directory.    

Note  –  you  should  not  modify  this  file  

Page 49: zendframework2 restful

The  AbstractResgulController  The  abstract  controller  comes  with  the  following  methods,  

all  set  to  return  header  code  405  –  method  not  allowed:    

•  create($data)  

•  delete($id)  

•  deleteList()  

•  get($id)  

•  getList()  

•  update($id,  $data)  

•  replaceList($data)  

•  patch($id,  $data)  

•  patchList($data)  

•  opIons()    

Page 50: zendframework2 restful

Sefng  up  the  User  Controller  Extending  the  AbstractRestulController  we  can  setup  

\module\Application\src\Application\Controller\UserController.php    

For  this  class  we  will:    

•  Set  the  opIons/  header  permissions  

•  Create  an  event  listener  

•  Start  building  our  API  methods  

Page 51: zendframework2 restful

Sefng  up  the  UserController  <?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractRestfulController; use Zend\View\Model\JsonModel; class UserController extends AbstractRestfulController { } !

Page 52: zendframework2 restful

Setup  OpXons  class UserController extends AbstractRestfulController { protected $collectionOptions = array('GET', 'POST'); protected $resourceOptions = array('GET', 'PUT', 'DELETE'); protected function _getOptions() { if ($this->params->fromRoute('id', false)) { // we have an ID, return specific item return $this->resourceOptions; } // no ID, return collection return $this->collectionOptions; } } !

We’ll  use  the  _getOpIons()  method  in  the  opIons()  and  checkOpIons()  methods  

Page 53: zendframework2 restful

Returning  Available  OpXons  public function options() {

$response = $this->getResponse();

// If in Options Array, Allow $response->getHeaders()

->addHeaderLine('Allow', implode(',', $this->_getOptions()));

// Return Response return $response;

}!

Page 54: zendframework2 restful

Adding  an  Event  Listener  

public function setEventManager(EventManagerInterface $events) { // events property defined in AbstractController $this->events = $events; // Register the listener and callback method with a priority of 10 $events->attach('dispatch', array($this, 'checkOptions'), 10); }!

The  event  listener  will  check  the  header  when  dispatched  to  see  if  the  behavior/  h`p  verb  being  a`empted  is  allowed  for  the  resource/  collecIon.    If  it  isn’t,  the  checkOpIons()  method  will  kill  the  process  and  return  a  status  code  of  405  to  inform  the  user  the  method  a`empted  is  not  allowed.  

Page 55: zendframework2 restful

Add  Event  Listener  Method  public function checkOptions($e) {

if (in_array($e->getRequest()->getMethod(), $this->_getOptions())) { // Method Allowed, Nothing to Do return;

}

// Method Not Allowed $response = $this->getResponse(); $response->setStatusCode(405);

return $response; }!

Page 56: zendframework2 restful

Add  AcXon  Methods   public function create($data) { // get created service to handle user creation // in this case userAPIService extends UserService and // adds in the _links or available actions to the result $userAPIService = $this->getServiceLocator()->get('userAPIService'); $result = $userAPIService->create($data); $response = $this->getResponse(); $response->setStatusCode(201); // Send Data to the View return new JsonModel($result); }!

Page 57: zendframework2 restful

Curl  –X  POST  Request  Response  

Page 58: zendframework2 restful

Add  AcXon  Methods   public function update($id, $data) { // get created service to handle user updates // in this case userAPIService extends UserService and // adds in the _links or available actions to the result $userAPIService = $this->getServiceLocator()->get('userAPIService'); $result = $userAPIService->update($id, $data); $response = $this->getResponse(); $response->setStatusCode(200); // Send Data to the View return new JsonModel($result); }!

Page 59: zendframework2 restful

Add  AcXon  Methods   public function deleteList() { $response = $this->getResponse(); $response->setStatusCode(400); $result = array( 'Error' => array( 'HTTP Status' => '400', 'Code' => '123', 'Message' => 'A user ID is required to delete a user', 'More Info' => 'http://www.mysite.com/api/docs/user/delete', ), ); return new JsonModel($result); }!

In  most  cases  you’re  going  to  want  to  prevent  clients  from  uIlizing  the  DELETE  HTTP  verb  without  providing  an  ID.    In    the  event  they  try  to  access  it  generically,  they  will  go  to  the  deleteList()  method.  

Page 60: zendframework2 restful

Curl  –X  DELETE  Request  Response  

Page 61: zendframework2 restful

You  now  have  a  funcXonal  API!  You  can  conInue  to  use  the  following  methods  (and  some  

others)  to  build  your  API  Controllers!    

•  create($data)  

•  delete($id)  

•  deleteList()  

•  get($id)  

•  getList()  

•  update($id,  $data)  

•  replaceList($data)  

•  patch($id,  $data)  

•  patchList($data)  

•  opIons()    

Page 62: zendframework2 restful

Remember…  You  will  want  to  add  more  features  including  OAuth  2  and  

thro`ling.    You  can  easily  do  this  by  creaIng  your  own  

abstract  class  that  extends  the  AbstractRestulController,  

or  by  taking  advantage  of  a  Zend  Framework  2  REST  

Skeleton  App  (available  on  GitHub)  

Page 63: zendframework2 restful

More  Resources  You  can  learn  more  about  REST  APIs  and  Zend  Framework  

2  by  visiIng  the  following:    

•  REST  API  Tutorial  -­‐  h`p://www.restapitutorial.com/  

•  Apigee  REST  Design  (PDF)  -­‐  h`p://bit.ly/13vZXAL    

•  ZF2  GeLng  Started  -­‐  h`p://bit.ly/17Wgmun    

•  MWOP  ZF2  REST  -­‐  h`p://bit.ly/19rmk9M    

•  Hounddog  ZF2  REST  -­‐  h`p://bit.ly/12fVW0x  

Page 64: zendframework2 restful

A  Final  Thought…  A  good  API  is  harder  for  your  clients  to  

implement…  

…but  easier  for  them  (and  you)  to  

maintain.    SDKs  save  lives.  

 

Page 65: zendframework2 restful

THANK YOU.

@mikegstowe

visit  mikestowe.com/slides  for  more  on  PHP  and  Web  Development  

@ctct_api

A big thank you to Constant Contact for making this presentation possible