Rapid API development examples for Impress Application Server / Node.js (jsfwdays 2014)

734 views
630 views

Published on

Application code and the server configuration examples with file-system access, RAM state, database access and parallel asynchronous processing of different resource types by stateful and stateless API requests.

Published in: Software, Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
734
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Rapid API development examples for Impress Application Server / Node.js (jsfwdays 2014)

  1. 1. Rapid API development examples for Impress Application Server (Node.js) Timur Shemsedinov Research Institute of System Technologies (UA, Kiev), MetaSystems Inc. mailto:timur.shemsedinov@gmail.com https://github.com/tshemsedinov/impress http://habrahabr.ru/users/marcusaurelius/ https://www.npmjs.org/package/impress
  2. 2. Impress Application Server is: • Scaling transparent to applications • Application isolation (memory configuration database) • Deployment or update code without restart • Highload serving static files from memory (gzip, js minification, etc.) • URL-rewriting using RegExp, with internal redirection or sending external HTTP-requests (reverse proxying) • Virtual hosts with multi-domain support (e.g.: *.domain.com) • Executable code and static caching in RAM • TCP port multiplexing and demultiplexing between applications • Server-Sent Events and WebSocket support • Stateless API (REST) and stateful API (RPC) support with IP-sticky and Cookie-sticky to associated processes and global state sync. • Many other features: sessions, rotating logging, IPC and ZeroMQ, database access drivers, etc.
  3. 3. Rapid API development examples General principles: • Request routing based on file system • Each handler in separate file, handler inherit/override mechanism • Handlers need not prepare request execution environment, such as import/load libraries, establish db connections, build memory structures, etc., request will come to ready application environment and handler will contain just applied code • Each application have own isolated context and in-memory state • Long and batch workers in separate threads (forking by Impress Application Server into parallel processes) • Global cross-server interprocess communication based on system IPC and ZeroMQ to translate events, synchronize state, use reactive approach and actor-pattern
  4. 4. 1. Simple JSON handler /example/app/examples/simple/jsonPost.json/post.js module.exports = function(client, callback) { client.context.data = { a: 1 }; callback(); } --------------------------------------------------------------- HTTP POST /example/app/examples/simple/jsonPost.json { "a": 1 }
  5. 5. 2. Simple AJAX handler with template /examples/simple/ajaxTest.ajax/get.js module.exports = function(client, callback) { client.context.data = { parameterName: client.query.parameterName, }; callback(); } --------------------------------------------------------------- /examples/simple/ajaxTest.ajax/html.template AJAX Request with parameter returning back in template<br> parameterName: @parameterName@ --------------------------------------------------------------- HTTP GET /examples/simple/ajaxTest.ajax?parameterName=parameterValue AJAX Request with parameter returning back in template<br> parameterName: parameterValue
  6. 6. 3. Client-side example /js/init.js $.post('/examples/simple/jsonPost.json', { parameterName: "paramaterValue" }, function(res) { console.log(res.valueLength); } ); --------------------------------------------------------------- HTTP POST /example/app/examples/simple/jsonPost.json { "status": 1, "parameterValue": "paramaterValue", "valueLength": 14, "requestCounter": 3 } --------------------------------------------------------------- Console: 14
  7. 7. 4. File system access example /examples/simple/fsAccess.json/get.js module.exports = function(client, callback) { var filePath = client.hostDir+client.path+'/test.txt'; fs.readFile(filePath, 'utf8', function(error, data) { client.context.data = { fileContent: data, dataLength: data.length }; callback(); }); } --------------------------------------------------------------- HTTP GET /examples/simple/fsAccess.json { "fileContent": "?Example text file", "dataLength": 18 }
  8. 8. 5. HTTP-request from API handle example /examples/simple/httpRequest.json/get.js module.exports = function(client, callback) { var req = impress.http.request({ hostname: 'google.com', port: 80, path: '/', method: 'get' }, function(response) { var data = ''; response.on('data', function(chunk) {data=data+chunk;}); response.on('end', function() { client.context.data = data; callback(); }); } ); req.on('error', function(e) { client.context.data = "Can't get page"; callback(); }); req.end(); }
  9. 9. 6. MongoDB (read) access example /examples/mongodb/getData.json/get.js module.exports = function(client, callback) { dbAlias.testCollection.find({}).toArray( function(err, nodes) { client.context.data = nodes; callback(); } ); } --------------------------------------------------------------- HTTP GET mongodb/getData.json [ { "_id": "53547375894c3d3022000001" } ]
  10. 10. 7. MongoDB write and metadata examples /examples/mongodb/insertData.json/get.js module.exports = function(client, callback) { dbAlias.testCollection.insert(client.query, function(err) { client.context.data = !err; callback(); }); } --------------------------------------------------------------- /examples/mongodb/getCollections.json/get.js module.exports = function(client, callback) { dbImpress.connection.collections(function(err, collections) { var items = []; for (var i = 0; i < collections.length; i++) { items.push(collections[i].collectionName); } client.context.data = items; callback(); }); }
  11. 11. 8. SQL-query (MySql) access example /examples/mysql/getCities.json/get.js module.exports = function(client, callback) { dbAlias.query( 'select * from City', function(err, rows, fields) { client.context.data = { rows:rows, fields:fields }; callback(); } ); }
  12. 12. 9. Async parallel resource access example /examples/complex/getFsMongoRequest.json/get.js module.exports = function(client, callback) { impress.async.parallel({ file: function(callback) { var filePath = client.hostDir+client.path+'/test.txt'; fs.readFile(filePath, 'utf8', function(error, data) { callback(null, data); }); }, request: function(callback) { var req = impress.http.request({ hostname: 'google.com', port: 80, path: '/', method: 'get' }, function(response) { var data = ''; response.on('data', function(chunk) { data = data+chunk; }); response.on('end', function() { callback(null, data); }); } ); req.on('error', function(e) { callback(null, "Can't get page"); }); req.end(); }, ...
  13. 13. ...previous example end /examples/complex/getFsMongoRequest.json/get.js ... mongo: function(callback) { dbAlias.testCollection.find({}).toArray(function(err, nodes) { callback(null, nodes); }); } }, function(err, results) { client.context.data = results; callback(); }); } --------------------------------------------------------------------------------- { "mongo": [ { "_id": "53547375894c3d3022000001" } ], "file": "?Example text file", "request": "<HTML><HEAD><meta http-equiv="content-type" content="text/html; charset=utf-8">n<TITLE>302 Moved</TITLE></HEAD><BODY>n <H1>302 Moved</H1>nThe document has movedn <A HREF="http://www.google.com.ua/?gws_rd=cr&amp; ei=OWVWU5nHOqOc4wTbjYDgBw">here</A>.rn</BODY></HTML>rn" }
  14. 14. 10. Stateful API handler example /examples/memory/stateful.json/get.js module.exports = function(client, callback) { application.stateTest = application.stateTest || { counter: 0, addresses: [] }; application.stateTest.counter++; application.stateTest.addresses.push( client.req.connection.remoteAddress ); client.context.data = application.stateTest; callback(); }
  15. 15. 11. SSE handle example /examples/events/connect.sse/get.js module.exports = function(client, callback) { client.sse.channel = 'TestEventStream'; callback(); } --------------------------------------------------------------- /js/init.js var sse = new EventSource("/examples/events/connect.sse"); sse.addEventListener("TestEventStream", function(e) { console.dir({ event: e.event, data: e.data }); });
  16. 16. 12. WebSocket handler example /examples/events/connect.ws/get.js module.exports = function(client, callback) { var connection = client.res.websocket.accept(); connection.send('Hello world'); connection.on('message', function(message) { connection.send('I am here'); }); connection.on('close', function(reasonCode, description) { console.log('disconnected'); }); callback(); } --------------------------------------------------------------- /js/init.js ws = new WebSocket("ws://127.0.0.1:80/examples/events/connect.ws"); ws.onopen = function() {}; ws.onclose = function() {}; ws.onmessage = function(evt) { console.log("Message from server: "+evt.data); }
  17. 17. API and FS introspection screens
  18. 18. Deployment patterns • Installation script with deployment recomendations • Applications Server Configuration /config/*.js • Start strategies (single, multiple, specialization, sticky) • Multithreading parameters: cluster.js • Network interfaces and port configuration: servers.js • Sandboxes configuration, plugins and access • Impress Applied Controller configuration: cloud.js • Logging configuration: log.js • Application configuration /applications/name/config/*.js • Database access parameters: databases.js • Virtualhosts: hosts.js • URL-rewriting and reverse proxy configuration: routes.js • Session parameters: sessions.js • Static files and caching parameters: files.js • Application specific configuration files
  19. 19. Server installation (node.js + Impress) CentOS 6.5 (64bit) minimal curl http://.../impress/install.sh | sh --------------------------------------------------------------- #!/bin/bash yum -y update yum -y install wget yum -y groupinstall "Development Tools" cd /usr/src wget http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gz tar zxf node-v0.10.26.tar.gz cd node-v0.10.26 ./configure make make install ln -s /usr/local/bin/node /bin ln -s /usr/local/bin/npm /bin mkdir /impress cd /impress npm install impress
  20. 20. Application Server as Linux Daemon If installing Impress into absolute path /impress Run /impress/bin/install.sh for: • Setup and configure as Linux daemon • Run at system startup • Auto-restart daemon workers on fails Run /impress/bin/uninstall.sh for: • Stop Application Server • Remove from system startup • Remove Daemon from system After install as a service (daemon) you can use: service impress start service impress stop service impress restart service impress update service impress status
  21. 21. Application Server Configuration /config/cloud.js module.exports = { name: "PrivateCloud", type: "standalone", controller: "127.0.0.1", pubSubPort: "3000", reqResPort: "3001", health: "2s" } --------------------------------------------------------------- /config/cluster.js module.exports = { check: "http://127.0.0.2/", name: "C1", cookie: "node", strategy: "multiple", // single, specialization, sticky workers: os.cpus().length, gcInterval: 0 }
  22. 22. Network interfaces & ports config /config/servers.js module.exports = { www: { protocol: "http", address: "127.0.0.1", port: 80, applications: ["example", "host2"], nagle: true, slowTime: "1s" }, ssl: { protocol: "https", address: "127.0.0.1", port: 443, key: "example.key", cert: "example.cer" } }
  23. 23. Plugins configuration /config/plugins.js module.exports = [ "db", "db.schema", "db.mongodb", "db.memcached", "db.mysql", "db.mysql.schema", "impress.log", "impress.security", "impress.security.mongodb", "impress.mail", "impress.uglify", "impress.health", "impress.cloud", "impress.geoip", "impress.websocket", "impress.sse" ]
  24. 24. Logging and sandbox configuration /config/log.js module.exports = { keepDays: 10, writeInterval: "3s", writeBuffer: 64*1024, fileTypes: [ "access", "error", "debug", "slow" ] } --------------------------------------------------------------- /config/sandbox.js module.exports = { modules: [ 'global', 'console', 'process', 'impress', 'db', 'domain', 'crypto', 'geoip', 'os', 'Buffer', 'stream', 'nodemailer', 'net', 'http', 'https', 'dgram', 'dns', 'url', 'path', 'fs', 'util', 'events', 'iconv', 'querystring', 'zlib', 'async' ]}
  25. 25. Virtualhosts and URL-rewriting config /applications/applicationName/config/hosts.js module.exports = [ "127.0.0.1", "mydomain.com", "*.domainname.com", ] --------------------------------------------------------------- /applications/applicationName/config/routes.js module.exports = [ { url: "/api/(one|two)/(.*)", rewrite: "/example/[1].json?par1=[2]" }, { url: "/api/(name1|name2|name3)/(.*)", rewrite: "/api/[1]/[2]", host: "example.com", port: 80, slowTime: "1s" } ]
  26. 26. Database access configuration /applications/applicationName/config/databases.js module.exports = { mongoTest: { url: "mongodb://hostName:27017/databaseName", slowTime: "2s", collections: ["collection1", "collection2"], security: true, alias: "alias1" }, system: { url: "mysql://user:password@localhost/dbName", slowTime: 1000, alias: "aliasName" } }
  27. 27. Session and static files serving config /applications/applicationName/config/sessions.js module.exports = { anonymous: true, cookie: "SID", characters: "ABCDEFGH...fghijkl...456789", length: 64, persist: true, database: "impress" } --------------------------------------------------------------- /applications/applicationName/config/files.js module.exports = { minify: false, static: [ "*/css/*", "*/images/*", "*/js/*", "*/favicon.ico", "*/favicon.png" ] }
  28. 28. Examples: Demo Applications
  29. 29. Thanks for attention! Questions please Timur Shemsedinov Research Institute of System Technologies (UA, Kiev), MetaSystems Inc. mailto:timur.shemsedinov@gmail.com http://habrahabr.ru/users/marcusaurelius/ https://www.npmjs.org/package/impress https://github.com/tshemsedinov/impress

×