From e5b78ee6c0b074cade317c612993ec6c01b22de1 Mon Sep 17 00:00:00 2001 From: Jovan Popovic Date: Wed, 22 Jun 2016 13:14:40 +0200 Subject: [PATCH] Node.js REST APi Draft version of NodeJS REST API that uses SQL/JSON functions --- .gitignore | 4 +- README.md | 3 + .../nodejs-express4-rest-api/.gitignore | 5 ++ .../nodejs-express4-rest-api/README.md | 83 +++++++++++++++++ .../todo-app/nodejs-express4-rest-api/app.js | 15 ++++ .../todo-app/nodejs-express4-rest-api/db.js | 69 +++++++++++++++ .../nodejs-express4-rest-api.njsproj | 88 +++++++++++++++++++ .../nodejs-express4-rest-api/package.json | 19 ++++ .../nodejs-express4-rest-api/routes/todo.js | 71 +++++++++++++++ 9 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/.gitignore create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/README.md create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/app.js create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/db.js create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/nodejs-express4-rest-api.njsproj create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/package.json create mode 100644 samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js diff --git a/.gitignore b/.gitignore index b317c54a..dad48f39 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ samples/databases/wide-world-importers/sample-scripts/always-encrypted/PopulateA *.zip samples/features/in-memory/ticket-reservations/packages/CircularGauge.1.0.0/CreatePackageFile.bat samples/features/in-memory/ticket-reservations/TicketReservations/TicketReservations.dbmdl -samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs \ No newline at end of file +samples/databases/wide-world-importers/workload-drivers/vehicle-location-insert/MultithreadedInMemoryTableInsert/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs +*.dat +*.sln \ No newline at end of file diff --git a/README.md b/README.md index 7671a409..eb66a452 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ To work in GitHub, go to https://github.com/microsoft/sql-server-samples and for Each sample should be in its own folder with a README.md file that follows the [template](README_samples_template.md). Generated files (e.g., .exe or .bacpac) and user configuration settings (e.g., .user) should not be committed to GitHub. +## Code of Conduct +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + ## License These samples and templates are all licensed under the MIT license. See the license.txt file in the root. diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/.gitignore b/samples/features/json/todo-app/nodejs-express4-rest-api/.gitignore new file mode 100644 index 00000000..ac5caeaf --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/.gitignore @@ -0,0 +1,5 @@ +node_modules/* +bin/* +obj/* +*.sln +*.log \ No newline at end of file diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/README.md b/samples/features/json/todo-app/nodejs-express4-rest-api/README.md new file mode 100644 index 00000000..71e16865 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/README.md @@ -0,0 +1,83 @@ +# NodeJS Express4 REST API that uses SQL/JSON functionalites + +This project contains an example implementation of NodeJS REST API with CRUD operations on a simple Todo table. You can learn how to build REST API on the existing database schema using new JSON functionalities that are available in SQL Server 2016 (or higher) and Azure SQL Database. + +### Contents + +[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Run this sample](#run-this-sample)
+[Sample details](#sample-details)
+[Disclaimers](#disclaimers)
+[Related links](#related-links)
+ + + +## About this sample + +- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database +- **Key features:** JSON Functions in SQL Server 2016/Azure SQL Database - FOR JSON and OPENJSON +- **Programming Language:** JavaScript (NodeJS) +- **Authors:** Jovan Popovic + + + +## Before you begin + +To run this sample, you need the following prerequisites. + +**Software prerequisites:** + +1. SQL Server 2016 (or higher) or an Azure SQL Database +2. Visual Studio 2015 (or higher) with the NodeJS + +**Azure prerequisites:** + +1. Permission to create an Azure SQL Database + + + +## Run this sample + +1. Navigate to the folder where you have downloaded sample and run **npm install** in command window. This command will install necessary npm packages defined in project.json. + +2. From SQL Server Management Studio or Sql Server Data Tools connect to your SQL Server 2016 or Azure SQL database and execute setup.sql script that will create and populate Todo table in the database. + +3. From Visual Studio, open the **TodoApp.xproj** file from the root directory, + +4. Locate db.js file in the project, change database connection info in createConnection() method to reference your database, and build solution using Ctrl+Shift+B, right-click on project + Build, or Build/Build Solution from menu. + +5. Run sample app using F5 or Ctrl+F5, +4.1. Open /api/Todo Url to get all Todo items as a JSON array, +4.2. Open /api/Todo/1 Url to get details about a single Todo item with id 1, +4.3. Send POST, PUT, PATCH, or DELETE Http requests to update content of Todo table. + + + +## Sample details + +This sample application shows how to create simple REST API service that performs CRUD operations on a simple Todo table. +NodeJS REST API is used to implement REST Service in the example. +Service uses built-in JSON functionalities that are available in SQL Server 2016 and Azure SQL Database. + + + +## Disclaimers +The code included in this sample is not intended demonstrate some general guidances and arhitectural patterns for web development. +It contains minimal code required to create REST API. +You can easily modify this code to fit the architecture of your application. + + + +## Related Links + +For more information, see this [MSDN documentation](https://msdn.microsoft.com/en-us/library/dn921897.aspx). + +## Code of Conduct +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## License +These samples and templates are all licensed under the MIT license. See the license.txt file in the root. + +## Questions +Email questions to: sqlserversamples@microsoft.com. diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/app.js b/samples/features/json/todo-app/nodejs-express4-rest-api/app.js new file mode 100644 index 00000000..e5392350 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/app.js @@ -0,0 +1,15 @@ +var express = require('express'); +var bodyParser = require('body-parser'); + +var app = express(); +app.use(bodyParser.text()); +app.use('/todo', require('./routes/todo')); + +// catch 404 and forward to error handler +app.use(function (req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +module.exports = app; diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/db.js b/samples/features/json/todo-app/nodejs-express4-rest-api/db.js new file mode 100644 index 00000000..6dae4c28 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/db.js @@ -0,0 +1,69 @@ +function createConnection() { + + var config = { + server : "SERVER.database.windows.net", + userName: "USER", + password: "PASSWORD", + // If you're on Azure, you will need this: + options: { encrypt: true, database: 'DATABASE' } + }; + + var Connection = require('tedious').Connection; + var connection = new Connection(config); + + return connection; +} + +function createRequest(query, connection) { + var Request = require('tedious').Request; + var req = + new Request(query, + function (err, rowCount) { + if (err) { + throw err; + } + connection && connection.close(); + }); + + return req; +} + +function stream (query, connection, output, defaultContent) { + + errorHandler = function (ex) { throw ex; }; + var request = query; + if (typeof query == "string") { + request = this.createRequest(query, connection); + } + + var empty = true; + request.on('row', function (columns) { + empty = false; + output.write(columns[0].value); + }); + + request.on('done', function (rowCount, more, rows) { + if (empty) { + output.write(defaultContent); + } + output.end(); + }); + + request.on('doneProc', function (rowCount, more, rows) { + if (empty) { + output.write(defaultContent); + } + output.end(); + }); + + connection.on('connect', function (err) { + if (err) { + throw err; + } + connection.execSql(request); + }); +} + +module.exports.createConnection = createConnection; +module.exports.createRequest = createRequest; +module.exports.stream = stream; \ No newline at end of file diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/nodejs-express4-rest-api.njsproj b/samples/features/json/todo-app/nodejs-express4-rest-api/nodejs-express4-rest-api.njsproj new file mode 100644 index 00000000..fc034286 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/nodejs-express4-rest-api.njsproj @@ -0,0 +1,88 @@ + + + + 11.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + nodejs-express4-rest-api + nodejs-express4-rest-api + todo + + + + Debug + 2.0 + da18f211-dee4-4b4a-8954-4c7505dc769b + . + bin\www + + + . + . + v4.0 + {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD} + ShowAllFiles + 1337 + True + + + true + + + true + + + + + + + + + + + + + + + + + + + + + + + False + True + 0 + / + http://localhost:48022/ + False + True + http://localhost:1337 + False + + + + + + + CurrentPage + True + False + False + False + + + + + + + + + False + False + + + + + \ No newline at end of file diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/package.json b/samples/features/json/todo-app/nodejs-express4-rest-api/package.json new file mode 100644 index 00000000..1376b6f8 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/package.json @@ -0,0 +1,19 @@ +{ + "name": "nodejs-express4-rest-api", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "description": "nodejs-express4-rest-api", + "author": { + "name": "Jovan Popovic", + "email": "jovanpop@microsoft.com" + }, + "dependencies": { + "body-parser": "^1.15.2", + "debug": "^2.2.0", + "express": "^4.14.0", + "tedious": "^1.14.0" + } +} diff --git a/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js b/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js new file mode 100644 index 00000000..7eb08aa0 --- /dev/null +++ b/samples/features/json/todo-app/nodejs-express4-rest-api/routes/todo.js @@ -0,0 +1,71 @@ +var express = require('express'); +var router = express.Router(); + +var db = require('../db.js'); +var TYPES = require('tedious').TYPES; + +/* GET task listing. */ +router.get('/', function (req, res) { + db.stream("select * from todo for json path", db.createConnection(), res, '[]'); +}); + +/* GET single task. */ +router.get('/:id', function (req, res) { + + var conn = db.createConnection(); + + var request = db.createRequest("select * from todo where id = @id for json path, without_array_wrapper", conn); + request.addParameter('id', TYPES.Int, req.params.id); + db.stream(request, conn, res, '{}'); +}); + +/* POST create task. */ +router.post('/', function (req, res) { + + var connection = db.createConnection(); + var request = db.createRequest("exec createTodo @todo", connection); + + request.addParameter('todo', TYPES.NVarChar, req.body); + + connection.on('connect', function (err) { + if (err) { + throw err; + } + connection.execSql(request); + }); +}); + +/* PUT update task. */ +router.put('/:id', function (req, res) { + + var connection = db.createConnection(); + var request = db.createRequest("exec updateTodo @id, @todo", connection); + + request.addParameter('id', TYPES.Int, req.params.id); + request.addParameter('todo', TYPES.NVarChar, req.body); + + connection.on('connect', function (err) { + if (err) { + throw err; + } + connection.execSql(request); + }); +}); + +/* DELETE single task. */ +router.delete('/:id', function (req, res) { + + var connection = db.createConnection(); + var request = db.createRequest("delete from todo where id = @id", connection); + + request.addParameter('id', TYPES.Int, req.params.id); + + connection.on('connect', function (err) { + if (err) { + throw err; + } + connection.execSql(request); + }); +}); + +module.exports = router; \ No newline at end of file