Slide 1

Slide 1 text

APIS With Lumen, Guzzle, & Swagger By Jeremy Lindblom (@jeremeamia)

Slide 2

Slide 2 text

I’m Jeremy! Product Architect McGraw-Hill Education @jeremeamia • @phpbard @pnwphp • @azphp

Slide 3

Slide 3 text

APIS Micro services Cloud REST Saas

Slide 4

Slide 4 text

CLIENT SERVER

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

$method = ?; $endpoint = ?; $payload = ?; $status = ?; $app->{$method}($endpoint, function () { /* The “easy” part */ return response($payload, $status) });

Slide 7

Slide 7 text

Time to make some design decisions!

Slide 8

Slide 8 text

api.mygradebook.local × Create an assignment × Read assignments (single & multiple) × Update an assignment × Delete an assignment

Slide 9

Slide 9 text

What Should the ENdpoints look like and Which HTTP Methods will we use?

Slide 10

Slide 10 text

GET PUt Delete Options POST Patch Head Common HTTP Methods

Slide 11

Slide 11 text

GET PUt (replace or create) Delete Options POST (create/other) Patch (update) Head Common HTTP Methods

Slide 12

Slide 12 text

api.mygradebook.local POST /assignments - Create GET /assignments - List/Search GET /assignments/{id} – Read PATCH /assignments/{id} - Update DELETE /assignments/{id} - Delete

Slide 13

Slide 13 text

https://leanpub.com/restful-api-design By: Keith Casey James Higginbotham Mailing List: “API Developer Weekly”

Slide 14

Slide 14 text

Status Codes?

Slide 15

Slide 15 text

503

Slide 16

Slide 16 text

503 SERVICE UNAVAILABLE

Slide 17

Slide 17 text

201

Slide 18

Slide 18 text

201 CREATED

Slide 19

Slide 19 text

429

Slide 20

Slide 20 text

429 TOO MANY REQUESTS

Slide 21

Slide 21 text

SHOULD the API Version go in the URL or in the HEaders?

Slide 22

Slide 22 text

URL

Slide 23

Slide 23 text

HEADERS

Slide 24

Slide 24 text

ELEPHPANT

Slide 25

Slide 25 text

application/json Or application/xml Or...

Slide 26

Slide 26 text

HATEOAS? HAL • JSON-LD JSON-API • CUSTOM And More

Slide 27

Slide 27 text

AUTH?

Slide 28

Slide 28 text

API AUTH First Visit SSL? Later Visits Examples: ID + Secret YES ID + Secret HTTP Basic Auth ID + Secret YES ID + Token OAuth 2.0, JWT ID + Signature PLZ ID + Signature Signature V4, OAuth 1.0a

Slide 29

Slide 29 text

APIS Are HARD! × REST & HTTP × API Versioning × Status Codes × Content Negotiation × HATEOAS × Auth × Streams / Blobs × Pagination × Idempotency × Rate Limiting × CORS × Response Caching × Scalability & Perf. × CAP Theorem

Slide 30

Slide 30 text

https://github.com/dingo/api

Slide 31

Slide 31 text

Dingo API × Content negotiation × Authentication adapters (inc. JWT & OAuth 2) × API versioning (in the headers) × Rate limiting middleware × Response builder/transformers

Slide 32

Slide 32 text

Opinionated Content-type API_STANDARDS_TREE API_NAME API_VERSION Accept: application/vnd.mygradebook.v1+json

Slide 33

Slide 33 text

Versioned ROUTING $api = app('Dingo\Api\Routing\Router'); $api->version('v1', [], function ($api) { $api->get('/assignments', ...); $api->post('/assignments', ...); $api->patch('/assignments/{id}', ...); });

Slide 34

Slide 34 text

RESPONSE BUILDERS + FRACTAL public function index() { $assgs = Assignment::all(); return $this->response ->collection($assgs, new AssgTransformer) ->withHeader('X-MyGB-Count', count($assgs)); }

Slide 35

Slide 35 text

http://fractal.thephpleague.com/

Slide 36

Slide 36 text

Assignments Table Schema::create('assignments', function ($table) { $table->increments('id'); $table->uuid('external_id')->unique(); $table->string('name', 100); $table->integer('points'); $table->timestamp('due_date'); $table->timestamps(); });

Slide 37

Slide 37 text

Assignment fractal transformer class AssgTransformer extends TransformerAbstract { public function transform(Assignment $assg) { return [ 'id' => $assg->external_id, 'name' => $assg->name, 'pointsPossible' => (int) $assg->points, 'dueDate' => date('n/j/Y', $assg->due_date), ]; } }

Slide 38

Slide 38 text

TRANSFORMED JSON RESULT { 'data': { 'id': 'c3ecf466-c7ce-4df1-b6dd-6ad74937e626', 'name': 'Reducing Fractions HW03', 'pointsPossible': 20, 'dueDate': '9/23/2016' } }

Slide 39

Slide 39 text

https://github.com/ramsey/uuid

Slide 40

Slide 40 text

DINGO Starter Project Lumen + Dingo + JWT Auth + CORS https://github.com/0plus1/lumendingojwtapi

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Let’s Consume our API!

Slide 43

Slide 43 text

HTTP CLients × file_get_contents (and stream contexts) × cURL × HTTP extension × Libraries: Buzz, Requests, Guzzle

Slide 44

Slide 44 text

https://github.com/guzzle/guzzle

Slide 45

Slide 45 text

Guzzle HTTP Client × HTTP Client for PHP × Wrapper for cURL (and other stuff) × PSR-7 compliant × Capable of concurrent & async requests × Popular Lib (5700+ , 32,000,000+ )

Slide 46

Slide 46 text

Configuring Guzzle $client = new GuzzleHttp\Client([ 'base_uri' => 'https://api.mygradebook.local', 'auth' => ['Si39fSKkjqba459', 'dl2+aScKw/asjASD721'], 'headers' => [ 'Accept' => 'application/vnd.mygradebook.v1+json', ] ]);

Slide 47

Slide 47 text

POSTING aN ASSIGNMENT $response = $client->post('assignments', [ 'form_params' => [ 'name' => 'Reducing Fractions HW03', 'pointsPossible' => 20, 'dueDate' => '2016-09-23' ] ]); echo $response->getStatusCode(); //> 201

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

CLIENT SERVER

Slide 50

Slide 50 text

CLIENT SERVER

Slide 51

Slide 51 text

http://swagger.io/

Slide 52

Slide 52 text

Swagger × Representation of your RESTful API × JSON or YAML × Large ecosystem × Documentation generation × Code generation × Gateway integration (e.g., Amazon API Gateway)

Slide 53

Slide 53 text

However, Swagger has a new name...

Slide 54

Slide 54 text

https://openapis.org/

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

SWAGGER DOCS (Part 1 - Meta) { "swagger": "2.0", "info": {...}, "host": "petstore-api.herokuapp.com", "basePath": "/pet", "schemes": ["http", "https"], "consumes": ["application/json"], "produces": ["application/json"], ...

Slide 57

Slide 57 text

SWAGGER DOCS (Part 2 - PATHS) "paths": { "/": { "get": { "parameters": [...] "responses": {...} } "post": {...}, ... } }

Slide 58

Slide 58 text

SWAGGER DOCS (Part 3 - PARAMeters) { "name": "limit", "in": "query", (query, path, formData, headers, body) "description": "number of pets to return", "type": "integer", "default": 10, "maximum": 100 }, ...

Slide 59

Slide 59 text

SWAGGER DOCS (Part 4 - RESPONSES) "200": { "description": "List all pets", "schema": { "title": "Pets", "type": "array", "items": {"$ref": "#/definitions/Pet"} } }, ...

Slide 60

Slide 60 text

SWAGGER DOCS (Part 5 - Definitions) "Pet": { "type": "object", "properties": { "name": {"type": "string"}, "birthday": {"type": "integer", "format": "int32"} } }, ...

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

https://www.npmjs.com/package/bootprint

Slide 63

Slide 63 text

INstalling & USING Bootprint > npm install -g bootprint > npm install -g bootprint-openapi > bootprint openapi ./swagger.json ./docs

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

CLIENT SERVER

Slide 66

Slide 66 text

Generate Swagger FROM CODE × Annotate your code for Swagger × https://github.com/zircote/swagger-php > swagger app -o public/swagger.json

Slide 67

Slide 67 text

AnNotations /** * @SWG\Post( * path="/assignments", * operationId="createAssignment", * summary="Create an assignment.", * <<< PARAMETERS >>> * @SWG\Response( * response=201 * ) * ) */ public function create(Request $request) {...}

Slide 68

Slide 68 text

AnNotations /** * ... * @SWG\Parameter( * name="name", * in="formData", * description="Name of the assignment.", * required=true, * type="string" * ), * ... */

Slide 69

Slide 69 text

Generate Code FROM SWAGGER × Swagger website has: × Client generation (decent cURL client) × Server generation (Lumen?) × jolicode/jane-openapi (pluggable client lib) × jl6m/swagger-lite (simple, Guzzle-based)

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

USING My Swagger-lite Guzzle Client $response = $client->createAssignment([ 'name' => 'Reducing Fractions HW03', 'pointsPossible' => 20, 'dueDate' => '2016-09-23' ]); echo $response->getStatusCode(); //> 201

Slide 72

Slide 72 text

APIS with Lumen, DINGO FRACTAL, UUID, Guzzle, OPENAPI (swagger), BootPrint, & More

Slide 73

Slide 73 text

WHAT’s MISSING?

Slide 74

Slide 74 text

HOW Can You Help? × Publish a Swagger doc for your API × Adopt a Swagger tool or make a new one × Get involved in the OpenAPI group × Improve Lumen/Laravel’s API ecosystem

Slide 75

Slide 75 text

Resources & CREDITS × laravel/lumen docs: https://lumen.laravel.com/docs/5.2 × dingo/api docs: https://github.com/dingo/api/wiki × jwt-auth docs: https://github.com/tymondesigns/jwt-auth/wiki × API starter project: https://github.com/0plus1/lumendingojwtapi × Slides template (Jachimo) from: http://www.slidescarnival.com/ × ramsey/uuid lib: https://github.com/ramsey/uuid × Guzzle docs: http://docs.guzzlephp.org/en/latest/ × Swagger website: http://swagger.io/ × OpenAPI Initiative website: https://openapis.org/

Slide 76

Slide 76 text

Resources & CREDITS × UUIDs in Laravel: http://humaan.com/using-uuids-with-eloquent-in-laravel/ × Percona UUID: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ × UUID model traits: https://github.com/alsofronie/eloquent-uuid/tree/master/src × HAL library: https://github.com/blongden/hal × JSON-API library: https://github.com/neomerx/json-api × JSON-LD library: https://github.com/lanthaler/JsonLD × Guzzle OAuth 2 library: https://github.com/Sainsburys/guzzle-oauth2-plugin × API design book: https://leanpub.com/restful-api-design × Swagger-lite Guzzle client: https://github.com/jeremeamia/guzzle-swagger-lite × Bootprint: https://www.npmjs.com/package/bootprint × Swagger-PHP: https://github.com/zircote/swagger-php

Slide 77

Slide 77 text

THANK YOU! I’m Jeremy. See ya online! @jeremeamia • @phpbard @pnwphp • @azphp