Slide 1

Slide 1 text

Web Frontend, API Backend Lorna Mitchell, NomadPHP August 2014

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Why Would You Do That?

Slide 4

Slide 4 text

Frontend / Backend Benefits • scalability • reusability • separation

Slide 5

Slide 5 text

Service-Oriented Architecture

Slide 6

Slide 6 text

How Would You Do That?

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Model-View-Controller

Slide 9

Slide 9 text

Model-View-Controller

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

API-First

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

One Request

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Output Handler 1 response->headers->set('Content-Type', 7 'application/json'); 8 return json_encode($this->data['mydata']); 9 } 10 }

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Now The Frontend

Slide 19

Slide 19 text

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/

Slide 20

Slide 20 text

Event List

Slide 21

Slide 21 text

One Request

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Template 34 35 36 37

38 avatar 41 More details: 44 45 46 47

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Event Detail Page Made in the same way

Slide 27

Slide 27 text

Is That Everything?

Slide 28

Slide 28 text

Additional Considerations • identifying consumers • logging users in • caching data • what else?

Slide 29

Slide 29 text

Identifying Consumers How open should your API be? Identify consumers to: • track users • control access to resources • rate-limit users

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Implementing Login Start with a login form

Slide 36

Slide 36 text

Login Flow

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Using The Access Token

Slide 41

Slide 41 text

Is That It?

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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