From 05460902b84e8d901069e24350ca42bdfbbb23e9 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 18 Jan 2016 15:33:13 -0800 Subject: [PATCH 01/16] Add SOAP connector examples --- stock-ws.js | 41 ++++++ weather-rest.js | 101 ++++++++++++++ weather-ws.js | 34 +++++ weather.wsdl | 349 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 525 insertions(+) create mode 100644 stock-ws.js create mode 100644 weather-rest.js create mode 100644 weather-ws.js create mode 100644 weather.wsdl diff --git a/stock-ws.js b/stock-ws.js new file mode 100644 index 0000000..9fa682c --- /dev/null +++ b/stock-ws.js @@ -0,0 +1,41 @@ +var loopback = require('loopback'); + +var ds = loopback.createDataSource('soap', + { + connector: require('../index'), + wsdl: 'http://www.webservicex.net/stockquote.asmx?WSDL', // The url to WSDL + url: 'http://www.webservicex.net/stockquote.asmx', // The service endpoint + + // Map SOAP service/port/operation to Node.js methods + operations: { + // The key is the method name + stockQuote: { + service: 'StockQuote', // The WSDL service name + port: 'StockQuoteSoap', // The WSDL port name + operation: 'GetQuote' // The WSDL operation name + }, + // The key is the method name + stockQuote12: { + service: 'StockQuote', // The WSDL service name + port: 'StockQuoteSoap12', // The WSDL port name + operation: 'GetQuote' // The WSDL operation name + } + } + }); + +// Unfortunately, the methods from the connector are mixed in asynchronously +// This is a hack to wait for the methods to be injected +ds.once('connected', function () { +// Create the model + var StockQuote = ds.createModel('StockQuote', {}); + + StockQuote.stockQuote({symbol: 'IBM'}, function (err, response) { + console.log('Response: ', response); + }); + + StockQuote.stockQuote12({symbol: 'FB'}, function (err, response) { + console.log('Response: ', response); + }); + + +}); \ No newline at end of file diff --git a/weather-rest.js b/weather-rest.js new file mode 100644 index 0000000..8de1b0a --- /dev/null +++ b/weather-rest.js @@ -0,0 +1,101 @@ +var loopback = require('loopback'); +var path = require('path'); + +var app = module.exports = loopback(); + +app.set('restApiRoot', '/api'); + +var ds = loopback.createDataSource('soap', + { + connector: require('../index'), + remotingEnabled: true, + // wsdl: 'http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL' // The url to WSDL + wsdl: path.join(__dirname, './weather.wsdl') + }); + +// Unfortunately, the methods from the connector are mixed in asynchronously +// This is a hack to wait for the methods to be injected +ds.once('connected', function () { + + // Create the model + var WeatherService = ds.createModel('WeatherService', {}); + + // Refine the methods + WeatherService.forecast = function (zip, cb) { + WeatherService.GetCityForecastByZIP({ZIP: zip || '94555'}, function (err, response) { + console.log('Forecast: %j', response); + var result = (!err && response.GetCityForecastByZIPResult.Success) ? + response.GetCityForecastByZIPResult.ForecastResult.Forecast : []; + cb(err, result); + }); + }; + + WeatherService.weather = function (zip, cb) { + WeatherService.GetCityWeatherByZIP({ZIP: zip || '94555'}, function (err, response) { + console.log('Weather: %j', response); + // var result = response.GetCityWeatherByZIPResult.Temperature; + var result = response; + cb(err, result); + }); + }; + + // Map to REST/HTTP + loopback.remoteMethod( + WeatherService.forecast, { + accepts: [ + {arg: 'zip', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/forecast'} + } + ); + + loopback.remoteMethod( + WeatherService.weather, { + accepts: [ + {arg: 'zip', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/weather'} + } + ); + + // Expose to REST + app.model(WeatherService); + + // LoopBack REST interface + app.use(app.get('restApiRoot'), loopback.rest()); +// API explorer (if present) + try { + var explorer = require('loopback-explorer')(app); + app.use('/explorer', explorer); + app.once('started', function (baseUrl) { + console.log('Browse your REST API at %s%s', baseUrl, explorer.route); + }); + } catch (e) { + console.log( + 'Run `npm install loopback-explorer` to enable the LoopBack explorer' + ); + } + + app.use(loopback.urlNotFound()); + app.use(loopback.errorHandler()); + + if (require.main === module) { + app.start(); + } + +}); + +app.start = function () { + return app.listen(3000, function () { + var baseUrl = 'http://127.0.0.1:3000'; + app.emit('started', baseUrl); + console.log('LoopBack server listening @ %s%s', baseUrl, '/'); + }); +}; + + + diff --git a/weather-ws.js b/weather-ws.js new file mode 100644 index 0000000..949ee7a --- /dev/null +++ b/weather-ws.js @@ -0,0 +1,34 @@ +var loopback = require('loopback'); + +var ds = loopback.createDataSource('soap', + { + connector: require('../index'), + wsdl: 'http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL' // The url to WSDL + }); + +// Unfortunately, the methods from the connector are mixed in asynchronously +// This is a hack to wait for the methods to be injected +ds.once('connected', function () { + + // Set up a before-execute hook to dump out the request object + ds.connector.observe('before execute', function(ctx, next) { + console.log('Http Request: ', ctx.req); + next(); + }); + +// Create the model + var WeatherService = ds.createModel('WeatherService', {}); + + WeatherService.GetCityForecastByZIP({ZIP: '94555'}, function (err, response) { + console.log('Forecast: %j', response); + }); + + WeatherService.GetCityWeatherByZIP({ZIP: '94555'}, function (err, response) { + console.log('Weather: %j', response); + }); + + WeatherService.GetWeatherInformation(function (err, response) { + console.log('Info: %j', response); + }); + +}); diff --git a/weather.wsdl b/weather.wsdl new file mode 100644 index 0000000..8b7aa3a --- /dev/null +++ b/weather.wsdl @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets Information for each WeatherID + + + + + Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only + + + + + Allows you to get your City's Weather, which is updated hourly. U.S. Only + + + + + + + Gets Information for each WeatherID + + + + + Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only + + + + + Allows you to get your City's Weather, which is updated hourly. U.S. Only + + + + + + + Gets Information for each WeatherID + + + + + Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only + + + + + Allows you to get your City's Weather, which is updated hourly. U.S. Only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a3c8b2a556f10c7d2535a5441183eaa8ce758e78 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 18 Jan 2016 15:36:17 -0800 Subject: [PATCH 02/16] Add LICENSE.md --- LICENSE.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..29d7815 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +Copyright (c) 2013-2015 StrongLoop, Inc and other contributors. + +loopback uses a dual license model. + +You may use this library under the terms of the [MIT License][], +or under the terms of the [StrongLoop Subscription Agreement][]. + +[MIT License]: http://opensource.org/licenses/MIT +[StrongLoop Subscription Agreement]: http://strongloop.com/license From 8a93a7a541a4c98d922a50f46b0a6b507481b377 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 18 Jan 2016 15:36:25 -0800 Subject: [PATCH 03/16] Add CONTRIBUTING.md --- CONTRIBUTING.md | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f978251 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,151 @@ +### Contributing ### + +Thank you for your interest in `loopback`, an open source project +administered by StrongLoop. + +Contributing to `loopback` is easy. In a few simple steps: + + * Ensure that your effort is aligned with the project's roadmap by + talking to the maintainers, especially if you are going to spend a + lot of time on it. + + * Make something better or fix a bug. + + * Adhere to code style outlined in the [Google C++ Style Guide][] and + [Google Javascript Style Guide][]. + + * Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/loopback) + + * Submit a pull request through Github. + + +### Contributor License Agreement ### + +``` + Individual Contributor License Agreement + + By signing this Individual Contributor License Agreement + ("Agreement"), and making a Contribution (as defined below) to + StrongLoop, Inc. ("StrongLoop"), You (as defined below) accept and + agree to the following terms and conditions for Your present and + future Contributions submitted to StrongLoop. Except for the license + granted in this Agreement to StrongLoop and recipients of software + distributed by StrongLoop, You reserve all right, title, and interest + in and to Your Contributions. + + 1. Definitions + + "You" or "Your" shall mean the copyright owner or the individual + authorized by the copyright owner that is entering into this + Agreement with StrongLoop. + + "Contribution" shall mean any original work of authorship, + including any modifications or additions to an existing work, that + is intentionally submitted by You to StrongLoop for inclusion in, + or documentation of, any of the products owned or managed by + StrongLoop ("Work"). For purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication + sent to StrongLoop or its representatives, including but not + limited to communication or electronic mailing lists, source code + control systems, and issue tracking systems that are managed by, + or on behalf of, StrongLoop for the purpose of discussing and + improving the Work, but excluding communication that is + conspicuously marked or otherwise designated in writing by You as + "Not a Contribution." + + 2. You Grant a Copyright License to StrongLoop + + Subject to the terms and conditions of this Agreement, You hereby + grant to StrongLoop and recipients of software distributed by + StrongLoop, a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare + derivative works of, publicly display, publicly perform, + sublicense, and distribute Your Contributions and such derivative + works under any license and without any restrictions. + + 3. You Grant a Patent License to StrongLoop + + Subject to the terms and conditions of this Agreement, You hereby + grant to StrongLoop and to recipients of software distributed by + StrongLoop a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this Section) + patent license to make, have made, use, offer to sell, sell, + import, and otherwise transfer the Work under any license and + without any restrictions. The patent license You grant to + StrongLoop under this Section applies only to those patent claims + licensable by You that are necessarily infringed by Your + Contributions(s) alone or by combination of Your Contributions(s) + with the Work to which such Contribution(s) was submitted. If any + entity institutes a patent litigation against You or any other + entity (including a cross-claim or counterclaim in a lawsuit) + alleging that Your Contribution, or the Work to which You have + contributed, constitutes direct or contributory patent + infringement, any patent licenses granted to that entity under + this Agreement for that Contribution or Work shall terminate as + of the date such litigation is filed. + + 4. You Have the Right to Grant Licenses to StrongLoop + + You represent that You are legally entitled to grant the licenses + in this Agreement. + + If Your employer(s) has rights to intellectual property that You + create, You represent that You have received permission to make + the Contributions on behalf of that employer, that Your employer + has waived such rights for Your Contributions, or that Your + employer has executed a separate Corporate Contributor License + Agreement with StrongLoop. + + 5. The Contributions Are Your Original Work + + You represent that each of Your Contributions are Your original + works of authorship (see Section 8 (Submissions on Behalf of + Others) for submission on behalf of others). You represent that to + Your knowledge, no other person claims, or has the right to claim, + any right in any intellectual property right related to Your + Contributions. + + You also represent that You are not legally obligated, whether by + entering into an agreement or otherwise, in any way that conflicts + with the terms of this Agreement. + + You represent that Your Contribution submissions include complete + details of any third-party license or other restriction (including, + but not limited to, related patents and trademarks) of which You + are personally aware and which are associated with any part of + Your Contributions. + + 6. You Don't Have an Obligation to Provide Support for Your Contributions + + You are not expected to provide support for Your Contributions, + except to the extent You desire to provide support. You may provide + support for free, for a fee, or not at all. + + 6. No Warranties or Conditions + + StrongLoop acknowledges that unless required by applicable law or + agreed to in writing, You provide Your Contributions on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER + EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES + OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR + FITNESS FOR A PARTICULAR PURPOSE. + + 7. Submission on Behalf of Others + + If You wish to submit work that is not Your original creation, You + may submit it to StrongLoop separately from any Contribution, + identifying the complete details of its source and of any license + or other restriction (including, but not limited to, related + patents, trademarks, and license agreements) of which You are + personally aware, and conspicuously marking the work as + "Submitted on Behalf of a Third-Party: [named here]". + + 8. Agree to Notify of Change of Circumstances + + You agree to notify StrongLoop of any facts or circumstances of + which You become aware that would make these representations + inaccurate in any respect. Email us at callback@strongloop.com. +``` + +[Google C++ Style Guide]: https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[Google Javascript Style Guide]: https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml From 008063a8ba86906e98bdf3aab936acafb2cb1b04 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Fri, 22 Jan 2016 13:35:42 -0800 Subject: [PATCH 04/16] Update README.md --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index 0b7ff14..0720a5a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1 @@ -# loopback-example-connector - -LoopBack connector examples. - -## Getting started - -Switch to a branch to view the corresponding connector example in the table -below: - -Connector|Branch -:--|:-- -SOAP| +# loopback-example-connector.soap From 553adaa9c621b2cd0e851d5fa25bd1cafe8cee0c Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 25 Jan 2016 17:09:00 -0800 Subject: [PATCH 05/16] Fix dependencies --- package.json | 33 +++++++++++++++++++++++++++++++++ stock-ws.js | 4 ++-- weather-rest.js | 2 +- weather-ws.js | 2 +- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..4f09ecd --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "loopback-example-connector", + "version": "1.0.0", + "description": "", + "main": "stock-ws.js", + "scripts": { + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/strongloop/loopback-example-connector.git" + }, + "keywords": [ + "connector", + "example", + "loopback", + "soap" + ], + "author": "StrongLoop Date: Mon, 25 Jan 2016 17:12:40 -0800 Subject: [PATCH 06/16] Update README.md --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 0720a5a..0ead457 100644 --- a/README.md +++ b/README.md @@ -1 +1,23 @@ # loopback-example-connector.soap + +## Usage + +``` +node stock-ws.js +``` + +or + +``` +node weather-rest.js +``` + +or + +``` +node weather-ws.js +``` + +--- + +https://github.com/strongloop/loopback-example From 7217b16e418d523e621b29225cfd7005f9b5022b Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 25 Jan 2016 17:13:35 -0800 Subject: [PATCH 07/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ead457..e54f8a5 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ node weather-ws.js --- -https://github.com/strongloop/loopback-example +[More Loopback examples](https://github.com/strongloop/loopback-example) From 6ab24264cdfc5419c05a0351164d80d548e71094 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 25 Jan 2016 17:13:50 -0800 Subject: [PATCH 08/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e54f8a5..a79e28f 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ node weather-ws.js --- -[More Loopback examples](https://github.com/strongloop/loopback-example) +[More LoopBack examples](https://github.com/strongloop/loopback-example) From dc2bd713ad25634e192eecda244f84a15cecd9b9 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 27 Jan 2016 12:12:03 -0800 Subject: [PATCH 09/16] Updates --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a79e28f..f2c8c6c 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,26 @@ ## Usage ``` +# get stock quotes by symbols node stock-ws.js ``` or ``` +# get weather and forecast information for a given zip code node weather-rest.js ``` or ``` +# expose REST APIs to proxy the SOAP web services node weather-ws.js ``` +and open http://localhost:3000/explorer. + --- [More LoopBack examples](https://github.com/strongloop/loopback-example) From 6e122ee59758dcfa87912be9bd93337e44585322 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 27 Jan 2016 12:14:43 -0800 Subject: [PATCH 10/16] Update README.md --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f2c8c6c..2d9ccd3 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,31 @@ ## Usage +### Example 1 + +Get stock quotes by symbols: + ``` -# get stock quotes by symbols node stock-ws.js ``` -or +### Example 2 + +Get weather and forecast information for a given zip code: ``` -# get weather and forecast information for a given zip code node weather-rest.js ``` -or +### Example 3 + +To expose REST APIs to proxy the SOAP web services, run: ``` -# expose REST APIs to proxy the SOAP web services node weather-ws.js ``` -and open http://localhost:3000/explorer. +then browse to http://localhost:3000/explorer. --- From bb9179056a15a85851c6390eb09334f38cff1198 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 27 Jan 2016 12:15:33 -0800 Subject: [PATCH 11/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d9ccd3..e09e9c8 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ To expose REST APIs to proxy the SOAP web services, run: node weather-ws.js ``` -then browse to http://localhost:3000/explorer. +then browse to http://localhost:3000/explorer --- From 7cfd3af0931e2c0ff063afb2a6dc7ec6cdba9c31 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 27 Jan 2016 12:15:51 -0800 Subject: [PATCH 12/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e09e9c8..71cc7c7 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ To expose REST APIs to proxy the SOAP web services, run: node weather-ws.js ``` -then browse to http://localhost:3000/explorer +then browse to [http://localhost:3000/explorer](http://localhost:3000/explorer) --- From 857b2979daddc2694af3e88bdb2c85fa11644504 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Fri, 12 Aug 2016 17:20:19 -0700 Subject: [PATCH 13/16] Remove unused test script to make CI pass --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 4f09ecd..35ad88f 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,6 @@ "version": "1.0.0", "description": "", "main": "stock-ws.js", - "scripts": { - "test": "mocha" - }, "repository": { "type": "git", "url": "git+https://github.com/strongloop/loopback-example-connector.git" From 2d40dd2996e8bad79947c94f908dee411ea6c5f3 Mon Sep 17 00:00:00 2001 From: Candy Date: Thu, 16 Mar 2017 12:44:21 -0400 Subject: [PATCH 14/16] Update readme tutorial link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71cc7c7..6c98180 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,4 @@ then browse to [http://localhost:3000/explorer](http://localhost:3000/explorer) --- -[More LoopBack examples](https://github.com/strongloop/loopback-example) +[More LoopBack examples](https://loopback.io/doc/en/lb3/Tutorials-and-examples.html) From b31f3142bdea11b1e95b5c52f9f658e053090a57 Mon Sep 17 00:00:00 2001 From: rashmihunt Date: Tue, 27 Jun 2017 09:25:25 -0700 Subject: [PATCH 15/16] Fixed soap examples and readme --- README.md | 9 +- package.json | 6 +- periodictable-rest.js | 96 ++++++++++++ periodictable-ws.js | 35 +++++ weather-rest.js | 101 ------------ weather-ws.js | 34 ---- weather.wsdl | 349 ------------------------------------------ 7 files changed, 140 insertions(+), 490 deletions(-) create mode 100644 periodictable-rest.js create mode 100644 periodictable-ws.js delete mode 100644 weather-rest.js delete mode 100644 weather-ws.js delete mode 100644 weather.wsdl diff --git a/README.md b/README.md index 6c98180..b86aad0 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ node stock-ws.js ### Example 2 -Get weather and forecast information for a given zip code: +Get Periodic Table element information: ``` -node weather-rest.js +node periodictable-rest.js ``` ### Example 3 @@ -23,11 +23,14 @@ node weather-rest.js To expose REST APIs to proxy the SOAP web services, run: ``` -node weather-ws.js +node periodictable-ws.js ``` then browse to [http://localhost:3000/explorer](http://localhost:3000/explorer) +In API explorer's operations list, select `GET /PeriodictableServices/GetAtomicNumber` or `GET /PeriodictableServices/GetAtomicWeight`, then enter `elementName` and click on `Try it out`. + + --- [More LoopBack examples](https://loopback.io/doc/en/lb3/Tutorials-and-examples.html) diff --git a/package.json b/package.json index 35ad88f..6153e70 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "mocha": "^2.3.4" }, "dependencies": { - "loopback": "^2.26.2", - "loopback-connector-soap": "^2.3.0", - "loopback-datasource-juggler": "^2.44.0" + "loopback": "^3.0.0", + "loopback-connector-soap": "^3.0.1", + "loopback-datasource-juggler": "^3.0.0" } } diff --git a/periodictable-rest.js b/periodictable-rest.js new file mode 100644 index 0000000..1af7f9d --- /dev/null +++ b/periodictable-rest.js @@ -0,0 +1,96 @@ +var loopback = require('loopback'); +var path = require('path'); + +var app = module.exports = loopback(); + +app.set('restApiRoot', '/api'); + +var ds = loopback.createDataSource('soap', + { + connector: require('loopback-connector-soap'), + remotingEnabled: true, + wsdl: 'http://www.webservicex.net/periodictable.asmx?WSDL' // The url to WSDL + }); + +// Unfortunately, the methods from the connector are mixed in asynchronously +// This is a hack to wait for the methods to be injected +ds.once('connected', function () { + + // Create the model + var PeriodictableService = ds.createModel('PeriodictableService', {}); + + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + PeriodictableService.atomicnumber = function (elementName, cb) { + PeriodictableService.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + cb(err, result); + }); + }; + + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + PeriodictableService.atomicweight = function(elementName, callback) { + PeriodictableService.GetAtomicWeight({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + callback(err, result); + }); + } + + // Map to REST/HTTP + loopback.remoteMethod( + PeriodictableService.atomicnumber, { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicNumber'} + } + ); + + loopback.remoteMethod( + PeriodictableService.atomicweight, { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicWeight'} + } + ); + + // Expose to REST + app.model(PeriodictableService); + + // LoopBack REST interface + app.use(app.get('restApiRoot'), loopback.rest()); + // API explorer (if present) + try { + var explorer = require('loopback-explorer')(app); + app.use('/explorer', explorer); + app.once('started', function (baseUrl) { + console.log('Browse your REST API at %s%s', baseUrl, explorer.route); + }); + } catch (e) { + console.log( + 'Run `npm install loopback-explorer` to enable the LoopBack explorer' + ); + } + + app.use(loopback.urlNotFound()); + + if (require.main === module) { + app.start(); + } + +}); + +app.start = function () { + return app.listen(3000, function () { + var baseUrl = 'http://127.0.0.1:3000'; + app.emit('started', baseUrl); + console.log('Use API explorer to invoke REST APIS @ %s%s', baseUrl, '/explorer'); + }); +}; + + + diff --git a/periodictable-ws.js b/periodictable-ws.js new file mode 100644 index 0000000..8b38312 --- /dev/null +++ b/periodictable-ws.js @@ -0,0 +1,35 @@ +var loopback = require('loopback'); + +var ds = loopback.createDataSource('soap', + { + connector: require('loopback-connector-soap'), + wsdl: 'http://www.webservicex.net/periodictable.asmx?WSDL' // The url to WSDL + }); + +// Unfortunately, the methods from the connector are mixed in asynchronously +// This is a hack to wait for the methods to be injected +ds.once('connected', function () { + + // Set up a before-execute hook to dump out the request object + ds.connector.observe('before execute', function(ctx, next) { + //console.log('Http Request: ', ctx.req); + next(); + }); + + // Create the model + var PeriodictableService = ds.createModel('PeriodictableService', {}); + + console.log(' \n Response from external WebService, http://www.webservicex.net/periodictable.asmx'); + PeriodictableService.GetAtomicNumber({ElementName: 'Iron'}, function (err, response) { + console.log('\n GetAtomicNumber for Iron: \n %j', response); + }); + + PeriodictableService.GetAtomicWeight({ElementName: 'Gold'}, function (err, response) { + console.log('\n GetAtomicWeight for Gold: \n %j', response); + }); + + PeriodictableService.GetElementSymbol({ElementName: 'Silver'}, function (err, response) { + console.log('\n GetElementSymbol for Silver: \n %j', response); + }); + +}); diff --git a/weather-rest.js b/weather-rest.js deleted file mode 100644 index dc7bf3d..0000000 --- a/weather-rest.js +++ /dev/null @@ -1,101 +0,0 @@ -var loopback = require('loopback'); -var path = require('path'); - -var app = module.exports = loopback(); - -app.set('restApiRoot', '/api'); - -var ds = loopback.createDataSource('soap', - { - connector: require('loopback-connector-soap'), - remotingEnabled: true, - // wsdl: 'http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL' // The url to WSDL - wsdl: path.join(__dirname, './weather.wsdl') - }); - -// Unfortunately, the methods from the connector are mixed in asynchronously -// This is a hack to wait for the methods to be injected -ds.once('connected', function () { - - // Create the model - var WeatherService = ds.createModel('WeatherService', {}); - - // Refine the methods - WeatherService.forecast = function (zip, cb) { - WeatherService.GetCityForecastByZIP({ZIP: zip || '94555'}, function (err, response) { - console.log('Forecast: %j', response); - var result = (!err && response.GetCityForecastByZIPResult.Success) ? - response.GetCityForecastByZIPResult.ForecastResult.Forecast : []; - cb(err, result); - }); - }; - - WeatherService.weather = function (zip, cb) { - WeatherService.GetCityWeatherByZIP({ZIP: zip || '94555'}, function (err, response) { - console.log('Weather: %j', response); - // var result = response.GetCityWeatherByZIPResult.Temperature; - var result = response; - cb(err, result); - }); - }; - - // Map to REST/HTTP - loopback.remoteMethod( - WeatherService.forecast, { - accepts: [ - {arg: 'zip', type: 'string', required: true, - http: {source: 'query'}} - ], - returns: {arg: 'result', type: 'object', root: true}, - http: {verb: 'get', path: '/forecast'} - } - ); - - loopback.remoteMethod( - WeatherService.weather, { - accepts: [ - {arg: 'zip', type: 'string', required: true, - http: {source: 'query'}} - ], - returns: {arg: 'result', type: 'object', root: true}, - http: {verb: 'get', path: '/weather'} - } - ); - - // Expose to REST - app.model(WeatherService); - - // LoopBack REST interface - app.use(app.get('restApiRoot'), loopback.rest()); -// API explorer (if present) - try { - var explorer = require('loopback-explorer')(app); - app.use('/explorer', explorer); - app.once('started', function (baseUrl) { - console.log('Browse your REST API at %s%s', baseUrl, explorer.route); - }); - } catch (e) { - console.log( - 'Run `npm install loopback-explorer` to enable the LoopBack explorer' - ); - } - - app.use(loopback.urlNotFound()); - app.use(loopback.errorHandler()); - - if (require.main === module) { - app.start(); - } - -}); - -app.start = function () { - return app.listen(3000, function () { - var baseUrl = 'http://127.0.0.1:3000'; - app.emit('started', baseUrl); - console.log('LoopBack server listening @ %s%s', baseUrl, '/'); - }); -}; - - - diff --git a/weather-ws.js b/weather-ws.js deleted file mode 100644 index 61a3ef7..0000000 --- a/weather-ws.js +++ /dev/null @@ -1,34 +0,0 @@ -var loopback = require('loopback'); - -var ds = loopback.createDataSource('soap', - { - connector: require('loopback-connector-soap'), - wsdl: 'http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL' // The url to WSDL - }); - -// Unfortunately, the methods from the connector are mixed in asynchronously -// This is a hack to wait for the methods to be injected -ds.once('connected', function () { - - // Set up a before-execute hook to dump out the request object - ds.connector.observe('before execute', function(ctx, next) { - console.log('Http Request: ', ctx.req); - next(); - }); - -// Create the model - var WeatherService = ds.createModel('WeatherService', {}); - - WeatherService.GetCityForecastByZIP({ZIP: '94555'}, function (err, response) { - console.log('Forecast: %j', response); - }); - - WeatherService.GetCityWeatherByZIP({ZIP: '94555'}, function (err, response) { - console.log('Weather: %j', response); - }); - - WeatherService.GetWeatherInformation(function (err, response) { - console.log('Info: %j', response); - }); - -}); diff --git a/weather.wsdl b/weather.wsdl deleted file mode 100644 index 8b7aa3a..0000000 --- a/weather.wsdl +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Gets Information for each WeatherID - - - - - Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only - - - - - Allows you to get your City's Weather, which is updated hourly. U.S. Only - - - - - - - Gets Information for each WeatherID - - - - - Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only - - - - - Allows you to get your City's Weather, which is updated hourly. U.S. Only - - - - - - - Gets Information for each WeatherID - - - - - Allows you to get your City Forecast Over the Next 7 Days, which is updated hourly. U.S. Only - - - - - Allows you to get your City's Weather, which is updated hourly. U.S. Only - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 81c9d87648157cb2c46fc9f980f48c9dcbfea0a3 Mon Sep 17 00:00:00 2001 From: crandmck Date: Thu, 29 Jun 2017 15:40:23 -0700 Subject: [PATCH 16/16] Redo example to use canonical structure --- README.md | 211 +++++++++++++++++++++++++++-- package.json | 38 ++++-- periodictable-rest.js | 96 ------------- periodictable-ws.js | 2 + server/boot/root.js | 8 ++ server/component-config.json | 5 + server/config.json | 22 +++ server/datasources.json | 21 +++ server/middleware.development.json | 10 ++ server/middleware.json | 50 +++++++ server/model-config.json | 20 +++ server/models/periodic-table.js | 44 ++++++ server/models/periodic-table.json | 13 ++ server/server.js | 30 ++++ 14 files changed, 445 insertions(+), 125 deletions(-) delete mode 100644 periodictable-rest.js create mode 100644 server/boot/root.js create mode 100644 server/component-config.json create mode 100644 server/config.json create mode 100644 server/datasources.json create mode 100644 server/middleware.development.json create mode 100644 server/middleware.json create mode 100644 server/model-config.json create mode 100644 server/models/periodic-table.js create mode 100644 server/models/periodic-table.json create mode 100644 server/server.js diff --git a/README.md b/README.md index b86aad0..ae3896d 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,217 @@ -# loopback-example-connector.soap +# loopback-example-connector (SOAP) -## Usage +The SOAP connector enables LoopBack applications to interact with +[SOAP](http://www.w3.org/TR/soap)-based web services described using +[WSDL](http://www.w3.org/TR/wsdl). This example app illustrates calling a [periodic table SOAP web service](http://www.webservicex.net/periodictable.asmx) from a LoopBack app, +where you define a remote method to call each SOAP web service operation. +This is a simple example of a LoopBack app "proxying" or intermediating a web service. -### Example 1 +For more information, see the +SOAP connector documentation. -Get stock quotes by symbols: +## Installation +Clone this repo and install dependencies from npm: + + +```shell +$ git clone https://github.com/strongloop-community/loopback-example-connector.git -b soap +$ cd loopback-example-connector +$ npm install ``` -node stock-ws.js + +## Run the example + +1. In the project root directory, run the app by entering this command: + ``` + node . + ``` + + You'll see this in the console: + ``` + Web server listening at: http://0.0.0.0:3000 + Browse your REST API at http://0.0.0.0:3000/explorer + ``` + +2. Open [API Explorer](http://0.0.0.0:3000/explorer) in your web browser. +3. Under the **periodicTable** model, you'll see two endpoints: `GET /periodicTables/GetAtomicNumber` and `GET /periodicTables/GetAtomicWeight`. +4. Click on `GetAtomicNumber` and in the **elementName** parameter field, enter the name of an element, for example, "Gold" or "Oxygen". In the **Response Body** field, you'll see an XML response from the web service that looks something like this (NOTE: line feeds have been added in the example below for readability, but in practice the response will be on a single line): + + ``` + { + "GetAtomicNumberResult": "\r\n \r\n + 26\r\n + Iron\r\n + Fe\r\n + 55.847\r\n + 3300\r\n + 7.9\r\n + 1.6400000000000001\r\n + 1.17\r\n + 1808\r\n + 7874\r\n
\r\n
" + } + ``` + +### Additional example code + +The app includes two other files `periodictable-ws.js` and `stock-ws.js` that illustrate other ways of programmatically calling a SOAP web service. NOTE: the [stock quote web service](http://www.webservicex.net/stockquote.asmx) may not be consistently available. + +## Recreate the app + +**Prerequisites**: If you haven't already done so, follow the [Installation instructions](http://loopback.io/doc/en/lb3/Installation.html) for the LoopBack CLI. In a nutshell: +``` +$ npm install -g loopback-cli ``` -### Example 2 +To create this app yourself, follow the steps in this section: +- [Scaffold the app](#scaffold-the-app) +- [Create a SOAP data source](#create-a-soap-data-source) +- [Create a periodicTable model](#create-a-periodictable-model) +- [Add remote methods](#add-remote-methods) +- [Try it out!](#try-it-out) + +### Scaffold the app -Get Periodic Table element information: +Scaffold a new application. Enter this command: ``` -node periodictable-rest.js +$ lb app ``` -### Example 3 +When prompted, respond as follows: +1. `What's the name of your application?` +
Give the app any name you wish, for example "my-soap-demo". +The tool will create a directory with that name (`my-soap-demo`). +1. `Enter name of the directory to contain the project:` +
Press Enter to accept the default (directory has the same name as the app). +1. `Which version of LoopBack would you like to use?` +
Choose `3.x (current)` +1. `What kind of application do you have in mind?` +
Choose `empty-server (An empty LoopBack API, without any configured models or datasources) ` -To expose REST APIs to proxy the SOAP web services, run: +The tool will then scaffold the app and install all the dependencies from npm. +### Create a SOAP data source + +Go into the app root directory: +``` +$ cd my-soap-demo ``` -node periodictable-ws.js + +Use the [data source generator](http://loopback.io/doc/en/lb3/Data-source-generator.html) to add a SOAP data source to your application. Enter this command: + +```shell +$ lb datasource +``` + +When prompted, respond as follows: + +1. `Enter the datasource name:` +
Enter "soapDS". +1. ` Select the connector for soapDS:` +
Use your arrow key to scroll down to `SOAP webservices (supported by StrongLoop)` and press Enter. +1. `URL to the SOAP web service endpoint:` +
Copy and paste the URL of the periodic table web service: + ``` + http://www.webservicex.net/periodictable.asmx + ``` +1. `HTTP URL or local file system path to the WSDL file:` +
Copy and paste this URL of the periodic table web service WSDL: + ``` + http://www.webservicex.net/periodictable.asmx?WSDL + ``` +1. `Expose operations as REST APIs: (Y/n)` +
Press Enter to accept the default (yes). +1. `Maps WSDL binding operations to Node.js methods:` +
Copy and paste the stringified JSON below. The JSON defines the service, port, and operation for each operation that will be called in the SOAP service. + ``` + {"getAtomicWeight":{"service":"periodictable","port":"periodictableSoap","operation":"GetAtomicWeight"},"getAtomicNumber":{"service":"periodictable","port":"periodictableSoap","operation":"GetAtomicNumber"}} + ``` + NOTE: The JSON you enter must **not** have any line endings, that is, it must be on a single line. +1. `Install loopback-connector-soap@^3.0` +
Press Enter to install the connector from npm. + +The data source generator then creates an entry for the data source in the `server/datasources.json` file and installs all the necessary dependencies. + +### Create a periodicTable model + +Use the [model generator](http://loopback.io/doc/en/lb3/Model-generator.html) to add a model to represent the periodic Table web service. Enter this command: + +```shell +$ lb model ``` -then browse to [http://localhost:3000/explorer](http://localhost:3000/explorer) +When prompted, respond as follows: + +1. `Enter the model name:`
Enter "periodicTable". +1. `Enter the model name: periodicTable`
Select `soapDS` that you previously created. +1. `Select model's base class` Select `Model`. +1. `Expose periodicTable via the REST API? (Y/n)`
Press Enter to accept the default (yes). +1. `Custom plural form (used to build REST URL):`
Press Enter for no custom plural. +1. `Common model or server only?`
Select `server` because this will be a server-only model. +1. `Property name:`
Press Enter when first prompted, because this model will not have any properties. + +The tool will create two files in the `server` directory: `periodicTable.json` and `periodicTable.js`. + +### Add remote methods + +Edit `server/models/periodic-table.js` and add the code shown below to the stubbed-out function. + +This code defines two functions, `Periodictable.getAtomicnumber` and `Periodictable.getAtomicweight` and adds them as remote methods to the `Periodictable` model, as described in [Remote methods](https://loopback.io/doc/en/lb3/Remote-methods.html). -In API explorer's operations list, select `GET /PeriodictableServices/GetAtomicNumber` or `GET /PeriodictableServices/GetAtomicWeight`, then enter `elementName` and click on `Try it out`. +```javascript +'use strict'; +module.exports = function(Periodictable) { ---- + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + Periodictable.getAtomicnumber = function (elementName, cb) { + Periodictable.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + cb(err, result); + }); + }; + + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + Periodictable.getAtomicweight = function(elementName, callback) { + Periodictable.GetAtomicWeight({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + callback(err, result); + }); + } + + // Map to REST/HTTP + Periodictable.remoteMethod( + 'getAtomicnumber', { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicNumber'} + } + ); + + Periodictable.remoteMethod( + 'getAtomicweight', { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicWeight'} + } + ); + +}; +``` + +### Try it out! + +Now, run your app: +``` +node . +``` -[More LoopBack examples](https://loopback.io/doc/en/lb3/Tutorials-and-examples.html) +Follow the same steps [as before](#run-the-example) and your app should behave the same as the one in this repository. diff --git a/package.json b/package.json index 6153e70..931b6ed 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,40 @@ { "name": "loopback-example-connector", "version": "1.0.0", - "description": "", - "main": "stock-ws.js", + "main": "server/server.js", + "description": "LoopBack SOAP connector example", "repository": { "type": "git", "url": "git+https://github.com/strongloop/loopback-example-connector.git" }, - "keywords": [ - "connector", - "example", - "loopback", - "soap" - ], - "author": "StrongLoop =4" + }, + "scripts": { + "lint": "eslint .", + "start": "node .", + "posttest": "npm run lint && nsp check" }, "dependencies": { + "compression": "^1.0.3", + "cors": "^2.5.2", + "helmet": "^1.3.0", "loopback": "^3.0.0", + "loopback-boot": "^2.6.5", + "loopback-component-explorer": "^4.0.0", "loopback-connector-soap": "^3.0.1", - "loopback-datasource-juggler": "^3.0.0" - } + "serve-favicon": "^2.0.1", + "strong-error-handler": "^2.0.0" + }, + "devDependencies": { + "eslint": "^3.17.1", + "eslint-config-loopback": "^8.0.0", + "nsp": "^2.1.0" + }, + "author": "StrongLoop ", + "license": "MIT" } diff --git a/periodictable-rest.js b/periodictable-rest.js deleted file mode 100644 index 1af7f9d..0000000 --- a/periodictable-rest.js +++ /dev/null @@ -1,96 +0,0 @@ -var loopback = require('loopback'); -var path = require('path'); - -var app = module.exports = loopback(); - -app.set('restApiRoot', '/api'); - -var ds = loopback.createDataSource('soap', - { - connector: require('loopback-connector-soap'), - remotingEnabled: true, - wsdl: 'http://www.webservicex.net/periodictable.asmx?WSDL' // The url to WSDL - }); - -// Unfortunately, the methods from the connector are mixed in asynchronously -// This is a hack to wait for the methods to be injected -ds.once('connected', function () { - - // Create the model - var PeriodictableService = ds.createModel('PeriodictableService', {}); - - // External PeriodTable WebService operation exposed as REST APIs through LoopBack - PeriodictableService.atomicnumber = function (elementName, cb) { - PeriodictableService.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) { - var result = response; - cb(err, result); - }); - }; - - // External PeriodTable WebService operation exposed as REST APIs through LoopBack - PeriodictableService.atomicweight = function(elementName, callback) { - PeriodictableService.GetAtomicWeight({ElementName: elementName || 'Copper'}, function (err, response) { - var result = response; - callback(err, result); - }); - } - - // Map to REST/HTTP - loopback.remoteMethod( - PeriodictableService.atomicnumber, { - accepts: [ - {arg: 'elementName', type: 'string', required: true, - http: {source: 'query'}} - ], - returns: {arg: 'result', type: 'object', root: true}, - http: {verb: 'get', path: '/GetAtomicNumber'} - } - ); - - loopback.remoteMethod( - PeriodictableService.atomicweight, { - accepts: [ - {arg: 'elementName', type: 'string', required: true, - http: {source: 'query'}} - ], - returns: {arg: 'result', type: 'object', root: true}, - http: {verb: 'get', path: '/GetAtomicWeight'} - } - ); - - // Expose to REST - app.model(PeriodictableService); - - // LoopBack REST interface - app.use(app.get('restApiRoot'), loopback.rest()); - // API explorer (if present) - try { - var explorer = require('loopback-explorer')(app); - app.use('/explorer', explorer); - app.once('started', function (baseUrl) { - console.log('Browse your REST API at %s%s', baseUrl, explorer.route); - }); - } catch (e) { - console.log( - 'Run `npm install loopback-explorer` to enable the LoopBack explorer' - ); - } - - app.use(loopback.urlNotFound()); - - if (require.main === module) { - app.start(); - } - -}); - -app.start = function () { - return app.listen(3000, function () { - var baseUrl = 'http://127.0.0.1:3000'; - app.emit('started', baseUrl); - console.log('Use API explorer to invoke REST APIS @ %s%s', baseUrl, '/explorer'); - }); -}; - - - diff --git a/periodictable-ws.js b/periodictable-ws.js index 8b38312..22d9d53 100644 --- a/periodictable-ws.js +++ b/periodictable-ws.js @@ -1,4 +1,6 @@ var loopback = require('loopback'); +app = loopback(); +ds = app.datasources['soapDS']; var ds = loopback.createDataSource('soap', { diff --git a/server/boot/root.js b/server/boot/root.js new file mode 100644 index 0000000..6adce90 --- /dev/null +++ b/server/boot/root.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = function(server) { + // Install a `/` route that returns server status + var router = server.loopback.Router(); + router.get('/', server.loopback.status()); + server.use(router); +}; diff --git a/server/component-config.json b/server/component-config.json new file mode 100644 index 0000000..f36959a --- /dev/null +++ b/server/component-config.json @@ -0,0 +1,5 @@ +{ + "loopback-component-explorer": { + "mountPath": "/explorer" + } +} diff --git a/server/config.json b/server/config.json new file mode 100644 index 0000000..d371cd2 --- /dev/null +++ b/server/config.json @@ -0,0 +1,22 @@ +{ + "restApiRoot": "/api", + "host": "0.0.0.0", + "port": 3000, + "remoting": { + "context": false, + "rest": { + "handleErrors": false, + "normalizeHttpPath": false, + "xml": false + }, + "json": { + "strict": false, + "limit": "100kb" + }, + "urlencoded": { + "extended": true, + "limit": "100kb" + }, + "cors": false + } +} diff --git a/server/datasources.json b/server/datasources.json new file mode 100644 index 0000000..e344673 --- /dev/null +++ b/server/datasources.json @@ -0,0 +1,21 @@ +{ + "soapDS": { + "url": "http://www.webservicex.net/periodictable.asmx", + "name": "soapDS", + "wsdl": "http://www.webservicex.net/periodictable.asmx?WSDL", + "remotingEnabled": true, + "operations": { + "getAtomicWeight": { + "service": "periodictable", + "port": "periodictableSoap", + "operation": "GetAtomicWeight" + }, + "getAtomicNumber": { + "service": "periodictable", + "port": "periodictableSoap", + "operation": "GetAtomicNumber" + } + }, + "connector": "soap" + } +} diff --git a/server/middleware.development.json b/server/middleware.development.json new file mode 100644 index 0000000..071c11a --- /dev/null +++ b/server/middleware.development.json @@ -0,0 +1,10 @@ +{ + "final:after": { + "strong-error-handler": { + "params": { + "debug": true, + "log": true + } + } + } +} diff --git a/server/middleware.json b/server/middleware.json new file mode 100644 index 0000000..cde21fe --- /dev/null +++ b/server/middleware.json @@ -0,0 +1,50 @@ +{ + "initial:before": { + "loopback#favicon": {} + }, + "initial": { + "compression": {}, + "cors": { + "params": { + "origin": true, + "credentials": true, + "maxAge": 86400 + } + }, + "helmet#xssFilter": {}, + "helmet#frameguard": { + "params": [ + "deny" + ] + }, + "helmet#hsts": { + "params": { + "maxAge": 0, + "includeSubdomains": true + } + }, + "helmet#hidePoweredBy": {}, + "helmet#ieNoOpen": {}, + "helmet#noSniff": {}, + "helmet#noCache": { + "enabled": false + } + }, + "session": {}, + "auth": {}, + "parse": {}, + "routes": { + "loopback#rest": { + "paths": [ + "${restApiRoot}" + ] + } + }, + "files": {}, + "final": { + "loopback#urlNotFound": {} + }, + "final:after": { + "strong-error-handler": {} + } +} diff --git a/server/model-config.json b/server/model-config.json new file mode 100644 index 0000000..d189583 --- /dev/null +++ b/server/model-config.json @@ -0,0 +1,20 @@ +{ + "_meta": { + "sources": [ + "loopback/common/models", + "loopback/server/models", + "../common/models", + "./models" + ], + "mixins": [ + "loopback/common/mixins", + "loopback/server/mixins", + "../common/mixins", + "./mixins" + ] + }, + "periodicTable": { + "dataSource": "soapDS", + "public": true + } +} diff --git a/server/models/periodic-table.js b/server/models/periodic-table.js new file mode 100644 index 0000000..7908b45 --- /dev/null +++ b/server/models/periodic-table.js @@ -0,0 +1,44 @@ +'use strict'; + +module.exports = function(Periodictable) { + + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + Periodictable.getAtomicnumber = function (elementName, cb) { + Periodictable.GetAtomicNumber({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + cb(err, result); + }); + }; + + // External PeriodTable WebService operation exposed as REST APIs through LoopBack + Periodictable.getAtomicweight = function(elementName, callback) { + Periodictable.GetAtomicWeight({ElementName: elementName || 'Copper'}, function (err, response) { + var result = response; + callback(err, result); + }); + } + + // Map to REST/HTTP + Periodictable.remoteMethod( + 'getAtomicnumber', { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicNumber'} + } + ); + + Periodictable.remoteMethod( + 'getAtomicweight', { + accepts: [ + {arg: 'elementName', type: 'string', required: true, + http: {source: 'query'}} + ], + returns: {arg: 'result', type: 'object', root: true}, + http: {verb: 'get', path: '/GetAtomicWeight'} + } + ); + +}; diff --git a/server/models/periodic-table.json b/server/models/periodic-table.json new file mode 100644 index 0000000..b1536ad --- /dev/null +++ b/server/models/periodic-table.json @@ -0,0 +1,13 @@ +{ + "name": "periodicTable", + "base": "Model", + "idInjection": true, + "options": { + "validateUpsert": true + }, + "properties": {}, + "validations": [], + "relations": {}, + "acls": [], + "methods": {} +} diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..2ae5f41 --- /dev/null +++ b/server/server.js @@ -0,0 +1,30 @@ +'use strict'; + +var loopback = require('loopback'); +var boot = require('loopback-boot'); + +var app = module.exports = loopback(); + +app.start = function() { + // start the web server + return app.listen(function() { + app.emit('started'); + var baseUrl = app.get('url').replace(/\/$/, ''); + console.log('Web server listening at: %s', baseUrl); + if (app.get('loopback-component-explorer')) { + var explorerPath = app.get('loopback-component-explorer').mountPath; + console.log('Browse your REST API at %s%s', baseUrl, explorerPath); + } + + }); +}; + +// Bootstrap the application, configure models, datasources and middleware. +// Sub-apps like REST API are mounted via boot scripts. +boot(app, __dirname, function(err) { + if (err) throw err; + + // start the server if `$ node server.js` + if (require.main === module) + app.start(); +});