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

Nodevember 2015: The dirty secrets of building ...

Nodevember 2015: The dirty secrets of building large, highly available, scalable HTTP APIs

Most HTTP APIs sites show how to implement the GET /hello sample and provide a list of links that developers can use to get more information about different topics.
While those are definitely useful, large APIs that are to be consumed by other developers span a range of cross-cutting concerns that is hard to be aware of when you start to build them. In this talk we will go over some of these concerns, such as authentication, authorization, documentation, validation, rate limiting, geo-redundancy, and no downtime deployments, and will provide specific examples based on what we do at Auth0.

Damian Schenkelman

November 14, 2015
Tweet

More Decks by Damian Schenkelman

Other Decks in Programming

Transcript

  1. Why? var  express  =  require('express');   var  app  =  express();

      app.get('/',  function  (req,  res)  {      res.send('Hello  World!');   });   var  server  =  app.listen(3000,  function  ()  {      var  host  =  server.address().address;      var  port  =  server.address().port;      console.log('Example  app  listening  at  http://%s:%s',  host,  port);   });
  2. Errors for developers {      "statusCode":  400,    

     "error":  "Bad  Request",      "message":  "Payload  validation  error:   'Expected  type  boolean  but  found  type   string'  on  property  enabled   (<code>true</code>  if  the  rule  is   enabled,  <code>false</code>   otherwise).",      "errorCode":  "invalid_body"   }
  3. ratify const  ZSchemaErrors  =  require('z-­‐schema-­‐errors');   const  errorReporters  =  ['headers',

     'query',  'path',   'payload'].reduce((current,  part)  =>  {      current[part]  =  ZSchemaErrors.init({/*...*/});      return  current;   },  {});   plugins.push({      register:  require('ratify'),      options:  {          errorReporters:  errorReporters,          /*...*/      }   });
  4. Leverage validation "enabled":  {   "type":  "boolean",   "description":  "<code>true</code>

     if   the  connection  is  enabled,   <code>false</code>  (default)  otherwise"   }
  5. limitd #port  to  listen  on   port:  9001   #db

     path   db:  /var/limitd/database   #define  the  bucket  types   buckets:      customers:          size:  10          per_second:  10
  6. 429 X-­‐RateLimit-­‐Limit   Maximum  amount   X-­‐RateLimit-­‐Remaining   How  many

     there  are  left   X-­‐RateLimit-­‐Reset   When  will  bucket  be  full  again
  7. patova plugins.push({      register:  require('patova'),      options:  {

             event:  'onPostAuth',  //  when  to  perform  the  limit  check          type:  'tenant',  //  bucket          address:  env.LIMITD_SERVER,          extractKey:  function(request,  reply,  done){              const  key  =  request.auth.credentials.__tenant;              done(null,  key);          }      }   });
  8. feature-change const  feature_change  =  require('feature-­‐change');   var  options  =  {

         expected:  function(cb){              mongo_search(mongo_opts,  cb);      },      actual:  function(cb){              es_search(es_opts,  cb);      },      logAction:  function(current_result,  new_result){              //  invoked  when  there  is  a  difference  in  the  results              //  (useful  for  logging)      }   };   feature_change(options,  function(err,  result){          //  this  is  the  original  callback  you  were  using  for  mongo          //  err  and  result  always  come  from  mongo_search   });
  9. AuthN & AuthZ • https://tools.ietf.org/html/rfc7519 • http://jwt.io/ • https://auth0.com/blog/2014/12/02/using-json- web-tokens-as-api-keys/

    • https://auth0.com/blog/2015/03/10/blacklist-json- web-token-api-keys/ • https://github.com/auth0/hapi-auth-jwt