Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Frontend, API Backend

Web Frontend, API Backend

Slide deck from my online presentation at NomadPHP in August 2014. about building websites with separate API and presentation layers

Lorna Mitchell

August 19, 2014
Tweet

More Decks by Lorna Mitchell

Other Decks in Technology

Transcript

  1. Web Frontend, API Backend Lorna Mitchell, NomadPHP August 2014

  2. Play along! Code is here: http://lrnja.net/backfront

  3. Why Would You Do That?

  4. Frontend / Backend Benefits • scalability • reusability • separation

  5. Service-Oriented Architecture

  6. How Would You Do That?

  7. How Would You Do That? Hint: using the skills you

    already have
  8. Model-View-Controller

  9. Model-View-Controller

  10. Slim Framework http://www.slimframework.com/ • modern microframework • offers routing out

    of the box • lightweight • extensible • actively developed and well supported
  11. API-First

  12. API Endpoints Our API will have two endpoints initially: •

    a list of events /events • an individual event /events/42 Using Slim Framework, let's put those in place
  13. One Request

  14. Events List Controller Slim registers a callback per route 24

    $app->get('/events', function () use ($app) { 25 $db = $app->config('container')['db']; 26 $data = array(); 27 28 $model = new EventModel($db); 29 $data['events'] = $model->getSomeEvents(); 30 31 $app->render("foo.php", array("mydata" => $data)); 32 }); 33
  15. Events List Model 1 public function getSomeEvents() { 2 //

    get all future events 3 $sql = "select ID, event_name, event_loc, event_des 4 . "from events " 5 . "where event_start > :start " 6 . "order by event_start " 7 . "limit 10"; 8 9 $stmt = $this->db->prepare($sql); 10 $stmt->execute(array("start" => mktime(0,0,0))); 11 $results = $stmt->fetchAll(PDO::FETCH_ASSOC); 12 return $results; 13 } 14
  16. Output Handler 1 <?php 2 3 class View extends \Slim\View

    { 4 public function render($template) { 5 $app = \Slim\Slim::getInstance(); 6 $app->response->headers->set('Content-Type', 7 'application/json'); 8 return json_encode($this->data['mydata']); 9 } 10 }
  17. Fetching the Events List GET http://localhost:8880/events { "events": [ {

    "ID": "44", "event_desc": "Praesent rutrum orci eget ipsum ornare et consequat neque egestas. Praesent rutru "event_loc": "Bridgeport", "event_name": "CentOS day" }, { "ID": "6", "event_desc": "Vivamus gravida, dolor ut porta bibendum, mauris ligula condimentum est, id facil "event_loc": "Nectar", "event_name": "Ruby day" }, { "ID": "48", "event_desc": "Etiam ligula elit, condimentum lacinia fermentum nec, elementum id urna. Praesent "event_loc": "New Hope", "event_name": "IT meetup" }, ...
  18. Now The Frontend

  19. Frontend Building Blocks This project is quick-started with: • Slim

    Framework again http://www.slimframework.com • Guzzle http://guzzlephp.org • PureCSS http://purecss.io/ (including their sample layout) • Brightened up with a little something from https://en.gravatar.com/
  20. Event List

  21. One Request

  22. Events List Controller Slim registers a callback per route 16

    $app->get('/', function () use ($app) { 17 $client = new ApiClient(new GuzzleHttp\Client()); 18 $events = $client->getEventList(); 19 $app->render("index.php", array("events" => $events)); 20 }); 21
  23. Api Client 4 class ApiClient { 5 protected $client; 6

    7 public function __construct(GuzzleHttp\Client $client) 8 $this->client = $client; 9 } 10 11 public function getEventList() { 12 // todo make this URL configurable 13 $response = $this->client->get( 14 "http://localhost:8880/events"); 15 return $response->json(); 16 } 17
  24. Template 34 <?php foreach($events['events'] as $event): ?> 35 <section class="post">

    36 <header class="post-header"> 37 <h2 class="post-title"><?=$event['event_name']?></h2> 38 <img class="post-avatar" alt="avatar" height="48" width 39 src="http://www.gravatar.com/avatar/<?=md5($event['ID 40 <p class="post-meta"> 41 More details: <a class="post-author" 42 href="/showEvent/<?=$event['ID']?>">click here</a 43 </p> 44 </header> 45 </section> 46 <?php endforeach; //events ?> 47
  25. The Gravatar Code Again To get one of those pattern

    things, the URL is: http://www.gravatar.com/avatar/[hash] ?d=identicon
  26. Event Detail Page Made in the same way

  27. Is That Everything?

  28. Additional Considerations • identifying consumers • logging users in •

    caching data • what else?
  29. Identifying Consumers How open should your API be? Identify consumers

    to: • track users • control access to resources • rate-limit users
  30. How To Identify Consumers 1. give them an API key

    2. check the API key on all requests
  31. Logging Users In Please use a standard! Tokens are nicer

    than credentials
  32. OAuth 2 OAuth2 solves trust and authentication issues between user,

    server and client.
  33. How OAuth Works Consumer sends Authorization Grant to server. (Full

    details at http://tools.ietf.org/html/rfc6749) Server supplies an access token in response
  34. OAuth2 Authorization Grants Authorization Code For untrusted clients; send user

    to website to log in, return an auth code Implicit Give the client an access token instead of an API key Client Credentials Use your own credentials as an access token Resource Owner Password Credentials Client exchanges user creds for an access token and only stores that
  35. Implementing Login Start with a login form

  36. Login Flow

  37. Authorizations Endpoint 48 $app->post('/authorizations', function () use ($app) { 49

    $db = $app->config('container')['db']; 50 $data = array(); 51 52 // horribly assuming JSON. Real code checks first 53 $in = json_decode(file_get_contents("php://input"), tru 54 55 $model = new AuthModel($db); 56 $data['access_token'] = $model->getAccessTokenFromCreds 57 $in['username'], $in['password']); 58 $app->render("foo.php", array("mydata" => $data)); 59 }); 60
  38. Making the Access Token 11 public function getAccessTokenFromCreds( 12 $username,

    $password) { 13 14 $sql = "select ID, username, password from user " 15 . "where username = :username " 16 . "and password = :password "; 17 18 $stmt = $this->db->prepare($sql); 19 $stmt->execute(array("username" => $username, 20 "password" => md5($password))); 21 $user_info = $stmt->fetch(PDO::FETCH_ASSOC); 22
  39. Making the Access Token 25 // would be neat to

    store consumer also 26 $token_sql = "insert into oauth_access_tokens " 27 . "set user_id = :user_id, " 28 . "access_token = :token "; 29 30 // get random number and hash it for token 31 $time = gettimeofday(); 32 $token = sha1($time['usec']); 33 $token_stmt = $this->db->prepare($token_sql); 34 $token_stmt->execute(array("user_id" => $user_info[ 35 "token" => $token)); 36 return $token; 37 } 38
  40. Using The Access Token

  41. Is That It?

  42. Frontend, Backend • independently scalable/deployable/maintainable • reusable backend • modular

    systems • flexible when requirements change
  43. Questions? While this slide is up, you may also be

    interested in: • my website: http://lornajane.net • the code: http://lrnja.net/backfront • PHP Web Services book and video http://shop.oreilly.com • joind.in http://m.joind.in/about