Skip to content

Commit 3837caf

Browse files
Merge pull request #61 from theKunte/natalia-issue6-temp
[Task] 4 Implement Azure Function for users/{user_id}/tasks/{task_id} API #6 by Natalia
2 parents 75f94fd + cfdacb8 commit 3837caf

File tree

5 files changed

+179
-0
lines changed

5 files changed

+179
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ typings/
7171
# dotenv environment variables file
7272
.env
7373
.env.test
74+
.vscode
7475

7576
# parcel-bundler cache (https://parceljs.org/)
7677
.cache

functions/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ venv/
105105
ENV/
106106
env.bak/
107107
venv.bak/
108+
.vscode
108109

109110
# Spyder project settings
110111
.spyderproject
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import logging
2+
import os
3+
import pyodbc
4+
import azure.functions as func
5+
6+
#GET API method function
7+
def get(param1, param2):
8+
#connects to db
9+
cnxn = connect()
10+
cursor = cnxn.cursor()
11+
logging.info('opened connection')
12+
logging.info('Going to execute select query')
13+
try:
14+
#Get task title, description and user name by userId and taskId
15+
sql_query = ("""SELECT tasks.title, tasks.description, CONCAT (users.firstName, ' ', users.lastName) AS "user"
16+
FROM [dbo].[tasks] JOIN [dbo].[users]
17+
on [dbo].[tasks].userId = [dbo].[users].userId
18+
WHERE [dbo].[users].userId = ? AND [dbo].[tasks].taskId = ?""")
19+
cursor.execute(sql_query, param1, param2)
20+
logging.info('Executed the query')
21+
data = cursor.fetchall()
22+
logging.info(f"Got result: {data}")
23+
return data
24+
#irrespective of results, closes connection
25+
finally:
26+
cursor.close()
27+
cnxn.close()
28+
logging.info('Closed the connection')
29+
30+
#POST API method function
31+
def post(param):
32+
return ('You selected POST method with {param} values. Functionality under construction')
33+
# STARTER CODE FOR NEXT SPRINT, SQL QUERY TESTED
34+
# #insert row into tasks table / create a new task
35+
# #createdDate #'20120618 10:34:09 AM' and title/description are hardcoded for sprint1, update with automated date stamp and url params later
36+
# sql_query = ("""INSERT INTO dbo.tasks (userId, title, description, createdDate)
37+
# VALUES (?, ?, ?, '20120618 10:34:09 AM')""")
38+
# cursor.execute(sql_query, userId, 'Do It', 'Almost like Nike motto')
39+
# logging.info('Executed the query')
40+
41+
#UPDATE API method function
42+
def update(param1, param2):
43+
#connects to db
44+
cnxn = connect()
45+
cursor = cnxn.cursor()
46+
logging.info('opened connection')
47+
logging.info('Going to execute update query')
48+
try:
49+
# update task: title and description. Client passes userId and taskId,
50+
# for sprint 1 other fields are HARDCODED
51+
sql_query = ("""UPDATE [dbo].[tasks]
52+
SET title = 'Title updated by team1', description = 'Description updated by team1'
53+
WHERE userId = ? AND taskId = ?""")
54+
rowcount = cursor.execute(sql_query, param1, param2).rowcount
55+
logging.info(f"Executed the query: {rowcount} rows affected")
56+
#commits changes to db
57+
cnxn.commit()
58+
return rowcount
59+
#irrespective of results, closes connection
60+
finally:
61+
cursor.close()
62+
cnxn.close()
63+
logging.info('Closed the connection')
64+
65+
#DELETE API method function
66+
def delete(param):
67+
return ('You selected POST method with {param} values. Functionality under construction')
68+
# STARTER CODE FOR NEXT SPRINT, SQL QUERY TESTED
69+
# # #delete row, client passes in userId and taskId
70+
# sql_query = ("""DELETE FROM [dbo].[tasks] WHERE userId = ? AND taskId = ?""")
71+
# cursor.execute(sql_query, userId, taskId)
72+
# logging.info('Executed the query')
73+
# cnxn.commit()
74+
75+
#connect to db function
76+
def connect():
77+
try:
78+
#creates connection string
79+
db_server = os.environ["ENV_DATABASE_SERVER"]
80+
db_name = os.environ["ENV_DATABASE_NAME"]
81+
db_username = os.environ["ENV_DATABASE_USERNAME"]
82+
db_password = os.environ["ENV_DATABASE_PASSWORD"]
83+
driver = '{ODBC Driver 17 for SQL Server}'
84+
conn_string = "Driver={};Server={};Database={};Uid={};Pwd={};Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;".format(
85+
driver, db_server, db_name, db_username, db_password)
86+
87+
# when passwords are permitted be saved to the config of the Azure function app,
88+
# using a single connection string value, saved to the config of the app,
89+
# is more economical : <conn_string = os.getenv('SQL_CONNECTION_STRING')>, get the string
90+
# from "Connection strings" menu on the left, in the database of interest
91+
#creates and returns connection variable
92+
cnxn = pyodbc.connect(conn_string)
93+
return cnxn
94+
except Exception:
95+
print ("Unable to connect to db. Code 503: Service unavailable")
96+
97+
#MAIN FUNCTION
98+
def main(req: func.HttpRequest) -> func.HttpResponse:
99+
logging.info('Python HTTP trigger function processed a request.')
100+
101+
#collects parameters passed in url
102+
userId = req.params.get('userId')
103+
taskId = req.params.get('taskId')
104+
logging.info('Trying to get userId and taskId')
105+
if (not userId) and (not taskId):
106+
logging.info("Got neither userId nor taskId")
107+
try:
108+
req_body = req.get_json()
109+
except ValueError:
110+
pass
111+
else:
112+
userId = req_body.get('userId')
113+
taskId = req_body.get('taskId')
114+
if userId and taskId:
115+
logging.info(f"Got userId:{userId} and taskId: {taskId}")
116+
117+
#determines which API method was requested, and calls the API method
118+
method = req.method
119+
if not method:
120+
logging.critical('No method available')
121+
raise Exception('No method passed')
122+
123+
try:
124+
#if GET method is selected, it executes here
125+
if method == "GET":
126+
getResult = get(userId, taskId)
127+
return func.HttpResponse(f"This {method} method was called. You entered {userId} as userId and {taskId} as taskId. Result: {getResult}")
128+
129+
#if POST method is selected, it executes here
130+
if method == "POST":
131+
postResult = post(method)
132+
return func.HttpResponse(f"Temp results: {postResult}")
133+
134+
#if UPDATE method is selected, it executes here
135+
if method == "UPDATE":
136+
updateResult = update(userId, taskId)
137+
return func.HttpResponse(f"This {method} method was called. You entered {userId} as userId and {taskId} as taskId. Result: {updateResult}")
138+
139+
#if DELETE method is selected, it executes here
140+
if method == "DELETE":
141+
deleteResult = delete(method)
142+
return func.HttpResponse(f"Temp results: {deleteResult}")
143+
#displays erros encountered when API methods were called
144+
except Exception as e:
145+
return func.HttpResponse("Error: %s" % str(e), status_code=500)
146+
#prompts clients to pass url parameters
147+
else:
148+
logging.info('Got only one of userId and taskId')
149+
return func.HttpResponse(
150+
"This HTTP triggered function executed successfully. Pass a method, userId and taskId for an appropriate response.",
151+
status_code=200
152+
)
153+
logging.info('Finishing the function without error')
154+
return func.HttpResponse("Nothing done")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"authLevel": "anonymous",
6+
"type": "httpTrigger",
7+
"direction": "in",
8+
"name": "req",
9+
"methods": [
10+
"get",
11+
"post",
12+
"delete",
13+
"update"
14+
]
15+
},
16+
{
17+
"type": "http",
18+
"direction": "out",
19+
"name": "$return"
20+
}
21+
]
22+
}

functions/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
azure-functions
66
pyodbc
77
pypyodbc
8+

0 commit comments

Comments
 (0)