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

API Tips from the Frontline

API Tips from the Frontline

Starting to write an API is an easy task, but you quickly stumble upon many obstacles and hard decisions. How to manage result pagination and input errors? How to handle write operations and file uploads? Join me as I share my tricks that allowed me to ship high-profile projects in record time while keeping the code clean and maintainable.

Anna Filina

May 25, 2017
Tweet

More Decks by Anna Filina

Other Decks in Programming

Transcript

  1. Write • POST /products • PUT or PATCH /products/1 •

    DELETE /products/1 • Version your APIs: ◦api.example.org/v1/products ◦Headers also an option.
  2. Multiple Formats • xml, json, html, etc. • Can use

    1 endpoint with Accept header. • Can send version, pagination & language info using headers too.
  3. Request Example: Add POST /products HTTP/1.1 Host: api.example.org Content-Type: application/json;

    charset=UTF-8 { "data": { "name": "Overwatch", "price": 49.99 } }
  4. Upload • Use tools, don't DIY (do it yourself). •

    Client-side: Plupload ◦Step 1: upload temp file. ◦Step 2: give file path to next API request. • Server-side: Guzzle.
  5. Plupload var uploader = new plupload.Uploader({ runtimes: 'html5,html4', max_file_size: '5mb',

    url: '/api/upload', filters: [{extensions: 'jpg,png,jpeg'}] }); uploader.init();
  6. Guzzle <?php $url = 'http://example.org/profiles/1/edit'; $request = $client->createRequest('PATCH', $url); $file

    = new PostFile('i.jpg', fopen('/path', 'r')); $body = $request->getBody(); $body->setField('data', ['first_name':'Anna']); $body->addFile($file); $response = $client->send($request);
  7. Status Codes • Don't confuse API & HTTP codes. •

    2xx success. • 3xx redirect. • 4xx client error. • 5xx server error. • Send API-specific code in body.
  8. Example of Error Status: 400 Content-Type: application/json; charset=UTF-8 { "errors":

    [{ "code": 1001, "message": "Price must be greater than 0." }] }
  9. Guzzle Test // tests/ApiProductTest.php public function test_GetOneProduct_ReturnsSuccess() { $client =

    new Client(); $response = $client->get('http://example.org/products/1', [ 'exceptions' => false, 'headers' => ['Accept' => 'application/json'] ]); $this->assertEquals(200, $response->getStatusCode()); // ... }
  10. Testing Tips • Create separate database for tests. • Write

    tests before you code: ◦TDD. ◦Contract between you and client dev.
  11. Multiple Methods • Don't send username/password in each request. ◦Especially

    with untrusted 3rd parties. ◦Especially if no SSL. • You can have multiple auth methods for one API. • Sessions similar to tokens.
  12. OAuth2 • SSL required. • Advanced features like access scope.

    • Can be overkill if you need basic features. • Private credentials.
  13. OAuth2 - Conceptual Diagram User Client app
 (php/js/mobile) API Request

    Forward Validate Create token Store token Login form Login token user/pass
  14. Digest • Its own encryption. • Easy to implement. •

    No replay (nonce). • Comes out-of-the-box with some frameworks.
  15. Progressive Rewrite • Rewrite one component/module at a time. •

    Start with whatever has fewer dependencies (or most critical). • Delete dead code. • Copy production data for dev environment.
  16. Services vs Libraries • Services: GET /products?category=game • Libraries/classes: ◦$table->getApiList(

    ["category" => "game"] ); ◦Bypass HTTP ◦Can fetch without pagination. ◦Can hydrate to models.
  17. Tools • I use MVC frameworks & ORMs. • Aside

    from frameworks, I prefer small libraries that don't do too much magic.
  18. Reuse & Standardize • Goal: streamline endpoint creation. • Automate

    request parameters extraction. • Automate query generation based on parameters. • Keep things fully customizable. • Decouple from framework.
  19. Benchmark • Give Tideways or Blackfire a spin. • Make

    performance part of your test suite. • In dev/test mode, use a perf block.
  20. Performance Tips • Don't use lazy loading. Example: $product->getPhotos(). •

    Craft your own joins and carefully select fields. • Avoid ORM built-in hydration for read operations.
  21. Performance Tips • Use API keys even for public endpoints

    (DDoS mitigation). • Put stuff in Memcached/Redis (especially blocked keys). • HTTP server can check headers.
  22. Useful Links • Standard API format
 http://jsonapi.org/format/ • Digest implementation


    http://php.net/manual/en/features.http- auth.php • Book "Build APIs You Won't Hate"
 https://leanpub.com/build-apis-you- wont-hate