1- import json
2- import jsonschema
31import os
42import requests
53
64from .errors import DemandAPIError
7-
8- SCHEMAS = [
9- "project_new" ,
10- "lineitem_new" ,
11- "project_update" ,
12- "lineitem_update" ,
13- ]
5+ from .validator import DemandAPIValidator
146
157
168class DemandAPIClient (object ):
@@ -33,27 +25,14 @@ def __init__(self, client_id=None, username=None, password=None, base_host=None)
3325 self .base_host = os .getenv ('DYNATA_DEMAND_BASE_URL' , default = 'https://api.researchnow.com' )
3426
3527 if None in [self .client_id , self .username , self .password ]:
36- raise DemandAPIError (" All authentication data is required." )
28+ raise DemandAPIError (' All authentication data is required.' )
3729
3830 self ._access_token = None
3931 self ._refresh_token = None
4032 self .auth_base_url = '{}/auth/v1' .format (self .base_host )
4133 self .base_url = '{}/sample/v1' .format (self .base_host )
4234
43- self ._load_schemas ()
44-
45- def _load_schemas (self ):
46- # Load the compiled schemas for use in validation.
47- self ._schemas = {}
48- for schema_type in SCHEMAS :
49- schema_file = open ('dynatademand/schemas/{}.json' .format (schema_type ), 'r' )
50- self ._schemas [schema_type ] = json .load (schema_file )
51- schema_file .close ()
52-
53- def _validate_object (self , schema_type , data ):
54- # jsonschema.validate will return none if there is no error,
55- # otherwise it will raise its' own error with details on the failure.
56- jsonschema .validate (self ._schemas [schema_type ], data )
35+ self .validator = DemandAPIValidator ()
5736
5837 def _check_authentication (self ):
5938 # This doesn't check if the access token is valid, just that it exists.
@@ -92,13 +71,23 @@ def _api_get(self, uri, query_params=None):
9271 return response .json ()
9372
9473 def authenticate (self ):
95- # Sends the authentication data to
74+ # Sends the authentication data to the access token endpoint.
9675 url = '{}/token/password' .format (self .auth_base_url )
97- auth_response = requests . post ( url , json = {
76+ payload = {
9877 'clientId' : self .client_id ,
9978 'password' : self .password ,
10079 'username' : self .username ,
101- })
80+ }
81+
82+ '''
83+ #TODO: Waiting for a valid schema.
84+ self.validator.validate_request(
85+ 'obtain_access_token',
86+ request_body=payload
87+ )
88+ '''
89+
90+ auth_response = requests .post (url , json = payload )
10291 if auth_response .status_code > 399 :
10392 raise DemandAPIError ('Authentication failed with status {} and error: {}' .format (
10493 auth_response .status_code ,
@@ -111,12 +100,18 @@ def authenticate(self):
111100
112101 def refresh_access_token (self ):
113102 url = '{}/token/refresh' .format (self .auth_base_url )
114- refresh_response = requests . post ( url , json = {
103+ payload = {
115104 'clientId' : self .client_id ,
116105 'refreshToken' : self ._refresh_token
117- })
106+ }
107+ # Validate the rqeuest before sending.
108+ self .validator .validate_request (
109+ 'refresh_access_token' ,
110+ request_body = payload
111+ )
112+ refresh_response = requests .post (url , json = payload )
118113 if refresh_response .status_code != 200 :
119- raise DemandAPIError (" Refreshing Access Token failed with status {} and error: {}" .format (
114+ raise DemandAPIError (' Refreshing Access Token failed with status {} and error: {}' .format (
120115 refresh_response .status_code , refresh_response .content
121116 ))
122117 response_data = refresh_response .json ()
@@ -126,49 +121,95 @@ def refresh_access_token(self):
126121
127122 def logout (self ):
128123 url = '{}/logout' .format (self .auth_base_url )
129- logout_response = requests . post ( url , json = {
124+ payload = {
130125 'clientId' : self .client_id ,
131126 'refreshToken' : self ._refresh_token ,
132127 'accessToken' : self ._access_token
133- })
128+ }
129+ self .validator .validate_request (
130+ 'logout' ,
131+ request_body = payload
132+ )
133+
134+ logout_response = requests .post (url , json = payload )
134135 if logout_response .status_code != 204 :
135- raise DemandAPIError (" Log out failed with status {} and error: {}" .format (
136+ raise DemandAPIError (' Log out failed with status {} and error: {}' .format (
136137 logout_response .status_code , logout_response .content
137138 ))
138139 return logout_response .json ()
139140
140- def get_attributes (self , country_code , language_code ):
141- return self ._api_get ('/attributes/{}/{}' .format (country_code , language_code ))
142-
143- def get_countries (self ):
144- return self ._api_get ('/countries' )
141+ def get_attributes (self , country_code , language_code , ** kwargs ):
142+ self .validator .validate_request (
143+ 'get_attributes' ,
144+ path_data = {
145+ 'countryCode' : '{}' .format (country_code ),
146+ 'languageCode' : '{}' .format (language_code )
147+ },
148+ query_params = kwargs ,
149+ )
150+ return self ._api_get ('/attributes/{}/{}' .format (country_code , language_code ), kwargs )
151+
152+ def get_countries (self , ** kwargs ):
153+ self .validator .validate_request (
154+ 'get_countries' ,
155+ query_params = kwargs ,
156+ )
157+ return self ._api_get ('/countries' , kwargs )
145158
146159 def get_event (self , event_id ):
160+ self .validator .validate_request (
161+ 'get_event' ,
162+ path_data = {'eventId' : '{}' .format (event_id )},
163+ )
147164 return self ._api_get ('/events/{}' .format (event_id ))
148165
149- def get_events (self ):
150- return self ._api_get ('/events' )
166+ def get_events (self , ** kwargs ):
167+ self .validator .validate_request (
168+ 'get_events' ,
169+ query_params = kwargs ,
170+ )
171+ return self ._api_get ('/events' , kwargs )
151172
152173 def create_project (self , project_data ):
153- # Creates a new project. Uses the "new project" schema.
154- self ._validate_object ("project_new" , project_data )
174+ '''
175+ #TODO: Waiting on a valid request body schema.
176+ self.validator.validate_request(
177+ 'create_project',
178+ request_body=project_data,
179+ )
180+ '''
155181 response_data = self ._api_post ('/projects' , project_data )
156182 if response_data .get ('status' ).get ('message' ) != 'success' :
157183 raise DemandAPIError (
158- " Could not create project. Demand API responded with: {}" .format (
184+ ' Could not create project. Demand API responded with: {}' .format (
159185 response_data
160186 )
161187 )
162188 return response_data
163189
164190 def get_project (self , project_id ):
191+ self .validator .validate_request (
192+ 'get_project' ,
193+ path_data = {'extProjectId' : '{}' .format (project_id )},
194+ )
165195 return self ._api_get ('/projects/{}' .format (project_id ))
166196
167- def get_projects (self ):
168- return self ._api_get ('/projects' )
197+ def get_projects (self , ** kwargs ):
198+ self .validator .validate_request (
199+ 'get_projects' ,
200+ query_params = kwargs ,
201+ )
202+ return self ._api_get ('/projects' , kwargs )
169203
170204 def update_project (self , project_id , update_data ):
171- self ._validate_object ("project_update" , update_data )
205+ '''
206+ #TODO: Waiting on a valid request body schema and path schema.
207+ self.validator.validate_request(
208+ 'update_project',
209+ path_data={'extProjectId': '{}'.format(project_id)},
210+ request_body=update_data,
211+ )
212+ '''
172213 response_data = self ._api_post ('/projects/{}' .format (project_id ), update_data )
173214 if response_data .get ('status' ).get ('message' ) != 'success' :
174215 raise DemandAPIError (
@@ -179,6 +220,10 @@ def update_project(self, project_id, update_data):
179220 return response_data
180221
181222 def get_project_detailed_report (self , project_id ):
223+ self .validator .validate_request (
224+ 'get_project_detailed_report' ,
225+ path_data = {'extProjectId' : '{}' .format (project_id )},
226+ )
182227 return self ._api_get ('/projects/{}/detailedReport' .format (project_id ))
183228
184229 def add_line_item (self , project_id , lineitem_data ):
@@ -189,8 +234,16 @@ def add_line_item(self, project_id, lineitem_data):
189234 completes required. A line item is our unit of work and is what
190235 gets billed to you.
191236 '''
192- # Creates a new line item. Uses the "new lineitem" schema.
193- self ._validate_object ("lineitem_new" , lineitem_data )
237+ '''
238+ #TODO: Waiting on a valid request body and path schema.
239+ self.validator.validate_request(
240+ 'create_line_item',
241+ path_data={
242+ 'extProjectId': '{}'.format(project_id)
243+ },
244+ request_body=lineitem_data
245+ )
246+ '''
194247 response_data = self ._api_post ('/projects/{}/lineItems' .format (project_id ), lineitem_data )
195248 if response_data .get ('status' ).get ('message' ) != 'success' :
196249 raise DemandAPIError (
@@ -201,16 +254,32 @@ def add_line_item(self, project_id, lineitem_data):
201254 return response_data
202255
203256 def get_line_item (self , project_id , line_item_id ):
257+ self .validator .validate_request (
258+ 'get_line_item' ,
259+ path_data = {
260+ 'extProjectId' : '{}' .format (project_id ),
261+ 'extLineItemId' : '{}' .format (line_item_id )
262+ },
263+ )
204264 return self ._api_get ('/projects/{}/lineItems/{}' .format (project_id , line_item_id ))
205265
206- def update_line_item (self , project_id , lineitem_id , lineitem_data ):
266+ def update_line_item (self , project_id , line_item_id , line_item_data ):
207267 '''
208268 Updates the specified line item by setting the values of the parameters passed.
209269 Any parameters not provided will be left unchanged.
210270 '''
211- # Update an existing line item. Uses the "lineitem_update" schema.
212- self ._validate_object ("lineitem_update" , lineitem_data )
213- response_data = self ._api_post ('/projects/{}/lineItems/{}' .format (project_id , lineitem_id ), lineitem_data )
271+ '''
272+ #TODO: Waiting on a valid path and request body schema.
273+ self.validator.validate_request(
274+ 'update_line_item',
275+ path_data={
276+ 'extProjectId': '{}'.format(project_id),
277+ 'extLineItemId': '{}'.format(line_item_id),
278+ },
279+ request_body=line_item_data,
280+ )
281+ '''
282+ response_data = self ._api_post ('/projects/{}/lineItems/{}' .format (project_id , line_item_id ), line_item_data )
214283 if response_data .get ('status' ).get ('message' ) != 'success' :
215284 raise DemandAPIError (
216285 "Could not update line item. Demand API responded with: {}" .format (
@@ -219,17 +288,40 @@ def update_line_item(self, project_id, lineitem_id, lineitem_data):
219288 )
220289 return response_data
221290
222- def get_line_items (self , project_id ):
223- return self ._api_get ('/projects/{}/lineItems' .format (project_id ))
291+ def get_line_items (self , project_id , ** kwargs ):
292+ self .validator .validate_request (
293+ 'get_line_items' ,
294+ path_data = {'extProjectId' : '{}' .format (project_id )},
295+ query_params = kwargs ,
296+ )
297+ return self ._api_get ('/projects/{}/lineItems' .format (project_id ), kwargs )
224298
225299 def get_line_item_detailed_report (self , project_id , line_item_id ):
300+ self .validator .validate_request (
301+ 'get_line_item_detailed_report' ,
302+ path_data = {
303+ 'extProjectId' : '{}' .format (project_id ),
304+ 'extLineItemId' : '{}' .format (line_item_id ),
305+ },
306+ )
226307 return self ._api_get ('/projects/{}/lineItems/{}/detailedReport' .format (project_id , line_item_id ))
227308
228309 def get_feasibility (self , project_id ):
310+ self .validator .validate_request (
311+ 'get_feasibility' ,
312+ path_data = {'extProjectId' : '{}' .format (project_id )},
313+ )
229314 return self ._api_get ('/projects/{}/feasibility' .format (project_id ))
230315
231- def get_survey_topics (self ):
232- return self ._api_get ('/categories/surveyTopics' )
316+ def get_survey_topics (self , ** kwargs ):
317+ self .validator .validate_request (
318+ 'get_survey_topics' ,
319+ query_params = kwargs ,
320+ )
321+ return self ._api_get ('/categories/surveyTopics' , kwargs )
233322
234323 def get_sources (self ):
324+ self .validator .validate_request (
325+ 'get_sources' ,
326+ )
235327 return self ._api_get ('/sources' )
0 commit comments