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

APIs with Lumen, Guzzle, & Swagger

APIs with Lumen, Guzzle, & Swagger

Building a quality RESTful API can be challenging. Let's discuss a few best practices and how embracing three particular technologies — the Lumen framework (and related packages), the Guzzle HTTP library, and the Swagger (OpenAPI) Specification — can make it easier for you to implement your API and for your users to consume your API. That way, everyone can spend more time adding business value, instead of writing boilerplate code. #laravel #php

Jeremy Lindblom

July 29, 2016
Tweet

More Decks by Jeremy Lindblom

Other Decks in Programming

Transcript

  1. $method = ?; $endpoint = ?; $payload = ?; $status

    = ?; $app->{$method}($endpoint, function () { /* The “easy” part */ return response($payload, $status) });
  2. api.mygradebook.local × Create an assignment × Read assignments (single &

    multiple) × Update an assignment × Delete an assignment
  3. api.mygradebook.local POST /assignments - Create GET /assignments - List/Search GET

    /assignments/{id} – Read PATCH /assignments/{id} - Update DELETE /assignments/{id} - Delete
  4. 503

  5. 201

  6. 429

  7. URL

  8. 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
  9. 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
  10. Dingo API × Content negotiation × Authentication adapters (inc. JWT

    & OAuth 2) × API versioning (in the headers) × Rate limiting middleware × Response builder/transformers
  11. Versioned ROUTING $api = app('Dingo\Api\Routing\Router'); $api->version('v1', [], function ($api) {

    $api->get('/assignments', ...); $api->post('/assignments', ...); $api->patch('/assignments/{id}', ...); });
  12. RESPONSE BUILDERS + FRACTAL public function index() { $assgs =

    Assignment::all(); return $this->response ->collection($assgs, new AssgTransformer) ->withHeader('X-MyGB-Count', count($assgs)); }
  13. 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), ]; } }
  14. TRANSFORMED JSON RESULT { 'data': { 'id': 'c3ecf466-c7ce-4df1-b6dd-6ad74937e626', 'name': 'Reducing

    Fractions HW03', 'pointsPossible': 20, 'dueDate': '9/23/2016' } }
  15. DINGO Starter Project Lumen + Dingo + JWT Auth +

    CORS https://github.com/0plus1/lumendingojwtapi
  16. HTTP CLients × file_get_contents (and stream contexts) × cURL ×

    HTTP extension × Libraries: Buzz, Requests, Guzzle
  17. 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+ )
  18. Configuring Guzzle $client = new GuzzleHttp\Client([ 'base_uri' => 'https://api.mygradebook.local', 'auth'

    => ['Si39fSKkjqba459', 'dl2+aScKw/asjASD721'], 'headers' => [ 'Accept' => 'application/vnd.mygradebook.v1+json', ] ]);
  19. POSTING aN ASSIGNMENT $response = $client->post('assignments', [ 'form_params' => [

    'name' => 'Reducing Fractions HW03', 'pointsPossible' => 20, 'dueDate' => '2016-09-23' ] ]); echo $response->getStatusCode(); //> 201
  20. Swagger × Representation of your RESTful API × JSON or

    YAML × Large ecosystem × Documentation generation × Code generation × Gateway integration (e.g., Amazon API Gateway)
  21. 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"], ...
  22. SWAGGER DOCS (Part 2 - PATHS) "paths": { "/": {

    "get": { "parameters": [...] "responses": {...} } "post": {...}, ... } }
  23. 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 }, ...
  24. SWAGGER DOCS (Part 4 - RESPONSES) "200": { "description": "List

    all pets", "schema": { "title": "Pets", "type": "array", "items": {"$ref": "#/definitions/Pet"} } }, ...
  25. SWAGGER DOCS (Part 5 - Definitions) "Pet": { "type": "object",

    "properties": { "name": {"type": "string"}, "birthday": {"type": "integer", "format": "int32"} } }, ...
  26. INstalling & USING Bootprint > npm install -g bootprint >

    npm install -g bootprint-openapi > bootprint openapi ./swagger.json ./docs
  27. Generate Swagger FROM CODE × Annotate your code for Swagger

    × https://github.com/zircote/swagger-php > swagger app -o public/swagger.json
  28. AnNotations /** * @SWG\Post( * path="/assignments", * operationId="createAssignment", * summary="Create

    an assignment.", * <<< PARAMETERS >>> * @SWG\Response( * response=201 * ) * ) */ public function create(Request $request) {...}
  29. AnNotations /** * ... * @SWG\Parameter( * name="name", * in="formData",

    * description="Name of the assignment.", * required=true, * type="string" * ), * ... */
  30. 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)
  31. USING My Swagger-lite Guzzle Client $response = $client->createAssignment([ 'name' =>

    'Reducing Fractions HW03', 'pointsPossible' => 20, 'dueDate' => '2016-09-23' ]); echo $response->getStatusCode(); //> 201
  32. 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
  33. 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/
  34. 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