Fullstack developer from Toronto
Core developer on Angular
BSc in Computer Science
Born in Helsinki, Finland
JavaScript, Dart, Ruby and Clojure
What exactly is a SPA?
The role of the API
Popular backend technologies
Crazy 3rd Party Tools
New web app paradigm
dynamic client-side websites
The only delivers data
No more full page refreshes!
Let's see something in action then...
You craft your data using XML
XSLT turns that XML into HTML
The webpage renders
Data is separate from HTML
Acts as a database transport layer
No more templates are delivered--only data
Easier to cache, scale & secure
Less data == less bandwidth
Yes of coarse it does, but...
The backend's job is to deliver data
Not to fully parse the HTML output for a page
So it's basically an API
But do popular frameworks craft good APIs?
Dynamic websites can still render templates
PHP, Rails, Express all do it
But better to look for API generation tools
And leave the template processing up to the SPAs!
<numbers>
<number>1</number>
<number>2</number>
<number>3</number>
<number>4</number>
<number>5</number>
<number>6</number>
<number>7</number>
<number>8</number>
<number>9</number>
</numbers>
<xsl:template match="/">
<html><body>
...
<xsl:for-each select="numbers">
<div>
<xsl:value-of select="number"/>
</div>
</xsl:for-each>
...
</body></html>
</xsl:template>
http://www.ng-tube.com
Uses a public API to do it's thing
The API code is completely separate
Easily over 100 frameworks out there
We want an easy API generation tool
Let's explore some frameworks
Rails
Sinatra
Ruby is the main programming language
Great for building large web apps
Huge ecosystem of tools and plugins
Great testing mechanisms
Fast moving, configurable
Create a scaffold
Load up the website
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
def index
@books = Book.all
end
def show
end
def load_book
@book = Book.find(params[:id])
end
end
Works great for building a complex API
API template code can be reused
# views/api/books/index.json.jbuilder
json.books = @books
# views/api/books/show.json.jbuilder
json.book = @book
A smaller subset of features for Rails
But designed for API building
Better suited for something like AngularJS / Ember
Smaller applications, less code involved
Less conventional, more to the point
require 'sinatra'
require 'json/ext'
require 'sqlite3'
get '/api/books' do
content_type :json
rows = []
$db.execute( "select * from books" ) do |row|
rows.push(row)
end
rows.to_json
end
get '/api/books/:id' do
id = params[:id]
# ...
end
Express
Sails
Other mentions
Simple, basic, barebones backend framework
Lightweight, easy to use
Runs on NodeJS
Organize the code yourself
var app = express();
var db = new sqlite3.Database("db.sqlite3");
var routes = require('./bookRoutes')(db);
app.get('/api/books', routes.index);
app.post('/api/books', routes.create);
app.get('/api/books/:book_id', routes.show);
app.put('/api/books/:book_id', routes.update);
app.delete('/api/books/:book_id', routes.destroy);
app.param('book_id', routes.findBook);
db.serialize(function() {
express.listen(8888);
});
module.exports = function(db) {
return {
index : function(req, res) {
var rows = [];
db.each("SELECT * FROM books", function(err, row) {
rows.push(row);
}, function() {
res.json(rows);
});
},
show : function(req, res) {
res.json(req.book);
}
};
};
Progressive community
Lots of plugins
Rails-like framework for building node backends
Scaffolding, searching capabilities, TTD-oriented
Rich ORM and data mapping capabilities
module.exports = {
adapter: 'sails-sqlite3',
attributes: {
title: { type: 'string', required: true },
description: { type: 'text', required: true },
isbn: { type: 'string', required: true }
}
};
// controllers/BookController.js
module.exports = {
index: function(req, res) {
Book.find(function(err, books) {
res.json({ books: books });
});
},
create: function(req, res) { ... }
};
// config / routes.js
module.exports.routes = {
'get /users.json': {
controller : 'Book',
action : 'index'
},
'post /books.json': {
controller : 'Book',
action : 'create'
}
//...
};
Slim
Raw PHP
Nice router code for making an API
<?php
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/api/books', 'getBooks');
$app->get('/api/books/:id', 'getBook');
$app->post('/api/books', 'addBook');
$app->put('/api/books/:id', 'updateBook');
$app->delete('/api/books/:id', 'deleteBook');
$app->run();
?>
<?php
function getBooks() {
$sql = "select * FROM books";
$query = $db->query($sql);
$books = $query->fetchAll(PDO::FETCH_OBJ);
echo json_encode($books);
}
function getBook() {}
?>
Effectively Slim minus the routing
Tricky to route without Apache/NGINX
Worth using a framework to do so
Firebase
Backendless
Built.io
Mashape
Firebase is a realtime Backend As a Service
Use the same backend for AJAX + realtime
Change the URL routing and go from there
.constant('API', 'https://booksapi.firebaseio.com/')
A bigger backend ecosystem
Uses its own library code
Comes packed with lots of features
self.submit = function(data) {
var db = Backendless.Persistence.of(Book);
var instance = new Book(data);
instance.save(instance);
function Book(data) {
this.title = data.title;
this.description = data.description;
this.isbn = data.isbn;
}
};
Another BaaS System
Also uses its own library code
.controller('BooksCtrl', function() {
var myQuery = new Built.Query('book');
myQuery.exec({
onSuccess: function(books) {
self.entries = books;
}
});
});
.controller('BooksForm', function() {
self.submit = function(data) {
var Book = Built.Object.extend('book');
book = new Book();
book.set(data);
book.save();
};
});
Large web wrapper for APIs
One single API point for everything
var url = "https://community-isbndb.p.mashape.com/" +
"books.xml?index1=isbn&value1=ISBN_VALUE";
unirest.get(url).header("X-Mashape-Key", "...KEY...")
.end(function (bookMatches) {
//data ...
});
Zapier
Kimono Labs
Amazon Mechanical Turk
Make your SPA use Zapier
Zapier can then communicate with other services
Maybe we can hook into Mechanical Turk using JSON?
Think of something crazy stupid to automate
Turn a website into an API
What about if we wanted to collect all books for ourselves?