Getting RESTless



presented by

ryan jarvinen / @ryanj

Used to run the developer program at [Eventbrite](

Realtime, multi-user experiences

## nodejs ![oaklandjs](
## code for america code for Oakland
## [sudoroom]( ![sudoroom](


  1. <3 EFF, digital rights
  2. fully homomorphic encryption
  3. tahoe-LAFS

Developer Advocates

one of 87 meetup groups


  • Intro to Meteor
  • Build a basic Meteor app
  • Test Client-Side Security for Meteor
### Requirements: Install [Meteorjs]( and [MongoDB]( curl | sh
Code du Jour [](



Data on the Wire

Don't send HTML over the network.
Just send data, let the client decide how to render it.

One Language


Database Everywhere

Use the same APIs on the client and the server.

Latency Compensation

On the client, use prefetching and model simulation to make it look like you have a zero-latency connection to the database.

Full Stack Reactivity

Make realtime your default.
All layers from DB to templates should make an event-driven interface available.

Embrace the Ecosystem

Meteor is Open Source and integrates with existing open source tools and frameworks (rather than replacing them).

Simplicity Equals Productivity

The best way to make something seem simple is to have it actually be simple.



Fibers, the Event Loop and Meteor

source: node-fibers

Smart Packages

meteor add bootstrap
meteor add handlebars
meteor add jquery
meteor add underscore
meteor add service-configuration
meteor add accounts-github
meteor remove insecure



npm install --global meteorite

no longer needed!

New: Meteor package system

Meteor 9.x includes a new Meteor package system (featuring Isobuild, Meteor Package Server)

  • publish your own packages
  • over 1800 community packages
meteor add <packagename>
meteor publish
meteor search <query>

Let's look at some code!

Client code and Server code

if (Meteor.isServer) {
if (Meteor.isClient) {
Showcase = new Meteor.Collection("showcase");

if (Meteor.isServer) {
  Meteor.publish("showcase-items", function () {
    return Showcase.find(); // share everything in the showcase

if (Meteor.isClient) {
# templates

Templates (HTML)


  {{> nav}}
  {{> list}}
  {{> submit}}
  {{> edit}}
  {{> view}}

Templates (HTML)

 <template name="list">
  <div class="showcase">
    {{#each items}}
      {{> item}}

Templates (HTML)

<template name="view">
<div id='modal_view' class="modal fade in"
  <div class="modal-header">
    <a href="#" data-dismiss="modal" class="close pull-right;">×</a>
    <h3 class="item_title">{{app_name}}</h3>
  <div class="modal-body">
    <div class'image_url'><a href='{{demo_url}}'><img src='{{image_url}}'/></a></div>
    <div class='name'>{{app_name}}</div>
    <div class='description'>{{description}}</div>
    <div class='authored_by'>By: <span class='author'>{{author}}</span></div>
    <div class='date'>Submitted on: {{date}}</div>
    <div class='score'>Score: {{score}}</div>
    <div class='source_url'>Source code: <a href='{{source_url}}'>{{source_url}}</a></div>
    <p><a href="{{clone_url}}" class="shift btn btn-large btn-inverse btn-block">Run on OpenShift <b class='icon-cog'></b></a></p>
  <div class="modal-footer">
    {{# if currentUser }}<a href="#" $('#modal_edit').modal('show') && $('#modal_view').modal('hide');" class="edit pull-left btn btn-info">Settings <b class='icon-wrench'></b></a>{{/if}}
    <a href="{{demo_url}}" onclick="console.log('Opening app...');" class="pull-right btn btn-primary">Visit <b class='icon-globe'></b></a>
    <a href="#" data-dismiss="modal" onclick="$('#modal_view').modal('hide');" class="btn pull-right">Cancel <b class='icon-remove'></b></a>

Templates (js)

Template.list.items = function () {
  var nav_config = Session.get('nav_settings');
  var sort_by = Session.get('sort_by');
  var sort_order = {};
  var filter = Session.get('filter');
  if (!filter || filter == undefined){ filter = '' };
  sort_order[sort_by] = nav_config[sort_by] || -1;
  return Showcase.find({ name: { $regex: filter, $options: 'i'}}, {sort: sort_order}).fetch();

Template.nav.username = function () {
  var u = Meteor.user();
  return u && u.profile &&;

  'click': function () {
    Showcase.update(Session.get("selected_item"), {$inc: {score: 5}});
  'click a.dec': function () {
    Showcase.update(Session.get("selected_item"), {$inc: {score: -5}});
  'click a.view': function () {

Protecting DB Access

  remove: function (userId, item) {
    var username = false;
      username = Meteor.users.findOne(userId);
    return ( == username || username == 'ryan jarvinen');
  insert: function (userId, item) {
    return (userId) ? true : false;
  update: function (userId, item, fieldNames, modifier) {
update: function (userId, item, fieldNames, modifier) {
  var username = false;
    username = Meteor.users.findOne(userId);
  if(item.score > 9000){
    // OVER 9000?!?!
    return false;
  }else if( _.isEqual(modifier, {$inc:{score: +5}})){
    //allow voting by anyone
    console.log('option1 - voter');
    return true;
  }else if( _.isEqual(modifier, {$inc:{score: -5}}) && item.score > 4 ){
    //allow voting by anyone
    console.log('option1 - voter');
    return true;
  }else if(username == 'ryan jarvinen') {
    //allow updates by admins (me) :-P
    console.log('option2 - admin');
    return true;
    //allow updates by owners
    console.log('option3 - owner');
    return ( username == ) ? true : false;

3rd party auth

var github_client_id = process.env.GITHUB_CLIENT || 'cc02855bd41dbfc4be72';
var github_client_secret = process.env.GITHUB_SECRET || '443ea5d64be6afada4acd946cf5b49878f4af4c8';
  service: "github"
  service: "github",
  clientId: github_client_id,
  secret: github_client_secret

Shipping Meteor


meteor deploy

Production flag

meteor --production


meteor bundle bundle.tar.gz

Docker Images

Thanks for following along!   --ryanj

link to slides: