Skip to content

Commit 61bb43d

Browse files
committed
initial commit
1 parent cf877ee commit 61bb43d

9 files changed

+432
-35
lines changed

.gitignore

+20-35
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
55

66
# User-specific files
7-
*.rsuser
87
*.suo
98
*.user
109
*.userosscache
@@ -13,23 +12,17 @@
1312
# User-specific files (MonoDevelop/Xamarin Studio)
1413
*.userprefs
1514

16-
# Mono auto generated files
17-
mono_crash.*
18-
1915
# Build results
2016
[Dd]ebug/
2117
[Dd]ebugPublic/
2218
[Rr]elease/
2319
[Rr]eleases/
2420
x64/
2521
x86/
26-
[Aa][Rr][Mm]/
27-
[Aa][Rr][Mm]64/
2822
bld/
2923
[Bb]in/
3024
[Oo]bj/
3125
[Ll]og/
32-
[Ll]ogs/
3326

3427
# Visual Studio 2015/2017 cache/options directory
3528
.vs/
@@ -43,10 +36,9 @@ Generated\ Files/
4336
[Tt]est[Rr]esult*/
4437
[Bb]uild[Ll]og.*
4538

46-
# NUnit
39+
# NUNIT
4740
*.VisualState.xml
4841
TestResult.xml
49-
nunit-*.xml
5042

5143
# Build Results of an ATL Project
5244
[Dd]ebugPS/
@@ -60,14 +52,15 @@ BenchmarkDotNet.Artifacts/
6052
project.lock.json
6153
project.fragment.lock.json
6254
artifacts/
55+
**/Properties/launchSettings.json
6356

6457
# StyleCop
6558
StyleCopReport.xml
6659

6760
# Files built by Visual Studio
6861
*_i.c
6962
*_p.c
70-
*_h.h
63+
*_i.h
7164
*.ilk
7265
*.meta
7366
*.obj
@@ -84,7 +77,6 @@ StyleCopReport.xml
8477
*.tlh
8578
*.tmp
8679
*.tmp_proj
87-
*_wpftmp.csproj
8880
*.log
8981
*.vspscc
9082
*.vssscc
@@ -127,6 +119,9 @@ _ReSharper*/
127119
*.[Rr]e[Ss]harper
128120
*.DotSettings.user
129121

122+
# JustCode is a .NET coding add-in
123+
.JustCode
124+
130125
# TeamCity is a build add-in
131126
_TeamCity*
132127

@@ -184,8 +179,6 @@ PublishScripts/
184179

185180
# NuGet Packages
186181
*.nupkg
187-
# NuGet Symbol Packages
188-
*.snupkg
189182
# The packages folder can be ignored because of Package Restore
190183
**/[Pp]ackages/*
191184
# except build/, which is used as an MSBuild target.
@@ -210,14 +203,12 @@ BundleArtifacts/
210203
Package.StoreAssociation.xml
211204
_pkginfo.txt
212205
*.appx
213-
*.appxbundle
214-
*.appxupload
215206

216207
# Visual Studio cache files
217208
# files ending in .cache can be ignored
218209
*.[Cc]ache
219210
# but keep track of directories ending in .cache
220-
!?*.[Cc]ache/
211+
!*.[Cc]ache/
221212

222213
# Others
223214
ClientBin/
@@ -230,7 +221,7 @@ ClientBin/
230221
*.publishsettings
231222
orleans.codegen.cs
232223

233-
# Including strong name files can present a security risk
224+
# Including strong name files can present a security risk
234225
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
235226
#*.snk
236227

@@ -261,9 +252,6 @@ ServiceFabricBackup/
261252
*.bim.layout
262253
*.bim_*.settings
263254
*.rptproj.rsuser
264-
*- [Bb]ackup.rdl
265-
*- [Bb]ackup ([0-9]).rdl
266-
*- [Bb]ackup ([0-9][0-9]).rdl
267255

268256
# Microsoft Fakes
269257
FakesAssemblies/
@@ -299,8 +287,12 @@ paket-files/
299287
# FAKE - F# Make
300288
.fake/
301289

302-
# CodeRush personal settings
303-
.cr/personal
290+
# JetBrains Rider
291+
.idea/
292+
*.sln.iml
293+
294+
# CodeRush
295+
.cr/
304296

305297
# Python Tools for Visual Studio (PTVS)
306298
__pycache__/
@@ -325,7 +317,7 @@ __pycache__/
325317
# OpenCover UI analysis results
326318
OpenCover/
327319

328-
# Azure Stream Analytics local run output
320+
# Azure Stream Analytics local run output
329321
ASALocalRun/
330322

331323
# MSBuild Binary and Structured Log
@@ -334,17 +326,10 @@ ASALocalRun/
334326
# NVidia Nsight GPU debugger configuration file
335327
*.nvuser
336328

337-
# MFractors (Xamarin productivity tool) working folder
329+
# MFractors (Xamarin productivity tool) working folder
338330
.mfractor/
339331

340-
# Local History for Visual Studio
341-
.localhistory/
342-
343-
# BeatPulse healthcheck temp database
344-
healthchecksdb
345-
346-
# Backup folder for Package Reference Convert tool in Visual Studio 2017
347-
MigrationBackup/
348-
349-
# Ionide (cross platform F# VS Code tools) working folder
350-
.ionide/
332+
# Additional Files
333+
venv/
334+
env/
335+
env.*

.vscode/launch.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python: Flask",
9+
"type": "python",
10+
"request": "launch",
11+
"module": "flask",
12+
"env": {
13+
"FLASK_APP": "app.py",
14+
"FLASK_ENV": "development",
15+
"FLASK_DEBUG": "0"
16+
},
17+
"args": [
18+
"run",
19+
"--no-debugger",
20+
"--no-reload"
21+
],
22+
"jinja": true
23+
}
24+
]
25+
}

.vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"python.pythonPath": "venv\\Scripts\\python.exe",
3+
"cSpell.words": [
4+
"pyodbc"
5+
]
6+
}

app.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import sys
2+
import os
3+
from flask import Flask
4+
from flask_restful import reqparse, abort, Api, Resource
5+
import json
6+
import pyodbc
7+
8+
# Initialize Flask
9+
app = Flask(__name__)
10+
11+
# Setup Flask Restful framework
12+
api = Api(app)
13+
parser = reqparse.RequestParser()
14+
parser.add_argument('customer')
15+
16+
# Create connection to Azure SQL
17+
conn = pyodbc.connect(os.environ['SQLAZURECONNSTR_WWIF'])
18+
19+
class Queryable(Resource):
20+
def executeQueryJson(self, verb, payload=None):
21+
result = {}
22+
cursor = conn.cursor()
23+
entity = type(self).__name__.lower()
24+
procedure = f"web.{verb}_{entity}"
25+
try:
26+
if payload:
27+
cursor.execute(f"EXEC {procedure} ?", json.dumps(payload))
28+
else:
29+
cursor.execute(f"EXEC {procedure}")
30+
31+
result = cursor.fetchone()
32+
33+
if result:
34+
result = json.loads(result[0])
35+
else:
36+
result = {}
37+
38+
cursor.commit()
39+
except:
40+
print("Unexpected error:", sys.exc_info()[0])
41+
raise
42+
finally:
43+
cursor.close()
44+
45+
return result
46+
47+
# Customer Class
48+
class Customer(Queryable):
49+
def get(self, customer_id):
50+
customer = {}
51+
customer["CustomerID"] = customer_id
52+
result = self.executeQueryJson("get", customer)
53+
return result, 200
54+
55+
def put(self):
56+
args = parser.parse_args()
57+
customer = json.loads(args['customer'])
58+
result = self.executeQueryJson("put", customer)
59+
return result, 201
60+
61+
def patch(self, customer_id):
62+
args = parser.parse_args()
63+
customer = json.loads(args['customer'])
64+
customer["CustomerID"] = customer_id
65+
result = self.executeQueryJson("patch", customer)
66+
return result, 202
67+
68+
def delete(self, customer_id):
69+
customer = {}
70+
customer["CustomerID"] = customer_id
71+
result = self.executeQueryJson("delete", customer)
72+
return result, 202
73+
74+
# Customers Class
75+
class Customers(Queryable):
76+
def get(self):
77+
result = self.executeQueryJson("get")
78+
return result, 200
79+
80+
81+
# Create API routes
82+
api.add_resource(Customer, '/customer', '/customer/<customer_id>')
83+
api.add_resource(Customers, '/customers')

azure-deploy.sh

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
# Make sure these values are correct for your environment
6+
resourceGroup="azure-sql-db-python-rest-api"
7+
appName="azure-sql-db-python-rest-api"
8+
location="WestUS2"
9+
10+
# Change this if you are using your own github repository
11+
gitSource="https://github.com/yorek/azure-sql-db-python-rest-api.git"
12+
13+
az group create \
14+
-n $resourceGroup \
15+
-l $location
16+
17+
az appservice plan create \
18+
-g $resourceGroup \
19+
-n "linux-plan" \
20+
--sku B1 \
21+
--is-linux
22+
23+
az webapp create \
24+
-g $resourceGroup \
25+
-n $appName \
26+
--plan "linux-plan" \
27+
--runtime "Python|3.7" \
28+
--deployment-source-url $gitSource \
29+
--deployment-source-branch master
30+
31+
az webapp config connection-string set \
32+
-g $resourceGroup \
33+
-n $appName \
34+
--settings WWIF=$SQLAZURECONNSTR_WWIF
35+
--connection-string-type=SQLAzure

requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pyodbc
2+
flask
3+
flask-restful

sample-usage.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Sample REST API usage with cUrl
2+
3+
## Get a customer
4+
5+
```bash
6+
curl -s -X GET http://localhost:5000/customer/123
7+
```
8+
9+
## Create new customer
10+
11+
```bash
12+
curl -s -X PUT http://localhost:5000/customer -d 'customer={"CustomerName": "John Doe", "PhoneNumber": "123-234-5678", "FaxNumber": "123-234-5678", "WebsiteURL": "http://www.something.com", "Delivery": { "AddressLine1": "One Microsoft Way", "PostalCode": 98052 }}'
13+
```
14+
15+
## Update customer
16+
17+
```bash
18+
curl -s -X PATCH http://localhost:5000/customer/123 -d 'customer={"CustomerName": "Jane Dean", "PhoneNumber": "231-778-5678" }'
19+
```
20+
21+
## Delete a customer
22+
23+
```bash
24+
curl -s -X DELETE http://localhost:5000/customer/123
25+
```

simple-app.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import sys
2+
import os
3+
from flask import Flask
4+
from flask_restful import reqparse, Api, Resource
5+
import json
6+
import pyodbc
7+
8+
# This is a simplified example that only support GET request.
9+
# It is meant to help you to get you started if you're new to development
10+
# and to show how simple is using Azure SQL with Python
11+
# A more complete example is in "app.py"
12+
# To run this simplified sample follow the README, but instead of running "flask run"
13+
# just run "python ./simple-app.py"
14+
# Enjoy!
15+
16+
# Initialize Flask
17+
app = Flask(__name__)
18+
19+
# Setup Flask Restful framework
20+
api = Api(app)
21+
parser = reqparse.RequestParser()
22+
parser.add_argument('customer')
23+
24+
# Create connection to Azure SQL
25+
conn = pyodbc.connect(os.environ['SQLAZURECONNSTR_WWIF'])
26+
27+
# Customer Class
28+
class Customer(Resource):
29+
def get(self, customer_id):
30+
customer = {"CustomerID": customer_id}
31+
cursor = conn.cursor()
32+
cursor.execute("EXEC web.get_customer ?", json.dumps(customer))
33+
result = json.loads(cursor.fetchone()[0])
34+
cursor.close()
35+
return result, 200
36+
37+
# Create API route to defined Customer class
38+
api.add_resource(Customer, '/customer', '/customer/<customer_id>')
39+
40+
# Start App
41+
if __name__ == '__main__':
42+
app.run()

0 commit comments

Comments
 (0)