From 0df4f35ab1f98b51e6194ad54bf9ebe095f59ff5 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Mon, 18 Jan 2016 16:03:51 -0800 Subject: [PATCH 1/8] Initial commit for REST example migration --- .gitignore | 3 + CONTRIBUTING.md | 6 +- LICENSE.md | 24 +++++-- README.md | 67 +++++++++++++++---- external-server/.editorconfig | 13 ++++ external-server/.jshintignore | 2 + external-server/.jshintrc | 21 ++++++ external-server/.npmignore | 16 +++++ external-server/client/README.md | 3 + external-server/common/models/coffee-shop.js | 3 + .../common/models/coffee-shop.json | 18 +++++ external-server/package.json | 20 ++++++ external-server/server/boot/authentication.js | 4 ++ .../server/boot/create-sample-models.js | 10 +++ external-server/server/boot/root.js | 6 ++ external-server/server/component-config.json | 5 ++ external-server/server/config.json | 27 ++++++++ external-server/server/datasources.json | 6 ++ external-server/server/middleware.json | 34 ++++++++++ external-server/server/model-config.json | 39 +++++++++++ external-server/server/server.js | 27 ++++++++ local-server/.editorconfig | 13 ++++ local-server/.eslintrc | 7 ++ local-server/.jshintignore | 2 + local-server/.jshintrc | 21 ++++++ local-server/.npmignore | 16 +++++ local-server/client/README.md | 3 + local-server/common/models/magazine.js | 22 ++++++ local-server/common/models/magazine.json | 18 +++++ local-server/package.json | 23 +++++++ local-server/server/boot/authentication.js | 4 ++ .../server/boot/create-sample-model.js | 8 +++ local-server/server/boot/root.js | 6 ++ local-server/server/component-config.json | 5 ++ local-server/server/config.json | 27 ++++++++ local-server/server/datasources.json | 21 ++++++ local-server/server/middleware.json | 34 ++++++++++ local-server/server/model-config.json | 33 +++++++++ local-server/server/server.js | 25 +++++++ package.json | 27 ++++++++ tests/smoke.js | 6 ++ 41 files changed, 653 insertions(+), 22 deletions(-) create mode 100644 external-server/.editorconfig create mode 100644 external-server/.jshintignore create mode 100644 external-server/.jshintrc create mode 100644 external-server/.npmignore create mode 100644 external-server/client/README.md create mode 100644 external-server/common/models/coffee-shop.js create mode 100644 external-server/common/models/coffee-shop.json create mode 100644 external-server/package.json create mode 100644 external-server/server/boot/authentication.js create mode 100644 external-server/server/boot/create-sample-models.js create mode 100644 external-server/server/boot/root.js create mode 100644 external-server/server/component-config.json create mode 100644 external-server/server/config.json create mode 100644 external-server/server/datasources.json create mode 100644 external-server/server/middleware.json create mode 100644 external-server/server/model-config.json create mode 100644 external-server/server/server.js create mode 100644 local-server/.editorconfig create mode 100644 local-server/.eslintrc create mode 100644 local-server/.jshintignore create mode 100644 local-server/.jshintrc create mode 100644 local-server/.npmignore create mode 100644 local-server/client/README.md create mode 100644 local-server/common/models/magazine.js create mode 100644 local-server/common/models/magazine.json create mode 100644 local-server/package.json create mode 100644 local-server/server/boot/authentication.js create mode 100644 local-server/server/boot/create-sample-model.js create mode 100644 local-server/server/boot/root.js create mode 100644 local-server/server/component-config.json create mode 100644 local-server/server/config.json create mode 100644 local-server/server/datasources.json create mode 100644 local-server/server/middleware.json create mode 100644 local-server/server/model-config.json create mode 100644 local-server/server/server.js create mode 100644 package.json create mode 100644 tests/smoke.js diff --git a/.gitignore b/.gitignore index 4796eb8..76f576a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ node_modules # Optional REPL history .node_repl_history + +local-server/node_modules +external-server/node_modules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f978251..eec57f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,9 @@ ### Contributing ### -Thank you for your interest in `loopback`, an open source project +Thank you for your interest in `loopback-example-access-control`, an open source project administered by StrongLoop. -Contributing to `loopback` is easy. In a few simple steps: +Contributing to `loopback-example-access-control` 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 @@ -14,7 +14,7 @@ Contributing to `loopback` is easy. In a few simple steps: * 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) + * Sign the [Contributor License Agreement](https://cla.strongloop.com/strongloop/loopback-example-access-control) * Submit a pull request through Github. diff --git a/LICENSE.md b/LICENSE.md index 29d7815..12c1973 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,9 +1,21 @@ -Copyright (c) 2013-2015 StrongLoop, Inc and other contributors. +Copyright (c) 2013-2015 StrongLoop, Inc. -loopback uses a dual license model. +MIT license -You may use this library under the terms of the [MIT License][], -or under the terms of the [StrongLoop Subscription Agreement][]. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -[MIT License]: http://opensource.org/licenses/MIT -[StrongLoop Subscription Agreement]: http://strongloop.com/license +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 9249b41..b57859f 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,61 @@ -# WORK IN PROGRESS +[strongloop-website]: http://strongloop.com/ -This repo is still in the works. The contents may or not be up to date at this -point in time. +#loopback-example-rest-connector ---- +- [Overview](#Overview) +- [Running the app](#running-the-app) +- [FAQs](#faqs) + +## Overview +This example demonstrates basic usage of [loopback-connector-rest](https://github.com/strongloop/loopback-connector-rest). + +The project has two servers: `local-server` and `external-server`. The "external" server +serves a simple REST API, while the local server fetches data using +this REST API. + +## Running the app + +``` +$ git clone https://github.com/strongloop/loopback-example-rest-connector.git +$ cd loopback-example-rest-connector/external-server +$ npm install +# node . +``` +In another shell: +``` +$ cd local-server +$ npm install +$ node . +``` + +You should see console messages on the local server. Verify the data has been +retrieved from the remote server by doing a GET request on Magazines in the +explorer or by running `curl localhost:3000/api/Magazines`. -# loopback-example-connector +## FAQs +The following are common questions related to using the REST connector. -LoopBack connector examples. +##How do you perform a GET request to a remote server? +In this example, we have a REST API exposed in [model-config.json](https://github.com/strongloop/loopback-example-rest-connector/blob/master/external-server/server/model-config.json#L31) +. -## Getting started +To make a request to the remote server, declare new datasource that uses the +REST connector in the local [datasources.json](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L6-L20). -Switch to a branch to view the corresponding connector example in the table -below: +A few things to note in this file is the `connector` property's value is `rest` and +there is an `operations` property that takes an array of objects. + +This object has two properties: `template` and `function`. + +The `template` property contains `method` which is the HTTP method type to +perform the request with and `url` which is the URL to the remote resource. + +The `function` property is the name of the property you will use to trigger the +request. For example, we name our property `find` because we will trigger the +request using `Magazine.find()...`. + +The idea is to use [`find`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L16) to make a [`GET`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L12) request to a [`url`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L13) we specify. + +--- -Connector|Branch -:--|:-- -Remote|https://github.com/strongloop/loopback-example-connector/tree/remote -SOAP|https://github.com/strongloop/loopback-example-connector/tree/soap +[Back to top](https://github.com/strongloop/loopback-example-rest-connector#loopback-example-rest-connector) diff --git a/external-server/.editorconfig b/external-server/.editorconfig new file mode 100644 index 0000000..3ee22e5 --- /dev/null +++ b/external-server/.editorconfig @@ -0,0 +1,13 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/external-server/.jshintignore b/external-server/.jshintignore new file mode 100644 index 0000000..ee8c771 --- /dev/null +++ b/external-server/.jshintignore @@ -0,0 +1,2 @@ +/client/ +/node_modules/ diff --git a/external-server/.jshintrc b/external-server/.jshintrc new file mode 100644 index 0000000..feb0928 --- /dev/null +++ b/external-server/.jshintrc @@ -0,0 +1,21 @@ +{ + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "eqeqeq": true, + "eqnull": true, + "immed": true, + "indent": 2, + "latedef": "nofunc", + "newcap": true, + "nonew": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": false, + "trailing": true, + "sub": true, + "maxlen": 80 +} diff --git a/external-server/.npmignore b/external-server/.npmignore new file mode 100644 index 0000000..7ec7473 --- /dev/null +++ b/external-server/.npmignore @@ -0,0 +1,16 @@ +.idea +.project +*.sublime-* +.DS_Store +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.swp +*.swo +node_modules +coverage +*.tgz +*.xml diff --git a/external-server/client/README.md b/external-server/client/README.md new file mode 100644 index 0000000..dd00c9e --- /dev/null +++ b/external-server/client/README.md @@ -0,0 +1,3 @@ +## Client + +This is the place for your application front-end files. diff --git a/external-server/common/models/coffee-shop.js b/external-server/common/models/coffee-shop.js new file mode 100644 index 0000000..5812a03 --- /dev/null +++ b/external-server/common/models/coffee-shop.js @@ -0,0 +1,3 @@ +module.exports = function(CoffeeShop) { + +}; diff --git a/external-server/common/models/coffee-shop.json b/external-server/common/models/coffee-shop.json new file mode 100644 index 0000000..fd7565b --- /dev/null +++ b/external-server/common/models/coffee-shop.json @@ -0,0 +1,18 @@ +{ + "name": "CoffeeShop", + "base": "PersistedModel", + "properties": { + "name": { + "type": "string", + "required": true + }, + "city": { + "type": "string", + "required": true + } + }, + "validations": [], + "relations": {}, + "acls": [], + "methods": [] +} diff --git a/external-server/package.json b/external-server/package.json new file mode 100644 index 0000000..2ca8e7a --- /dev/null +++ b/external-server/package.json @@ -0,0 +1,20 @@ +{ + "name": "external-server", + "version": "1.0.0", + "main": "server/server.js", + "scripts": { + "pretest": "jshint ." + }, + "dependencies": { + "compression": "^1.0.3", + "cors": "^2.5.2", + "loopback": "^2.22.0", + "loopback-boot": "^2.6.5", + "loopback-component-explorer": "^2.1.0", + "loopback-datasource-juggler": "^2.39.0", + "serve-favicon": "^2.0.1" + }, + "devDependencies": { + "jshint": "^2.5.6" + } +} diff --git a/external-server/server/boot/authentication.js b/external-server/server/boot/authentication.js new file mode 100644 index 0000000..a87cd08 --- /dev/null +++ b/external-server/server/boot/authentication.js @@ -0,0 +1,4 @@ +module.exports = function enableAuthentication(server) { + // enable authentication + server.enableAuth(); +}; diff --git a/external-server/server/boot/create-sample-models.js b/external-server/server/boot/create-sample-models.js new file mode 100644 index 0000000..cd0858c --- /dev/null +++ b/external-server/server/boot/create-sample-models.js @@ -0,0 +1,10 @@ +module.exports = function(app) { + app.models.CoffeeShop.create([ + {name: 'Bel Cafe', city: 'Vancouver'}, + {name: 'Three Bees Coffee House', city: 'San Mateo'}, + {name: 'Caffe Artigiano', city: 'Vancouver'} + ], function(err) { + if (err) throw err; + console.log('> coffee shop models created'); + }); +}; diff --git a/external-server/server/boot/root.js b/external-server/server/boot/root.js new file mode 100644 index 0000000..e106142 --- /dev/null +++ b/external-server/server/boot/root.js @@ -0,0 +1,6 @@ +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/external-server/server/component-config.json b/external-server/server/component-config.json new file mode 100644 index 0000000..bbe9320 --- /dev/null +++ b/external-server/server/component-config.json @@ -0,0 +1,5 @@ +{ + "loopback-component-explorer": { + "mountPath": "/explorer" + } +} \ No newline at end of file diff --git a/external-server/server/config.json b/external-server/server/config.json new file mode 100644 index 0000000..65efaea --- /dev/null +++ b/external-server/server/config.json @@ -0,0 +1,27 @@ +{ + "restApiRoot": "/api", + "host": "0.0.0.0", + "port": 3001, + "remoting": { + "context": { + "enableHttpContext": false + }, + "rest": { + "normalizeHttpPath": false, + "xml": false + }, + "json": { + "strict": false, + "limit": "100kb" + }, + "urlencoded": { + "extended": true, + "limit": "100kb" + }, + "cors": false, + "errorHandler": { + "disableStackTrace": false + } + }, + "legacyExplorer": false +} \ No newline at end of file diff --git a/external-server/server/datasources.json b/external-server/server/datasources.json new file mode 100644 index 0000000..d6caf56 --- /dev/null +++ b/external-server/server/datasources.json @@ -0,0 +1,6 @@ +{ + "db": { + "name": "db", + "connector": "memory" + } +} diff --git a/external-server/server/middleware.json b/external-server/server/middleware.json new file mode 100644 index 0000000..ea6540d --- /dev/null +++ b/external-server/server/middleware.json @@ -0,0 +1,34 @@ +{ + "initial:before": { + "loopback#favicon": {} + }, + "initial": { + "compression": {}, + "cors": { + "params": { + "origin": true, + "credentials": true, + "maxAge": 86400 + } + } + }, + "session": { + }, + "auth": { + }, + "parse": { + }, + "routes": { + "loopback#rest": { + "paths": ["${restApiRoot}"] + } + }, + "files": { + }, + "final": { + "loopback#urlNotFound": {} + }, + "final:after": { + "loopback#errorHandler": {} + } +} \ No newline at end of file diff --git a/external-server/server/model-config.json b/external-server/server/model-config.json new file mode 100644 index 0000000..1de89d1 --- /dev/null +++ b/external-server/server/model-config.json @@ -0,0 +1,39 @@ +{ + "_meta": { + "sources": [ + "loopback/common/models", + "loopback/server/models", + "../common/models", + "./models" + ], + "mixins": [ + "loopback/common/mixins", + "loopback/server/mixins", + "../common/mixins", + "./mixins" + ] + }, + "User": { + "dataSource": "db" + }, + "AccessToken": { + "dataSource": "db", + "public": false + }, + "ACL": { + "dataSource": "db", + "public": false + }, + "RoleMapping": { + "dataSource": "db", + "public": false + }, + "Role": { + "dataSource": "db", + "public": false + }, + "CoffeeShop": { + "dataSource": "db", + "public": true + } +} diff --git a/external-server/server/server.js b/external-server/server/server.js new file mode 100644 index 0000000..620ce22 --- /dev/null +++ b/external-server/server/server.js @@ -0,0 +1,27 @@ +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(); +}); \ No newline at end of file diff --git a/local-server/.editorconfig b/local-server/.editorconfig new file mode 100644 index 0000000..3ee22e5 --- /dev/null +++ b/local-server/.editorconfig @@ -0,0 +1,13 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/local-server/.eslintrc b/local-server/.eslintrc new file mode 100644 index 0000000..9f7dcc6 --- /dev/null +++ b/local-server/.eslintrc @@ -0,0 +1,7 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "extends": "eslint:recommended" +} diff --git a/local-server/.jshintignore b/local-server/.jshintignore new file mode 100644 index 0000000..ee8c771 --- /dev/null +++ b/local-server/.jshintignore @@ -0,0 +1,2 @@ +/client/ +/node_modules/ diff --git a/local-server/.jshintrc b/local-server/.jshintrc new file mode 100644 index 0000000..feb0928 --- /dev/null +++ b/local-server/.jshintrc @@ -0,0 +1,21 @@ +{ + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "eqeqeq": true, + "eqnull": true, + "immed": true, + "indent": 2, + "latedef": "nofunc", + "newcap": true, + "nonew": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": false, + "trailing": true, + "sub": true, + "maxlen": 80 +} diff --git a/local-server/.npmignore b/local-server/.npmignore new file mode 100644 index 0000000..7ec7473 --- /dev/null +++ b/local-server/.npmignore @@ -0,0 +1,16 @@ +.idea +.project +*.sublime-* +.DS_Store +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.swp +*.swo +node_modules +coverage +*.tgz +*.xml diff --git a/local-server/client/README.md b/local-server/client/README.md new file mode 100644 index 0000000..dd00c9e --- /dev/null +++ b/local-server/client/README.md @@ -0,0 +1,3 @@ +## Client + +This is the place for your application front-end files. diff --git a/local-server/common/models/magazine.js b/local-server/common/models/magazine.js new file mode 100644 index 0000000..de54749 --- /dev/null +++ b/local-server/common/models/magazine.js @@ -0,0 +1,22 @@ +module.exports = function(Magazine) { + + Magazine.observe('before save', function(ctx, next) { + + console.log('> Magazine before save triggered'); + + var model = ctx.instance; + var coffeeShopService = Magazine.app.dataSources.CoffeeShopService; + + coffeeShopService.find(function(err, response, context) { + if (err) throw err; //error making request + if (response.error) { + next('> response error: ' + response.error.stack); + } + model.coffeeShops = response; + console.log('> coffee shops fetched successfully from remote server'); + //verify via `curl localhost:3000/api/Magazines` + next(); + }); + }); + +}; diff --git a/local-server/common/models/magazine.json b/local-server/common/models/magazine.json new file mode 100644 index 0000000..ae42111 --- /dev/null +++ b/local-server/common/models/magazine.json @@ -0,0 +1,18 @@ +{ + "name": "Magazine", + "base": "PersistedModel", + "properties": { + "name": { + "type": "string" + }, + "coffeeShops": { + "type": [ + "object" + ] + } + }, + "validations": [], + "relations": {}, + "acls": [], + "methods": [] +} diff --git a/local-server/package.json b/local-server/package.json new file mode 100644 index 0000000..d8b68c0 --- /dev/null +++ b/local-server/package.json @@ -0,0 +1,23 @@ +{ + "name": "local-server", + "version": "1.0.0", + "main": "server/server.js", + "scripts": { + "lint": "eslint **/*.js", + "test": "mocha .", + "posttest": "npm run lint" + }, + "dependencies": { + "compression": "^1.0.3", + "cors": "^2.5.2", + "loopback": "^2.22.0", + "loopback-boot": "^2.6.5", + "loopback-component-explorer": "^2.1.0", + "loopback-datasource-juggler": "^2.39.0", + "serve-favicon": "^2.0.1", + "loopback-connector-rest": "^1.5.0" + }, + "devDependencies": { + "jshint": "^2.5.6" + } +} diff --git a/local-server/server/boot/authentication.js b/local-server/server/boot/authentication.js new file mode 100644 index 0000000..a87cd08 --- /dev/null +++ b/local-server/server/boot/authentication.js @@ -0,0 +1,4 @@ +module.exports = function enableAuthentication(server) { + // enable authentication + server.enableAuth(); +}; diff --git a/local-server/server/boot/create-sample-model.js b/local-server/server/boot/create-sample-model.js new file mode 100644 index 0000000..4630b50 --- /dev/null +++ b/local-server/server/boot/create-sample-model.js @@ -0,0 +1,8 @@ +module.exports = function(app) { + app.models.Magazine.create([ + {name: 'Bean around the world'} + ], function(err) { + if (err) throw err; + console.log('> magazine model created'); + }); +}; diff --git a/local-server/server/boot/root.js b/local-server/server/boot/root.js new file mode 100644 index 0000000..e106142 --- /dev/null +++ b/local-server/server/boot/root.js @@ -0,0 +1,6 @@ +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/local-server/server/component-config.json b/local-server/server/component-config.json new file mode 100644 index 0000000..bbe9320 --- /dev/null +++ b/local-server/server/component-config.json @@ -0,0 +1,5 @@ +{ + "loopback-component-explorer": { + "mountPath": "/explorer" + } +} \ No newline at end of file diff --git a/local-server/server/config.json b/local-server/server/config.json new file mode 100644 index 0000000..fad1436 --- /dev/null +++ b/local-server/server/config.json @@ -0,0 +1,27 @@ +{ + "restApiRoot": "/api", + "host": "0.0.0.0", + "port": 3000, + "remoting": { + "context": { + "enableHttpContext": false + }, + "rest": { + "normalizeHttpPath": false, + "xml": false + }, + "json": { + "strict": false, + "limit": "100kb" + }, + "urlencoded": { + "extended": true, + "limit": "100kb" + }, + "cors": false, + "errorHandler": { + "disableStackTrace": false + } + }, + "legacyExplorer": false +} \ No newline at end of file diff --git a/local-server/server/datasources.json b/local-server/server/datasources.json new file mode 100644 index 0000000..803e01d --- /dev/null +++ b/local-server/server/datasources.json @@ -0,0 +1,21 @@ +{ + "db": { + "name": "db", + "connector": "memory" + }, + "CoffeeShopService": { + "name": "CoffeeShopService", + "connector": "rest", + "operations": [ + { + "template": { + "method": "GET", + "url": "http://localhost:3001/api/CoffeeShops" + }, + "functions": { + "find": [] + } + } + ] + } +} diff --git a/local-server/server/middleware.json b/local-server/server/middleware.json new file mode 100644 index 0000000..ea6540d --- /dev/null +++ b/local-server/server/middleware.json @@ -0,0 +1,34 @@ +{ + "initial:before": { + "loopback#favicon": {} + }, + "initial": { + "compression": {}, + "cors": { + "params": { + "origin": true, + "credentials": true, + "maxAge": 86400 + } + } + }, + "session": { + }, + "auth": { + }, + "parse": { + }, + "routes": { + "loopback#rest": { + "paths": ["${restApiRoot}"] + } + }, + "files": { + }, + "final": { + "loopback#urlNotFound": {} + }, + "final:after": { + "loopback#errorHandler": {} + } +} \ No newline at end of file diff --git a/local-server/server/model-config.json b/local-server/server/model-config.json new file mode 100644 index 0000000..e951f05 --- /dev/null +++ b/local-server/server/model-config.json @@ -0,0 +1,33 @@ +{ + "_meta": { + "sources": [ + "loopback/common/models", + "loopback/server/models", + "../common/models", + "./models" + ] + }, + "User": { + "dataSource": "db" + }, + "AccessToken": { + "dataSource": "db", + "public": false + }, + "ACL": { + "dataSource": "db", + "public": false + }, + "RoleMapping": { + "dataSource": "db", + "public": false + }, + "Role": { + "dataSource": "db", + "public": false + }, + "Magazine": { + "dataSource": "db", + "public": true + } +} diff --git a/local-server/server/server.js b/local-server/server/server.js new file mode 100644 index 0000000..6c12246 --- /dev/null +++ b/local-server/server/server.js @@ -0,0 +1,25 @@ +var loopback = require('loopback'); +var boot = require('loopback-boot'); + +var app = module.exports = loopback(); + +// boot scripts mount components like REST API +boot(app, __dirname); + +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); //eslint-disable-line no-console + 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); //eslint-disable-line no-console + } + }); +}; + +// start the server if `$ node server.js` +if (require.main === module) { + app.start(); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6b5a8d0 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "loopback-example-rest-connector", + "version": "1.0.0", + "description": "LoopBack REST connector example", + "repository": { + "type": "git", + "url": "git+https://github.com/strongloop/loopback-example-rest-connector.git" + }, + "keywords": [ + "LoopBack", + "REST", + "connector" + ], + "author": "Simon Ho", + "license": "MIT", + "bugs": { + "url": "https://github.com/strongloop/loopback-example-rest-connector/issues" + }, + "homepage": "https://github.com/strongloop/loopback-example-rest-connector#readme", + "main": "index.js", + "scripts": { + "test": "tape tests/**/*.js" + }, + "devDependencies": { + "tape": "^4.2.0" + } +} diff --git a/tests/smoke.js b/tests/smoke.js new file mode 100644 index 0000000..b044d26 --- /dev/null +++ b/tests/smoke.js @@ -0,0 +1,6 @@ +var test = require('tape'); + +test('smoke test', function(t) { + t.plan(1); + t.equal(1, 1); +}); From b2af705af1f85d623bc195cbb58a3261b407cee3 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Fri, 22 Jan 2016 13:25:31 -0800 Subject: [PATCH 2/8] Add examples from loopback-connector-rest --- example/comparison/geocode-qlio.js | 25 ++++ example/comparison/geocode-request.js | 37 ++++++ example/comparison/geocode-restler.js | 43 ++++++ example/comparison/geocode-superagent.js | 21 +++ example/comparison/geocode-swagger.js | 75 +++++++++++ example/comparison/geocode.ql | 7 + example/comparison/qlio-connector/loopback.js | 18 +++ example/comparison/qlio-loopback-connector.js | 47 +++++++ example/geocode.json | 11 ++ example/rest-builder-app.js | 69 ++++++++++ example/rest-crud-app.js | 113 ++++++++++++++++ example/rest-loopback-crud.js | 123 ++++++++++++++++++ example/rest-loopback-geocode.js | 46 +++++++ 13 files changed, 635 insertions(+) create mode 100644 example/comparison/geocode-qlio.js create mode 100644 example/comparison/geocode-request.js create mode 100644 example/comparison/geocode-restler.js create mode 100644 example/comparison/geocode-superagent.js create mode 100644 example/comparison/geocode-swagger.js create mode 100644 example/comparison/geocode.ql create mode 100644 example/comparison/qlio-connector/loopback.js create mode 100644 example/comparison/qlio-loopback-connector.js create mode 100644 example/geocode.json create mode 100644 example/rest-builder-app.js create mode 100644 example/rest-crud-app.js create mode 100644 example/rest-loopback-crud.js create mode 100644 example/rest-loopback-geocode.js diff --git a/example/comparison/geocode-qlio.js b/example/comparison/geocode-qlio.js new file mode 100644 index 0000000..a97a9ad --- /dev/null +++ b/example/comparison/geocode-qlio.js @@ -0,0 +1,25 @@ +var Engine = require('ql.io-engine'); + +// Create an instance of ql.io engine +var engine = new Engine({}); + +// Define the script with two statements +// First create a virtual table +var script = "create table google.geocode on " + + " select get from \"http://maps.googleapis.com/maps/api/geocode/{format}?sensor=true&latlng={^latlng}\"" + + " using defaults format = 'json'" + + " resultset 'results'\n"; + +// Define a select statement +script += "select formatted_address from google.geocode where latlng='40.714224,-73.961452'"; + +// Run the query +engine.execute(script, function (req) { + req.on('end', function (err, results) { + console.log(results); + }) +}) + + + + diff --git a/example/comparison/geocode-request.js b/example/comparison/geocode-request.js new file mode 100644 index 0000000..789e863 --- /dev/null +++ b/example/comparison/geocode-request.js @@ -0,0 +1,37 @@ +var request = require('request'); + +var processResponse = function (error, response, body) { + if (!error) { + if (typeof body === 'string') { + body = JSON.parse(body); + } + + if (body.status === 'OK') { + console.log(body.results[0].formatted_address); + } else { + console.log('Error: ', body.status); + } + + } else { + console.log('Error: ' + response.statusCode) + console.log('Body: ', body) + } +}; + +request('http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true', processResponse); + +request.get('http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true', processResponse); + +request( + { + method: 'GET', + uri: 'http://maps.googleapis.com/maps/api/geocode/json', + qs: { + latlng: '40.714224,-73.961452', + sensor: true + } + }, + processResponse +) + + diff --git a/example/comparison/geocode-restler.js b/example/comparison/geocode-restler.js new file mode 100644 index 0000000..bda9fb5 --- /dev/null +++ b/example/comparison/geocode-restler.js @@ -0,0 +1,43 @@ +var restler = require('restler'); + +var processResponse = function (prefix, body, response) { + // console.log(body); + if (typeof body === 'string') { + body = JSON.parse(body); + } + + if (body.status === 'OK') { + console.log(prefix, 'Address: ', body.results[0].formatted_address); + } else { + console.log(prefix, 'Error: ', body.status); + } +}; + +var req1 = restler.get('http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true'); +req1.on('complete', processResponse.bind(null, '1')); + +var req2 = restler.request('http://maps.googleapis.com/maps/api/geocode/json', + { + method: 'GET', + query: { + latlng: '40.714224,-73.961452', + sensor: true + } + } +); + +req2.on('complete', processResponse.bind(null, '2')); + +var GeoService = restler.service(function (sensor) { + // this.defaults.query = {sensor: sensor ? true : false}; +}, { + baseURL: 'http://maps.googleapis.com/maps/api/geocode/' +}, { + getAddress: function (latlng, cb) { + return this.get('json', {query: {sensor: true, latlng: latlng}}).on('complete', cb); + } +}); + +var geoService = new GeoService(false); +// geoService.getAddress('40.714224,-73.961452'); +geoService.getAddress('40.714224,-73.961452', processResponse.bind(null, '3')); diff --git a/example/comparison/geocode-superagent.js b/example/comparison/geocode-superagent.js new file mode 100644 index 0000000..dff1b57 --- /dev/null +++ b/example/comparison/geocode-superagent.js @@ -0,0 +1,21 @@ +var agent = require('superagent'); + +var processResponse = function (prefix, err, response) { + var body = response.body; + if (typeof body === 'string') { + body = JSON.parse(body); + } + + if (body.status === 'OK') { + console.log(prefix, 'Address: ', body.results[0].formatted_address); + } else { + console.log(prefix, 'Error: ', body.status); + } +}; + +agent.get('http://maps.googleapis.com/maps/api/geocode/json') + .query({latlng: '40.714224,-73.961452', sensor: true}) + .end(processResponse.bind(null, '1')); + +agent.get('http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true', processResponse.bind(null, '2')); + diff --git a/example/comparison/geocode-swagger.js b/example/comparison/geocode-swagger.js new file mode 100644 index 0000000..85f9068 --- /dev/null +++ b/example/comparison/geocode-swagger.js @@ -0,0 +1,75 @@ +var apiList = +{ + apiVersion: "1.0", + swaggerVersion: "1.0", + basePath: "http://maps.googleapis.com/maps/api/", + + apis: [ + { + path: "/geocode/{format}", + description: "Google Maps Geocode API" + } + ] +}; + +var geocodeApiSpec = { + resourcePath: "/geocode", + basePath: "http://maps.googleapis.com/maps/api/", + apis: [ + { + swaggerVersion: "1.0", + apiVersion: "1.0", + path: "geocode/{format}", + description: "", + operations: [ + { + parameters: [ + { + name: "latlng", + description: "Latitude & Longitude (lat,lng)", + required: true, + dataType: "string", + paramType: "query" + }, + { + name: "sensor", + description: "Sensor", + required: true, + dataType: "boolean", + paramType: "query" + } + ], + summary: "Geocode reverse lookup", + httpMethod: "GET", + errorResponses: [ + { + reason: "Internal Error", + code: 500 + } + ], + nickname: "geocode", + responseClass: "AddressComponents" + } + + ], + models: { + AddressComponents: { + uniqueItems: false, + properties: { + formatted_address: { + uniqueItems: false, + type: "string", + required: false + }, + status: { + uniqueItems: false, + type: "string", + required: false + } + } + } + } + } + ] +} + diff --git a/example/comparison/geocode.ql b/example/comparison/geocode.ql new file mode 100644 index 0000000..1ad1ef3 --- /dev/null +++ b/example/comparison/geocode.ql @@ -0,0 +1,7 @@ +create table google.geocode on +select get from "http://maps.googleapis.com/maps/api/geocode/{format}?sensor=true&latlng={^latlng}" +using defaults format = 'json' +resultset 'results'; + +return select formatted_address from google.geocode where latlng='40.714224,-73.961452'; + diff --git a/example/comparison/qlio-connector/loopback.js b/example/comparison/qlio-connector/loopback.js new file mode 100644 index 0000000..8972c10 --- /dev/null +++ b/example/comparison/qlio-connector/loopback.js @@ -0,0 +1,18 @@ +console.log('Loading LoopbackConnector'); + +var LoopbackConnector = module.exports = + + function (table, statement, type, bag, path) { + console.log('Exporting LoopbackConnector: ', table, statement, type, bag, path); + + this.exec = function (args) { + console.log('Executing LoopbackConnector: ', args); + return args.callback(null, {headers: {}, body: {results: [ + {formatted_address: '123 Street'} + ]}}); + } + }; + +LoopbackConnector.connectorName = 'loopback'; + + diff --git a/example/comparison/qlio-loopback-connector.js b/example/comparison/qlio-loopback-connector.js new file mode 100644 index 0000000..76f9b68 --- /dev/null +++ b/example/comparison/qlio-loopback-connector.js @@ -0,0 +1,47 @@ +var Engine = require('ql.io-engine'); +var path = require('path'); + +console.log(__dirname); + +var engine = new Engine({ + connectors: path.join(__dirname, './qlio-connector') +}); +var script = 'create table loopback.inventory via loopback on ' + + ' select do find at "inventory where product={^product}"' + + ' using defaults format = \'json\'' + + ' resultset \'results\''; + +script += '\nselect formatted_address from loopback.inventory where product=\'p001\''; + +var inFlight, success, error, request, response; +engine.execute(script, function (req) { + /* + req.on(Engine.Events.STATEMENT_IN_FLIGHT, function() { + console.log ("Statement In_flight event"); + inFlight = true; + }); + req.on(Engine.Events.STATEMENT_SUCCESS, function() { + console.log ("Statement Success event"); + success = true; + }); + req.on(Engine.Events.STATEMENT_REQUEST, function() { + console.log ("Statement Request event"); + request = true; + }); + req.on(Engine.Events.STATEMENT_RESPONSE, function() { + console.log ("Statement Response event"); + response = true; + }); + req.on(Engine.Events.STATEMENT_ERROR, function() { + console.log ("Statement Error event"); + error = true; + }); + */ + req.on('end', function (err, results) { + console.log('Results: ', err, results); + }) +}) + + + + diff --git a/example/geocode.json b/example/geocode.json new file mode 100644 index 0000000..a01752e --- /dev/null +++ b/example/geocode.json @@ -0,0 +1,11 @@ +{ + "method": "GET", + "url": "http://maps.googleapis.com/maps/api/geocode/{format=json}", + "headers": { + "accept": "application/json" + }, + "query": { + "latlng": "{latitude},{longitude}", + "sensor": "{sensor=true}" + } +} diff --git a/example/rest-builder-app.js b/example/rest-builder-app.js new file mode 100644 index 0000000..d3d9fa7 --- /dev/null +++ b/example/rest-builder-app.js @@ -0,0 +1,69 @@ +var restConnector = require('../lib/rest-builder'); + +// Define a callback to handle the response +var processResponse = function (error, result, response) { + if (!error) { + var body = response.body; + if (typeof body === 'string') { + body = JSON.parse(body); + } + + if (body.status === 'OK') { + if (Array.isArray(result)) { + console.log('Result:', result); + } + console.log('formatted_address', body.results[0].formatted_address); + console.log('geometry.location', body.results[0].geometry.location); + } else { + console.log('Error: ', body.status); + } + + } else { + console.log('Error: ' + error) + console.log('Body: ', body) + } +}; + +// Build a REST API request using templates +var req = restConnector.get('http://maps.googleapis.com/maps/api/geocode/{format=json}') + .query({latlng: '{!latitude:number},{!longitude:number}', sensor: '{sensor=true}'}).responsePath('$.results[0].formatted_address') +// .body({x: 1, y: 'y', z: [1, 2, '{z:3}']}); + +// var schema = req.parse(); +// console.log(schema); + +// Now we can invoke the REST API using an object that provide values to the templatized variables +req.invoke({latitude: 40.714224, longitude: -73.961452, sensor: true}, processResponse); + +// The 2nd flavor is to construct a function from the request by +// specifying an array of parameter names corresponding to the templatized variables +var fn = req.operation(['latitude', 'longitude']); + +// Now we invoke the REST API as a method +fn(40.714224, -73.961452, processResponse); + +// We can also directly use request apis +restConnector.request('http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true', processResponse); + +restConnector.request({ + method: 'GET', + uri: 'http://maps.googleapis.com/maps/api/geocode/json', + qs: { + latlng: '40.714224,-73.961452', + sensor: true + } +}, processResponse); + +// Load the spec from json doc +var spec = require('./geocode.json'); +req = restConnector.fromJSON(spec); + +// Now we can invoke the REST API using an object that provide values to the templatized variables +req.invoke({latitude: 40.714224, longitude: -73.961452, sensor: true}, processResponse); + +// Lookup by address +var req2 = restConnector.get('http://maps.googleapis.com/maps/api/geocode/{format=json}') + .query({address: '{address}', sensor: '{sensor=false}', components: 'country:US'}); + +req2.invoke({address: '107 S B St, San Mateo, CA'}, processResponse); + diff --git a/example/rest-crud-app.js b/example/rest-crud-app.js new file mode 100644 index 0000000..e2c6ad5 --- /dev/null +++ b/example/rest-crud-app.js @@ -0,0 +1,113 @@ +var loopback = require('loopback'); + +// simplier way to describe model +var User = loopback.createModel('User', { + name: String, + bio: String, + approved: Boolean, + joinedAt: Date, + age: Number +}); + +console.log(User.modelName); + +var app = loopback(); + +app.set('port', process.env.PORT || 3000); +app.use(loopback.bodyParser.json({extended: false})); + +var count = 2; +var users = [new User({id: 1, name: 'Ray'}), new User({id: 2, name: 'Joe'})] + +app.get('/Users', function (req, res, next) { + res.setHeader('Content-Type', 'application/json'); + res.json(users); + res.end(); +}); + +app.post('/Users', function (req, res, next) { + res.setHeader('Content-Type', 'application/json'); + var body = req.body; + if (!body.id) { + body.id = (++count); + } + res.setHeader('Location', req.protocol + '://' + req.headers['host'] + '/' + body.id); + users.push(body); + res.status(201).json(body); + res.end(); +}); + +app.put('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.id) { + res.setHeader('Content-Type', 'application/json'); + users[i] = body; + res.end(null, 200); + return; + } + } + res.end(null, 404); +}); + +app.delete('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.params.id) { + res.setHeader('Content-Type', 'application/json'); + users.splice(i, 1); + res.end(null, 200); + return; + } + } + res.end(404); +}); + +app.get('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.params.id) { + res.setHeader('Content-Type', 'application/json'); + res.json(user); + res.end(); + return; + } + } +}); + +app.listen(app.get('port'), function (err, data) { + console.log('Server listening on 3000.'); + var RestResource = require('../lib/rest-model'); + + var rest = new RestResource('Users', 'http://localhost:3000'); + + rest.query(function (err, body, response) { + console.log(body); + }); + + rest.find(1, function (err, body, response) { + console.log(err, response && response.statusCode); + console.log(body); + }); + + rest.update(1, new User({name: 'Raymond'}), function (err, body, response) { + console.log(err, response && response.statusCode); + }); + + rest.delete(1, function (err, body, response) { + console.log(err, response && response.statusCode); + }); + + rest.create(new User({name: 'Mary'}), function (err, body, response) { + console.log(response && response.statusCode); + console.log(response && response.headers['location']); + console.log(body); + }); + + rest.query(function (err, body, response) { + console.log(body); + }); + + console.log('Press Ctrl+C to exit.'); + +}); \ No newline at end of file diff --git a/example/rest-loopback-crud.js b/example/rest-loopback-crud.js new file mode 100644 index 0000000..3ae001b --- /dev/null +++ b/example/rest-loopback-crud.js @@ -0,0 +1,123 @@ +var loopback = require("loopback"); +var app = loopback(); + +app.set('port', process.env.PORT || 3000); +app.use(loopback.bodyParser.json({extended: false})); + +var ds = loopback.createDataSource({ + connector: require("../index"), + debug: false, + baseURL: 'http://localhost:3000' +}); + +var User = ds.createModel('User', { + name: String, + bio: String, + approved: Boolean, + joinedAt: Date, + age: Number +}); + +var count = 2; +var users = [new User({id: 1, name: 'Ray'}), new User({id: 2, name: 'Joe'})] + +app.get('/Users', function (req, res, next) { + res.setHeader('Content-Type', 'application/json'); + res.json(users); + res.end(); +}); + +app.post('/Users', function (req, res, next) { + res.setHeader('Content-Type', 'application/json'); + var body = req.body; + if (!body.id) { + body.id = (++count); + } + res.setHeader('Location', req.protocol + '://' + req.headers['host'] + '/' + body.id); + users.push(body); + res.status(201).json(body); + res.end(); +}); + +app.put('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.id) { + res.setHeader('Content-Type', 'application/json'); + users[i] = body; + res.end(null, 200); + return; + } + } + res.end(null, 404); +}); + +app.delete('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.params.id) { + res.setHeader('Content-Type', 'application/json'); + users.splice(i, 1); + res.end(null, 200); + return; + } + } + res.end(404); +}); + +app.get('/Users/:id', function (req, res, next) { + for (var i = 0; i < users.length; i++) { + var user = users[i]; + if (user.id == req.params.id) { + res.setHeader('Content-Type', 'application/json'); + res.json(user); + res.end(); + return; + } + } +}); + +app.listen(app.get('port'), function (err, data) { + console.log('Server listening on 3000.'); + + User.find(function (err, user) { + console.log(user); + }); + + User.findById(1, function (err, user) { + console.log(err, user); + }); + + User.upsert(new User({id: 1, name: 'Raymond'}), function (err, user) { + console.log(err, user); + }); + + User.findById(1, function (err, user) { + console.log(err, user); + if (!err) { + user.delete(function (err, user) { + console.log(err, user); + }); + } + + }); + + /* + User.delete(1, function (err, user) { + console.log(err, user); + }); + */ + + User.create(new User({name: 'Mary'}), function (err, user) { + console.log(user); + }); + + User.find(function (err, user) { + console.log(user); + }); + + console.log('Press Ctrl+C to exit.'); + +}); + + diff --git a/example/rest-loopback-geocode.js b/example/rest-loopback-geocode.js new file mode 100644 index 0000000..696c65f --- /dev/null +++ b/example/rest-loopback-geocode.js @@ -0,0 +1,46 @@ +var loopback = require("loopback"); + +var ds = loopback.createDataSource({ + connector: require("../index"), + strictSSL: false, + debug: false, + defaults: { + "headers": { + "accept": "application/json", + "content-type": "application/json" + } + }, + operations: [ + { + template: { + "method": "GET", + "url": "http://maps.googleapis.com/maps/api/geocode/{format=json}", + "query": { + "address": "{street},{city},{zipcode}", + "sensor": "{sensor=false}" + }, + "options": { + "strictSSL": true, + "useQuerystring": true + }, + "responsePath": "$.results[0].geometry.location" + }, + functions: { + "geocode": ["street", "city", "zipcode"] + } + } + ]}); + +var model = ds.createModel('dummy'); + +var loc = { + street: '107 S B St', + city: 'San Mateo', + zipcode: '94401' +}; + +model.geocode(loc.street, loc.city, loc.zipcode, function (err, result) { + if (result && result[0]) { + console.log(result[0]); + } +}); From 9c886e1cc80092ce3ae6146774f7ace01ee25764 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Tue, 2 Feb 2016 17:51:11 -0800 Subject: [PATCH 3/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b57859f..7282c74 100644 --- a/README.md +++ b/README.md @@ -58,4 +58,4 @@ The idea is to use [`find`](https://github.com/strongloop/loopback-example-rest- --- -[Back to top](https://github.com/strongloop/loopback-example-rest-connector#loopback-example-rest-connector) +[More LoopBack examples](https://github.com/strongloop/loopback-example) From 546028efe664439a05efeabc0a3f67d843d0e7f4 Mon Sep 17 00:00:00 2001 From: Sequoia McDowell Date: Wed, 12 Oct 2016 19:13:11 -0400 Subject: [PATCH 4/8] Updating to fix jekyll formatting (#11) https://github.com/strongloop/loopback.io/issues/49 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7282c74..ce4f17b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [strongloop-website]: http://strongloop.com/ -#loopback-example-rest-connector +# loopback-example-rest-connector - [Overview](#Overview) - [Running the app](#running-the-app) @@ -19,7 +19,7 @@ this REST API. $ git clone https://github.com/strongloop/loopback-example-rest-connector.git $ cd loopback-example-rest-connector/external-server $ npm install -# node . +$ node . ``` In another shell: ``` @@ -35,7 +35,7 @@ explorer or by running `curl localhost:3000/api/Magazines`. ## FAQs The following are common questions related to using the REST connector. -##How do you perform a GET request to a remote server? +## How do you perform a GET request to a remote server? In this example, we have a REST API exposed in [model-config.json](https://github.com/strongloop/loopback-example-rest-connector/blob/master/external-server/server/model-config.json#L31) . From 9b70d28dd08b8f4564b853d8c84cda72a6f4666f Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Wed, 15 Feb 2017 11:02:32 -0800 Subject: [PATCH 5/8] Update README.md Fix instructions for rest example --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ce4f17b..171be4f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [FAQs](#faqs) ## Overview -This example demonstrates basic usage of [loopback-connector-rest](https://github.com/strongloop/loopback-connector-rest). +This example demonstrates basic use of [loopback-connector-rest](https://github.com/strongloop/loopback-connector-rest). The project has two servers: `local-server` and `external-server`. The "external" server serves a simple REST API, while the local server fetches data using @@ -16,8 +16,10 @@ this REST API. ## Running the app ``` -$ git clone https://github.com/strongloop/loopback-example-rest-connector.git -$ cd loopback-example-rest-connector/external-server +$ git clone https://github.com/strongloop/loopback-example-connector.git +$ cd loopback-example-connector +$ git checkout rest +$ cd external-server $ npm install $ node . ``` @@ -55,7 +57,3 @@ request. For example, we name our property `find` because we will trigger the request using `Magazine.find()...`. The idea is to use [`find`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L16) to make a [`GET`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L12) request to a [`url`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L13) we specify. - ---- - -[More LoopBack examples](https://github.com/strongloop/loopback-example) From b12380c85529bc18acd23c06678daa94aee2ad34 Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Wed, 15 Feb 2017 11:04:39 -0800 Subject: [PATCH 6/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 171be4f..6a396c9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [strongloop-website]: http://strongloop.com/ -# loopback-example-rest-connector +# loopback-example-connector (REST) - [Overview](#Overview) - [Running the app](#running-the-app) From 95a843c134c14284fb7ddf9d8f7ca5ed4f5e1ba2 Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Wed, 15 Feb 2017 11:05:21 -0800 Subject: [PATCH 7/8] Update README.md Fix url of repo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a396c9..ece3928 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ this REST API. ## Running the app ``` -$ git clone https://github.com/strongloop/loopback-example-connector.git +$ git clone https://github.com/strongloop-community/loopback-example-connector.git $ cd loopback-example-connector $ git checkout rest $ cd external-server From 420219b2f04de366af325201a8936de08118a435 Mon Sep 17 00:00:00 2001 From: jannyHou Date: Thu, 28 Dec 2017 15:21:03 -0500 Subject: [PATCH 8/8] doc: update link --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ece3928..e0d3326 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ explorer or by running `curl localhost:3000/api/Magazines`. The following are common questions related to using the REST connector. ## How do you perform a GET request to a remote server? -In this example, we have a REST API exposed in [model-config.json](https://github.com/strongloop/loopback-example-rest-connector/blob/master/external-server/server/model-config.json#L31) +In this example, we have a REST API exposed in [model-config.json](https://github.com/strongloop-community/loopback-example-connector/blob/rest/external-server/server/model-config.json#L31) . To make a request to the remote server, declare new datasource that uses the -REST connector in the local [datasources.json](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L6-L20). +REST connector in the local [datasources.json](https://github.com/strongloop-community/loopback-example-connector/blob/rest/local-server/server/datasources.json#L6-L20). A few things to note in this file is the `connector` property's value is `rest` and there is an `operations` property that takes an array of objects. @@ -56,4 +56,4 @@ The `function` property is the name of the property you will use to trigger the request. For example, we name our property `find` because we will trigger the request using `Magazine.find()...`. -The idea is to use [`find`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L16) to make a [`GET`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L12) request to a [`url`](https://github.com/strongloop/loopback-example-rest-connector/blob/master/local-server/server/datasources.json#L13) we specify. +The idea is to use [`find`](https://github.com/strongloop-community/loopback-example-connector/blob/rest/local-server/server/datasources.json#L16) to make a [`GET`](https://github.com/strongloop-community/loopback-example-connector/blob/rest/local-server/server/datasources.json#L12) request to a [`url`](https://github.com/strongloop-community/loopback-example-connector/blob/rest/local-server/server/datasources.json#L13) we specify.