Marco Rico Gomez | Weigle Wilczek GmbHLeichtgewichtige Webanwendungen mit dem MEAN Stack
Agenda
berblick MEAN-StackArchitektur einer modernen Webanwendung
Warum?Was spricht fr diesen Technologiestack
Wie?Der Server
Datenmodell und -speicherung
Frontend
Tooling
ca. 1 min.
Technologiestack fr die Entwicklung von Webanwendung
Valeri Karpov, April 2013
Was ist der MEAN Stack?
Kein Produkt oder Standard!
Sammlung von Technologien fr den Entwicklung von WebanwendungenAnlehnung an LAMP-Stack.
Begriff wurde erstmals von Valeri Karpov im April 2013 in einem Blogpost erwhnt.
M
E
A
N
MongoDB: 2007 / 2010 (prod ready)Express: (932 SLC + 1143 SLOC)AngularJs: 2009Node.js: 2009
Architektur
Single-Page Applikation
UI-Logik wird vom Client berechnet
Server ist zustandslos und liefert nur Daten
HTML Templates, JS, CSS usw. knnen separat von einem WebServer geliefert werden.
Warum?
Welche Grnde sprechen fr den MEAN-Stack?
Node.JS/ Express.JSapp.get('/api/foo/:bar', function (req, res, next) { res.send({ foo: 'bar' });});
AngularJS: angular.controller('FooCtrl', function ($scope, $resource) { var Foo = $resource('/api/foo/:bar', { bar: '@id'}); $scope.bar = Foo.get({bar: 'bar'});});
MongoDBdb.foo.find({ foo: 'bar' });
Eine Programmiersprache
JavaScript Die Sprache des WebsAlle Entwickler sprechen die gleiche Sprache
Don't repeat yourself. Zahlreiche JavaScript Bibliotheken knnen sowohl auf dem Client als auch auf dem Server verwendet werden
Ein Datenformat (JSON)
{ "title": "Foo Bar", "type": 12}
{ "title": "Foo Bar", "type": 12}
{ "title": "Foo Bar", "type": 12}
Einheitliches Datenformat
Client/Server und Datenbank sprechen JSON.
Keine Schemamigrationen
Schema wird in der Anwendung definiert.
ALTER TABLE foo ADD COLUMN bar VARCHAR(200) NOT NULL;
Geringer Resourcenverbrauch
kein (wenig) UI-Rendering auf dem Server
ereignisgesteuerte Architektur / Non-blocking I/O
Non-blocking I/O
Non-blocking I/O
vs.
Blocking I/O
Wie?
app.js
// declare module dependencies ...var express = require('express');// more ...
var app = express();
// configure express ...app.use(express.logger('dev'));app.use(express.bodyParser());app.use(app.router);// more ...
// define routes ...app.get('/', routes.index);app.get('/users', user.list);
// ... and go!!http.createServer(app).listen(app.get('port'), function() { console.log('Express server listening on port ' + app.get('port'));});
Express API (HTTP Verben)
app.get(path, [callback...], callback)
app.post(path, [callback...],callback)
app.put(path, [callback...], callback)
app.delete(path, [callback...],callback)
...
callback = function (req, res, next) { }
app.get('/api/foo', function (req, res) { res.send({ foo: 'bar' });});
Routen sind einfache Funktionen
app.all("/app/*", function (req, res, next) { if (isUserLoggedIn) next(); else res.redirect('/login');});
Routen filtern (Wildcards)
app.put("/api/task/:id", function(req, res, next) { res.send("Your request id: " + req.params.id);});
Routen (Variablen)
MongoDB
{ "name": "Create something beautiful", "dueBy": Date(2013, 10, 1), "priority": 2, "done": false, "subTasks": [ { "name": "blabla", "done": true, }, { "name": "blabla", "done": false } ]}
dokumentenorientiert
schemafrei
Join-less
verschachtelte Datenstrukturen
16 MB Limit beachten !
{ "name": "Create something beautiful", "dueBy": Date(2013, 10, 1), "priority": 2, "done": false, "subTasks": [ { "name": "blabla", "done": true, }, { "name": "blabla", "done": false } ]}
Adhoc-Abfragen
db.tasks.find({ done: false, dueBy: { $gte: new Date(2013, 10, 1), $lt: new Date(2013, 11, 1) }, priotity: { $in: [0, 2] }, subTasks: { $exists: true } }).sort({dueBy: -1}).limit(10);
Mongoose
var mongoose = require('mongoose');
var Task = mongoose.model('Task', { name: { type: String, required: true }, done: { type: Boolean, default: false }, dueBy: Date, priority: Number});
Validierung
Task.schema.path('priority') .validate(function (value) { return (value >= 0 && value