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

Web Frontend, API Backend

Web Frontend, API Backend

Introduction to building a PHP application with separate front and back ends.

Lorna Mitchell

October 29, 2014
Tweet

More Decks by Lorna Mitchell

Other Decks in Technology

Transcript

  1. Web Frontend, API Backend
    Lorna Mitchell, ZendCon 2014

    View full-size slide

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

    View full-size slide

  3. Why Would You Do That?

    View full-size slide

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

    View full-size slide

  5. Service-Oriented Architecture

    View full-size slide

  6. How Would You Do That?

    View full-size slide

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

    View full-size slide

  8. Model-View-Controller

    View full-size slide

  9. Model-View-Controller

    View full-size slide

  10. Slim Framework
    http://www.slimframework.com/
    • modern microframework
    • offers routing out of the box
    • lightweight
    • extensible
    • actively developed and well supported

    View full-size slide

  11. 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

    View full-size slide

  12. 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

    View full-size slide

  13. Events List Model
    1 public function getSomeEvents() {
    2 // get all future events
    3 $sql = "select ID, event_name, event_loc, event_desc "
    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

    View full-size slide

  14. Output Handler
    1 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 }

    View full-size slide

  15. 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 rutrum orci eget ipsum ornare et consequat neque egestas. Lo
    "event_loc": "Bridgeport",
    "event_name": "CentOS day"
    },
    {
    "ID": "6",
    "event_desc": "Vivamus gravida, dolor ut porta bibendum, mauris ligula condimentum est, id facilisis ante massa a justo. Nulla faucibus mollis ipsum si
    "event_loc": "Nectar",
    "event_name": "Ruby day"
    },
    {
    "ID": "48",
    "event_desc": "Etiam ligula elit, condimentum lacinia fermentum nec, elementum id urna. Praesent rutrum orci eget ipsum ornare et consequat neque egest
    "event_loc": "New Hope",
    "event_name": "IT meetup"
    },
    ...

    View full-size slide

  16. Now The Frontend

    View full-size slide

  17. 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/

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

  20. Template
    34
    35
    36
    37 =$event['event_name']?>
    38 39 src="http://www.gravatar.com/avatar/=md5($event['ID'])?>?d=identicon">
    40
    41 More details: 42 href="/showEvent/=$event['ID']?>">click here
    43
    44
    45
    46
    47

    View full-size slide

  21. The Gravatar Code Again
    To get one of those pattern things, the URL is:
    http://www.gravatar.com/avatar/[hash] ?d=identicon

    View full-size slide

  22. Event Detail Page
    Made in the same way

    View full-size slide

  23. Is That Everything?

    View full-size slide

  24. Additional Considerations
    • identifying consumers
    • logging users in
    • picking a data format
    • documentation and testing

    View full-size slide

  25. Identifying Consumers
    How open should your API be? Identify consumers to:
    • control access to resources
    • enable rate-limiting
    • track how the API is being used

    View full-size slide

  26. How To Identify Consumers
    1. give them an API key
    2. check the API key on all requests

    View full-size slide

  27. Logging Users In
    Please use a standard!
    Tokens are nicer than credentials

    View full-size slide

  28. OAuth 2
    OAuth2 solves trust and authentication issues between user, server and
    client.

    View full-size slide

  29. 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

    View full-size slide

  30. 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

    View full-size slide

  31. Implementing Login
    Start with a login form

    View full-size slide

  32. 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"), true);
    54
    55 $model = new AuthModel($db);
    56 $data['access_token'] = $model->getAccessTokenFromCreds(
    57 $in['consumer'], $in['username'], $in['password']);
    58 $app->render("foo.php", array("mydata" => $data));
    59 });
    60

    View full-size slide

  33. Making the Access Token
    11 public function getAccessTokenFromCreds(
    12 $consumer, $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

    View full-size slide

  34. Making the Access Token
    25 $token_sql = "insert into oauth_access_tokens "
    26 . "set consumer_key = :consumer, "
    27 . "user_id = :user_id, "
    28 . "access_token = :token ";
    29
    30 // get random number and hash it for token
    31 $token = bin2hex(openssl_random_pseudo_bytes(16));
    32 $token_stmt = $this->db->prepare($token_sql);
    33 $token_stmt->execute(array(
    34 "user_id" => $user_info['ID'],
    35 "consumer" = $consumer, "token" => $token));
    36 return $token;
    37 }
    38

    View full-size slide

  35. Using The Access Token

    View full-size slide

  36. Data Formats
    • JSON or XML?
    • use Content-Type to specify which
    • be specific by using "Media Types"

    View full-size slide

  37. Media Types
    Take the Content-Type header to the next level!
    Consider these:
    • application/json
    • application/vnd.github+json
    • application/vnd.github.v3+json
    https://en.wikipedia.org/wiki/Internet_media_type

    View full-size slide

  38. Hypermedia
    • add links to related resources
    • for bonus points, use a standard like HAL
    {
    "_links": {
    "self": { "href": "/things/42" },
    "messages": {"href": "/things/42/messages" },
    "user": { "href": "/users/123" }
    }
    }
    http://stateless.co/hal_specification.html

    View full-size slide

  39. Documentation
    Yes

    View full-size slide

  40. Documentation
    Lots of options:
    • old-fashioned, write words and copy/paste examples
    • static plus something like http://hurl.it
    • interactive docs: try https://github.com/mashery/iodocs
    • http://apiary.io/ produces a mock API, then verifies your real one

    View full-size slide

  41. Frontend, Backend
    • independently scalable/deployable/maintainable
    • reusable backend
    • modular systems
    • flexible when requirements change

    View full-size slide

  42. Questions?
    While this slide is up, there may be interest in:
    • Feedback https://m.joind.in/talk/1af2a
    (from http://oreilly.com)

    my blog: http://lornajane.net

    joind.in itself http://m.joind.in/about

    View full-size slide