├── LICENSE ├── README.md ├── apigee └── hello │ ├── README.md │ └── apiproxy │ ├── hello.xml │ ├── proxies │ └── default.xml │ ├── resources │ └── node │ │ └── server.js │ └── targets │ └── default.xml └── node ├── echo ├── README.md └── server.js ├── employees ├── README.md ├── config-template.js ├── package.json └── server.js ├── hello ├── README.md └── server.js ├── mashup ├── README.md ├── mashup.js └── package.json └── method-override ├── README.md ├── package.json └── server.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Apigee Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apigee Node.js Samples 2 | 3 | These are some sample Apigee and Node.js applications for the Node.js support 4 | in the Apigee API Platform. 5 | 6 | To deploy these bundles, install [apigeetool](https://github.com/apigee/api-platform-tools) and follow the directions in each sample's README. 7 | 8 | # Node Samples 9 | 10 | These samples are unmodified Node.js applications that will run locally or in 11 | the Apigee Platform. The `apigeetool deploynodeapp` script will package these 12 | programs up in a form that may be deployed to Apigee, and deploy them. 13 | 14 | # Apigee Samples 15 | 16 | While the "Node Samples" are generic Node.js applications that `apigeetool` 17 | turns into Apigee API proxies on deployment, these samples are API proxies that 18 | contain Node.js applications. They do the same thing, but by deploying this 19 | way, we get access to other features of the Apigee API Platform. 20 | -------------------------------------------------------------------------------- /apigee/hello/README.md: -------------------------------------------------------------------------------- 1 | ## "Hello" Apigee Node.js Sample Proxy Bundle 2 | 3 | This sample shows how to integrate a Node.js script into an API proxy. This application simply prints out "Hello, World!". 4 | 5 | To deploy: 6 | 7 | apigeetool deployproxy -u USERNAME -p PASSWORD \ 8 | -o ORG -e test -n hello -d . 9 | 10 | Where: 11 | 12 | * USERNAME: Your Apigee user name 13 | * PASSWORD: Your Apigee password 14 | * ORG: Your Apigee organization name 15 | 16 | To run: 17 | 18 | curl http://ORG-test.apigee.net/hello 19 | 20 | -------------------------------------------------------------------------------- /apigee/hello/apiproxy/hello.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apigee/hello/apiproxy/proxies/default.xml: -------------------------------------------------------------------------------- 1 | / default default -------------------------------------------------------------------------------- /apigee/hello/apiproxy/resources/node/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var svr = http.createServer(function(req, resp) { 4 | resp.writeHead(200, { 'Content-Type': 'text/plain' }); 5 | resp.end('Hello, World!\n'); 6 | }); 7 | 8 | svr.listen(9000, function() { 9 | console.log('The server is listening on port 9000'); 10 | }); 11 | -------------------------------------------------------------------------------- /apigee/hello/apiproxy/targets/default.xml: -------------------------------------------------------------------------------- 1 | node://server.js -------------------------------------------------------------------------------- /node/echo/README.md: -------------------------------------------------------------------------------- 1 | # "Echo" Apigee Node.js Sample 2 | 3 | This application is an echo service that responds with a JSON object that describes the incoming request. 4 | 5 | To deploy: 6 | 7 | apigeetool deploynodeapp -u USERNAME -p PASSWORD \ 8 | -o ORG -e test -n echo -d . 9 | -m server.js -b /echo 10 | 11 | Where: 12 | 13 | * USERNAME: Your Apigee user name 14 | * PASSWORD: Your Apigee password 15 | * ORG: Your Apigee organization name 16 | 17 | To use: 18 | 19 | curl -X POST \ 20 | -H "Test-Header: 123" \ 21 | -d "Hello, world!" \ 22 | "http://ORG-test.apigee.net/echo/some/path?foo=bar" 23 | -------------------------------------------------------------------------------- /node/echo/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var server = http.createServer(function (req, resp) { 4 | var body = { 5 | origin: req.socket.remoteAddress, 6 | httpVersion: req.httpVersion, 7 | headers: req.headers, 8 | trailers: req.trailers, 9 | method: req.method, 10 | url: req.url 11 | }, 12 | data = ''; 13 | 14 | resp.writeHead(200, { 'Content-Type': 'application/json' }); 15 | 16 | req.setEncoding('utf8'); 17 | req.on('data', function (chunk) { 18 | data += chunk; 19 | }); 20 | 21 | req.on('end', function () { 22 | if (data) { 23 | body.data = data; 24 | } 25 | 26 | resp.end(JSON.stringify(body, null, 2)); 27 | }); 28 | 29 | }); 30 | 31 | server.listen(9000, function () { 32 | console.log('The server is listening on port 9000'); 33 | }); 34 | -------------------------------------------------------------------------------- /node/employees/README.md: -------------------------------------------------------------------------------- 1 | # "Employees" Apigee Node.js Sample 2 | 3 | A simple API built using Express and Usergrid that maintains a 4 | database of "employee" names and phone numbers. 5 | 6 | To deploy: 7 | 8 | npm install 9 | apigeetool deploynodeapp -u USERNAME -p PASSWORD \ 10 | -o ORG -e test -n employees -d . 11 | -m server.js -b /employees 12 | 13 | Where: 14 | 15 | * USERNAME: Your Apigee user name 16 | * PASSWORD: Your Apigee password 17 | * ORG: Your Apigee organization name 18 | 19 | To use: 20 | 21 | curl http://ORG-test.apigee.net/employees/employees 22 | 23 | curl http://ORG-test.apigee.net/employees/employees \ 24 | -H "Content-Type: application/json" \ 25 | -d '{"id":"moe", "firstName":"Moe", "lastName":"Moeness", "phone": "201-867-5309" }' 26 | -X POST 27 | -------------------------------------------------------------------------------- /node/employees/config-template.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy this file to "config.js" and edit the defaults for your environment 3 | */ 4 | 5 | exports.organization = ORGANIZATION 6 | exports.application = 'employees' 7 | exports.clientId = CLIENT_ID 8 | exports.clientSecret = CLIENT_SECRET 9 | exports.username = 'demo' 10 | exports.password = 'demo' 11 | exports.tokenExpiration = 60000 12 | exports.logging = true 13 | -------------------------------------------------------------------------------- /node/employees/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "employees", 3 | "version": "0.0.0", 4 | "description": "Employee Database API", 5 | "main": "server.js", 6 | "private": true, 7 | "dependencies": { 8 | "express": "3.x.x", 9 | "usergrid": "x.x.x" 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /node/employees/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var usergrid = require('usergrid'); 3 | var config = require('./config'); 4 | 5 | // Set up Express environment and enable it to read and write JavaScript 6 | var app = express(); 7 | app.use(express.bodyParser()); 8 | 9 | // Initialize Usergrid 10 | 11 | var ug = new usergrid.client({ 12 | 'orgName': config.organization, 13 | 'appName': config.application, 14 | 'clientId': config.clientId, 15 | 'clientSecret': config.clientSecret, 16 | logging: config.logging 17 | }); 18 | 19 | var loggedIn = null; 20 | 21 | // The API starts here 22 | 23 | // GET / 24 | 25 | var rootTemplate = { 26 | 'employees': { 'href': './employees' } 27 | }; 28 | 29 | app.get('/', function(req, resp) { 30 | resp.jsonp(rootTemplate); 31 | }); 32 | 33 | // GET /employees 34 | 35 | app.get('/employees', function(req, res) { 36 | if (loggedIn === null) { 37 | logIn(req, res, getEmployees); 38 | } else { 39 | getEmployees(req, res); 40 | } 41 | }); 42 | 43 | function getEmployees(req, res) { 44 | loggedIn.createCollection({ type: 'employees' }, function(err, employees) { 45 | if (err) { 46 | res.jsonp(500, {'error': JSON.stringify(err) }); 47 | return; 48 | } 49 | 50 | var emps = []; 51 | while (employees.hasNextEntity()) { 52 | var emp = employees.getNextEntity().get(); 53 | var e = { 'id': emp.id, 54 | 'firstName': emp.firstName, 55 | 'lastName': emp.lastName, 56 | 'phone': emp.phone }; 57 | emps.push(e); 58 | } 59 | res.jsonp(emps); 60 | }); 61 | } 62 | 63 | // POST /employees 64 | 65 | app.post('/employees', function(req, res) { 66 | if (!req.is('json')) { 67 | res.jsonp(400, {error: 'Bad request'}); 68 | return; 69 | } 70 | 71 | var b = req.body; 72 | var e = { 73 | 'id': b.id, 74 | 'firstName': b.firstName, 75 | 'lastName': b.lastName, 76 | 'phone': b.phone 77 | }; 78 | 79 | if ((e.id === undefined) || (e.firstName === undefined) || 80 | (e.lastName === undefined) || (e.phone === undefined)) { 81 | res.jsonp(400, {error: 'Bad request' }); 82 | return; 83 | } 84 | 85 | if (loggedIn === null) { 86 | logIn(req, res, function() { 87 | createEmployee(e, req, res); 88 | }); 89 | } else { 90 | createEmployee(e, req, res); 91 | } 92 | }); 93 | 94 | function createEmployee(e, req, res) { 95 | var opts = { 96 | type: 'employees', 97 | name: e.id 98 | }; 99 | loggedIn.createEntity(opts, function(err, o) { 100 | if (err) { 101 | res.jsonp(500, err); 102 | return; 103 | } 104 | o.set(e); 105 | o.save(function(err) { 106 | if (err) { 107 | res.jsonp(500, err); 108 | return; 109 | } 110 | res.send(201); 111 | }); 112 | }); 113 | } 114 | 115 | // We need this for UserGrid authentication 116 | 117 | function logIn(req, res, next) { 118 | console.log('Logging in as %s', config.username); 119 | ug.login(config.username, config.password, function(err) { 120 | if (err) { 121 | console.log('Login failed: %s', JSON.stringify(err)); 122 | res.jsonp(500, {error: err}); 123 | return; 124 | } 125 | 126 | loggedIn = new usergrid.client({ 127 | 'orgName' : config.organization, 128 | 'appName' : config.application, 129 | 'authType' : usergrid.AUTH_APP_USER, 130 | 'token': ug.token, 131 | logging: config.logging 132 | }); 133 | 134 | console.log("Got a token. I wonder when it expires? Let's guess."); 135 | 136 | // Go on to do what we were trying to do in the first place 137 | setTimeout(expireToken, config.tokenExpiration); 138 | 139 | next(req, res); 140 | }); 141 | } 142 | 143 | function expireToken() { 144 | console.log('Getting rid of user authentication token'); 145 | if (loggedIn !== null) { 146 | loggedIn.logout(); 147 | loggedIn = null; 148 | } 149 | } 150 | 151 | // Listen for requests until the server is stopped 152 | 153 | app.listen(9000); 154 | console.log('Listening on port 9000'); 155 | 156 | 157 | -------------------------------------------------------------------------------- /node/hello/README.md: -------------------------------------------------------------------------------- 1 | # "Hello" Apigee Node.js Sample 2 | 3 | This application simply prints out "Hello, World!" 4 | 5 | To deploy: 6 | 7 | apigeetool deploynodeapp -u USERNAME -p PASSWORD \ 8 | -o ORG -e test -n hello -d . 9 | -m server.js -b /hello 10 | 11 | Where: 12 | 13 | * USERNAME: Your Apigee user name 14 | * PASSWORD: Your Apigee password 15 | * ORG: Your Apigee organization name 16 | 17 | To run: 18 | 19 | curl http://ORG-test.apigee.net/hello 20 | 21 | -------------------------------------------------------------------------------- /node/hello/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | 3 | var svr = http.createServer(function(req, resp) { 4 | resp.writeHead(200, { 'Content-Type': 'text/plain' }); 5 | resp.end('Hello, World!\n'); 6 | }); 7 | 8 | svr.listen(9000, function() { 9 | console.log('The server is listening on port 9000'); 10 | }); 11 | -------------------------------------------------------------------------------- /node/mashup/README.md: -------------------------------------------------------------------------------- 1 | # "Mashup" Apigee Node.js Sample 2 | 3 | A mashup of the Google geocoding and altitude APIs. It gives you the 4 | average altitude of any postal code in the world. 5 | 6 | To deploy: 7 | 8 | npm install 9 | apigeetool deploynodeapp -u USERNAME -p PASSWORD \ 10 | -o ORG -e test -n altitude -d . 11 | -m mashup.js -b /altitude 12 | 13 | Where: 14 | 15 | * USERNAME: Your Apigee user name 16 | * PASSWORD: Your Apigee password 17 | * ORG: Your Apigee organization name 18 | 19 | To use: 20 | 21 | curl "http://ORG-test.apigee.net/altitude?country=XX&postalcode=ZZZZ" 22 | -------------------------------------------------------------------------------- /node/mashup/mashup.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var http = require('http'); 3 | var urlparse = require('url'); 4 | var util = require('util'); 5 | 6 | function sendError(resp, code, msg) { 7 | var o = { 'error': msg }; 8 | resp.writeHead(code, {'Content-Type': 'application/json'}); 9 | resp.end(JSON.stringify(o)); 10 | } 11 | 12 | function geocode(postalcode, country, resp) { 13 | var url = util.format( 14 | 'http://maps.googleapis.com/maps/api/geocode/json?address=%s®ion=%s&sensor=false', 15 | postalcode, country); 16 | 17 | request(url, function(err, result, body) { 18 | if (err) { 19 | sendError(resp, 400, 20 | util.format('Error response %s from geocoding web service', err.message)); 21 | return; 22 | } 23 | 24 | var geoResponse = JSON.parse(body); 25 | if (geoResponse.status !== 'OK') { 26 | sendError(resp, 500, 'Invalid geocode response'); 27 | } else { 28 | getAltitude(geoResponse.results[0].geometry.location.lat, 29 | geoResponse.results[0].geometry.location.lng, resp); 30 | } 31 | }); 32 | } 33 | 34 | function getAltitude(lat, lng, resp) { 35 | var url = util.format( 36 | 'http://maps.googleapis.com/maps/api/elevation/json?locations=%s,%s&sensor=false', 37 | lat, lng); 38 | 39 | request(url, function(err, result, body) { 40 | if (err) { 41 | sendError(resp, 400, 42 | util.format('Error response %s from elevation web service', err.message)); 43 | return; 44 | } 45 | 46 | var altResponse = JSON.parse(body); 47 | if (altResponse.status !== 'OK') { 48 | sendError(resp, 500, 'Invalid altitude response'); 49 | } else { 50 | makeResponse(lat, lng, altResponse.results[0].elevation, resp); 51 | } 52 | }); 53 | } 54 | 55 | function makeResponse(lat, lng, altitude, resp) { 56 | var o = { 'latitude': lat, 'longitide': lng, 57 | 'altitude': altitude }; 58 | resp.writeHead(200, {'Content-Type': 'application/json'}); 59 | resp.end(JSON.stringify(o)); 60 | } 61 | 62 | var svr = http.createServer(function(req, resp) { 63 | var parsed = urlparse.parse(req.url, true); 64 | if (!parsed.query.postalcode) { 65 | sendError(resp, 400, 'Missing query parameter "postalcode"'); 66 | } else if (!parsed.query.country) { 67 | sendError(resp, 400, 'Missing query parameter "country"'); 68 | } else { 69 | geocode(parsed.query.postalcode, parsed.query.country, resp); 70 | } 71 | }); 72 | 73 | svr.listen(9000, function() { 74 | console.log('Node Mashup sample app is running on port 9000'); 75 | }); 76 | 77 | 78 | -------------------------------------------------------------------------------- /node/mashup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mashup", 3 | "version": "0.0.0", 4 | "description": "Geocoding mashup", 5 | "main": "server.js", 6 | "private": true, 7 | "dependencies": { 8 | "request": "2.x.x" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /node/method-override/README.md: -------------------------------------------------------------------------------- 1 | # "Method Override" Apigee Node.js Sample 2 | 3 | This application is a proxy that changes the HTTP method sent to a target. If a `X-HTTP-Method-Override` header or `method_override` query parameter is specified in a request, its value will be used as the method instead of the original method, and the header or query parameter will be removed. [HTTPBin](http://httpbin.org/) is the default backend service. 4 | 5 | To deploy: 6 | 7 | npm install 8 | apigeetool deploynodeapp -u USERNAME -p PASSWORD \ 9 | -o ORG -e test -n method-override -d . 10 | -m server.js -b /method-override 11 | 12 | Where: 13 | 14 | * USERNAME: Your Apigee user name 15 | * PASSWORD: Your Apigee password 16 | * ORG: Your Apigee organization name 17 | 18 | To use: 19 | 20 | curl -X GET \ 21 | "http://ORG-test.apigee.net/method-override/post?method_override=POST" 22 | 23 | curl -X GET \ 24 | -H "X-HTTP-Method-Override: POST" \ 25 | -d "Hello, world!" \ 26 | "http://ORG-test.apigee.net/method-override/post" 27 | -------------------------------------------------------------------------------- /node/method-override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "method-override", 3 | "version": "0.0.0", 4 | "description": "Method Override sample", 5 | "main": "server.js", 6 | "private": true, 7 | "dependencies": { 8 | "argo": "~0.4.0" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /node/method-override/server.js: -------------------------------------------------------------------------------- 1 | var url = require('url'), 2 | argo = require('argo'); 3 | 4 | argo() 5 | .use(function(handle) { 6 | handle('request', function(env, next) { 7 | console.log(env); 8 | var method, 9 | parsedReqUrl; 10 | 11 | // Try the X-HTTP-Method-Override header 12 | // in Node.js, header names are lowercased 13 | if (env.request.headers['x-http-method-override']) { 14 | method = env.request.headers['x-http-method-override']; 15 | delete env.request.headers['x-http-method-override']; 16 | } else { 17 | // Try the method_override query parameter 18 | parsedReqUrl = url.parse(env.request.url, true); 19 | 20 | if (parsedReqUrl.query['method_override']) { 21 | method = parsedReqUrl.query['method_override']; 22 | 23 | // Remove the param from the request URL 24 | delete parsedReqUrl.query['method_override']; 25 | delete parsedReqUrl.search; 26 | env.request.url = url.format(parsedReqUrl); 27 | } 28 | } 29 | 30 | if (method) { 31 | env.request.method = method; 32 | } 33 | 34 | next(env); 35 | }); 36 | }) 37 | .target('http://httpbin.org') 38 | .listen(9000); 39 | --------------------------------------------------------------------------------