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

Scaleconf 2016: The dirty little secrets of bui...

Scaleconf 2016: The dirty little secrets of building large, highly available, scalable HTTP APIs

When you first start building an API for a new product you mostly focus on getting an MVP ready, with the goal of shipping as soon as possible so you can get feedback from customers. If you are lucky enough, your product will be successful and you will have to start worrying about things like authentication, authorization, documentation, validation, rate limiting, geo-redundancy, and no downtime deployments. In this talk I will go over some real life examples of our experience evolving our APIs at Auth0 and some of the tools we use for that.

Damian Schenkelman

March 11, 2016
Tweet

More Decks by Damian Schenkelman

Other Decks in Technology

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. Route { method: 'GET', path: '/api/v2/clients/{id}', config: { auth: {

    strategy: 'jwt', scope: ['read:clients', 'read:client_keys'] }, } }
  6. limitd #port to listen on port: 9001 #db path db:

    /var/limitd/database #define the bucket types buckets: customers: size: 10 per_second: 10
  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. Password Hashing app.use('/login', (req, res) => { // fetch the

    user by req.username from db db.users.findOne({ email: req.body.email }, (err, user) => { ... // compare bcrypt for req.password to db hash const success = bcrypt.compare(req.body.password, user.passwordHash); res.send(success ? 200 : 401); }); });
  9. BaaS app.use('/login', (req, res) => { // fetch the user

    by req.username from db db.users.findOne({ email: req.body.email }, (err, user) => { ... // compare bcrypt for req.password to db hash baas.compare(req.body.password, user.passwordHash).then((e success) => { res.send(err || !success ? 401 : 200); }); }); });
  10. Cost comparison Price / (1M req) #req per sec /

    vCPU t2-micro $0.36 10.00 t2-medium $0.76 9.50 c4-large $1.53 10.00 c3-8xlarge $1.64 8.88
  11. 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 });
  12. 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