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

Web Frontend, API Backend

Web Frontend, API Backend

Talk about how to build PHP websites in two modular sections, including advice on API design and OAuth2

Lorna Mitchell

October 03, 2014
Tweet

More Decks by Lorna Mitchell

Other Decks in Technology

Transcript

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

    View full-size slide

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

    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_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

    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 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"
    },
    ...

    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
    40
    41 More details: 42 href="/showEvent/=$event['ID']?>">click here43
    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"), tru
    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 http://m.joind.in/talk/014f7
    (from http://oreilly.com)

    my blog: http://lornajane.net

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

    View full-size slide