-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttpHandler.py
More file actions
237 lines (186 loc) · 10.2 KB
/
httpHandler.py
File metadata and controls
237 lines (186 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import json
import logging
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs
# from AEq321`` import isUserRecord
# from registerUser import registerUser
# from Users import Users
# from userLogin import userLogin
# from tokenLogin import TokenLogin
from Articles import Articles
from makeArticle import makeArticle
from getArticles import getAllArticles
from getArticles import getMedArticles
from getArticles import getTechArticles
from getArticles import getStyleArticles
# Class Logger we can use for debugging our Python service. You can add a parameter here for
# specifying a log file if you want to see a stream of log data in one file.
logging.basicConfig(level=logging.DEBUG)
# BaseHTTPRequestHandler is a class from the http.server python module. http.server is a simple
# module used for creating application servers. BaseHTTPRequestHandler will help us respond to requests that arrive
# at our server, matching a specified hostname and port. For additional documentation on this module,
# you can read: https://docs.python.org/3/library/http.server.html
class httpHdlrCmBackEnd(BaseHTTPRequestHandler):
# HTTP Response code dictionary
# Add any additional response codes you might want to use
# You can look up the codes and their proper uses online
HTTP_STATUS_RESPONSE_CODES = {
'OK': HTTPStatus.OK,
'FORBIDDEN': HTTPStatus.FORBIDDEN,
'NOT_FOUND': HTTPStatus.NOT_FOUND,
'INTERNAL SEVER ERROR': HTTPStatus.INTERNAL_SERVER_ERROR
}
# Here's a function to extract GET parameters from a URL
def extract_GET_parameters(self):
# GET parameters are just stored in the path of the request, so we can just urlparse this
path = self.path
parsedPath = urlparse(path)
paramsDict = parse_qs(parsedPath.query)
logging.info('GET parameters received: ' + json.dumps(paramsDict, indent=4, sort_keys=True))
return paramsDict
# Here's a function to extract POST parameters from a POST request
def extract_POST_Body(self):
# The content-length HTTP header is where our POST data will be in the request. So we'll need to
# read the data using an IO input buffer stream built into the http.server module.
postBodyLength = int(self.headers['content-length'])
postBodyString = self.rfile.read(postBodyLength)
postBodyDict = json.loads(postBodyString)
logging.info('POST Body received: ' + json.dumps(postBodyDict, indent=4, sort_keys=True))
return postBodyDict
## GET REQUEST HANDLING ##
def do_GET(self):
# self.path here will return us the http request path entered by the client.
path = self.path
# Extract the GET parameters associated with this HTTP request and store them in a python dictionary
paramsDict = self.extract_GET_parameters()
status = self.HTTP_STATUS_RESPONSE_CODES['NOT_FOUND']
responseBody = {}
# This is a root URI or block of code that will be executed when client requests the address:
# http://localhost:8083.
if path == '/':
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
responseBody['data'] = 'Hello world'
# Here is where you define your GET endpoints
# Note that for GET, you should use the "in" format to ensure you still get the correct endpoint
# even when parameters are included
# If you want to add more endpoints, simply add more elif statements with the endpoints
# This will add a response header to the header buffer. Here, we are simply sending back
# an HTTP response header with an HTTP status code to the client.
self.send_response(status)
# This will add a header to the header buffer included in our HTTP response. Here we are specifying
# the data Content-type of our response from the server to the client.
self.send_header("Content-type", "text/html")
# The end_headers method will close the header buffer, indicating that we're not sending
# any more headers back to the client after the line below.
self.end_headers()
# Convert the Key-value python dictionary into a string which we'll use to respond to this request
response = json.dumps(responseBody)
logging.info('Response: ' + response)
# Fill the output stream with our encoded response string which will be returned to the client.
# The wfile.write() method will only accept bytes data.
byteStringResponse = response.encode('utf-8')
self.wfile.write(byteStringResponse)
## POST REQUEST HANDLING ##
def do_POST(self):
path = self.path
# Extract the POST body data from the HTTP request, and store it into a Python
# dictionary we can utilize inside any of our POST endpoints.
postBody = self.extract_POST_Body()
status = self.HTTP_STATUS_RESPONSE_CODES['NOT_FOUND']
responseBody = {}
# These path endpoints can be very picky sometimes, and are very much connected to how your DevOps
# has configured your web server. You will need to communicate with your DevOps to decide on these
# endpoint for TaasUser
if path == '/UserRegister':
# This is where you'll implement your actual service logic
# Process any POST data you are expecting to receive
response = "userNotCreated"
User = Users(postBody.get("email"),
postBody.get("username"),
postBody.get("password"))
# Collect any data you want to send back into a dictionary and send it back in the responseBody
isUserExist = isUserRecord(User.user_name)
if isUserExist == "userNotExist":
response = registerUser(User)
elif isUserExist == "userExist":
response = isUserExist
# three responses to frontend userCreated, userExist, or userNotCreated.
# userCreated user was created in DB
# userExist meaning username is already taken in DB
# userNotCreated pointing to some backend issue preventing trying to write to DB.
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
elif path == '/articleData':
response = "BIG_ERROR"
response = getAllArticles()
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
elif path == '/mediumData':
response = "BIG_ERROR"
response = getMedArticles()
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
elif path == '/techData':
response = "BIG_ERROR"
response = getTechArticles()
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
elif path == '/styleData':
response = "BIG_ERROR"
response = getStyleArticles()
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
elif path == '/createdArticle':
# This is where you'll implement your actual service logic
# Process any POST data you are expecting to receive
response = "articleNotCreated"
Article = Articles(postBody.get("article_title"),
postBody.get("author_username"),
postBody.get("author_verification"),
postBody.get("article_text_path"),
postBody.get("article_type"),
postBody.get("article_texts"),
postBody.get("article_img"))
# Collect any data you want to send back into a dictionary and send it back in the responseBody
# isUserExist = isUserRecord(User.user_name)
response = makeArticle(Article)
# three responses to frontend userCreated, userExist, or userNotCreated.
# userCreated user was created in DB
# userExist meaning username is already taken in DB
# userNotCreated pointing to some backend issue preventing trying to write to DB.
responseBody['data'] = response
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
if path == '/loginSend':
# This is where you'll implement your actual service logic
# Process any POST data you are expecting to receive
token = TokenLogin(postBody.get("username"), postBody.get("password"))
responseBody['data'] = userLogin(token)
status = self.HTTP_STATUS_RESPONSE_CODES['OK']
self.send_response(status)
self.send_header("Content-type", "application/json")
self.end_headers()
# When using the json.dumps() method, you may encounter data types which aren't easily serializable into
# a string. When working with these types of data you can include an additional parameters in the dumps()
# method, 'default=str' to let the serializer know to convert to a string when it encounters a data type
# it doesn't automatically know how to convert.
response = json.dumps(responseBody, indent=4, sort_keys=True, default=str)
logging.info('Response: ' + response)
byteStringResponse = response.encode('utf-8')
self.wfile.write(byteStringResponse)
# Turn the application server on at the specified port on localhost and fork the process.
if __name__ == '__main__':
hostName = "localhost"
# Communicate with your DevOps to pick a port for each of your services.
# Note that ports 0-1023 are reserved and cannot be used.
serverPort = 8083
appServer = HTTPServer((hostName, serverPort), httpHdlrCmBackEnd)
logging.info('Server started http://%s:%s' % (hostName, serverPort))
# Start the server and fork it. Use 'Ctrl + c' command to kill this process when running it in the foreground
# on your terminal.
try:
appServer.serve_forever()
except KeyboardInterrupt:
pass
appServer.server_close()
logging.info('Server stopped')