\$\begingroup\$
\$\endgroup\$
Is there a way to improve this method that interacts with ADP's workforce-now API?
- 200: capture and parse JSON
- 204: return a None
- 400 and 403: return specific text from JSON
- others: throw an exception
def get_worker_by_ssn(access_token, ssn):
import json
# try:
headers={
"Accept": "application/json;masked=false",
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
data = {
"events": [
{
"serviceCategoryCode": {"codeValue": "hr"},
"eventNameCode": {"codeValue": "worker.read"},
"data": {
"transform": {
"queryParameter": f"$filter=person/governmentIDs[0]/idValue eq '{ssn}' and person/governmentIDs[0]/nameCode eq 'SSN'"
}
},
}
]
}
certificate_path = "./certificate.pem"
private_key_path = "./private_key.key"
response = requests.request(
'POST',
'https://api.adp.com/events/hr/v1/worker.read',
headers=headers,
data=json.dumps(data) if data else None,
cert=(certificate_path, private_key_path),
)
print("response.status_code", response.status_code)
if response.status_code == 200:
return response.json()
elif response.status_code == 204:
return None
# Bad Request [400], Forbidden [403]
elif response.status_code in [400,403]:
data = response.json()
error_message = data["confirmMessage"]["resourceMessages"][0]['processMessages'][0]["userMessage"]["messageTxt"] if data else None
# print('error_message',error_message)
raise ValueError(error_message)
else:
response.raise_for_status()
# except requests.exceptions.RequestException as err:
# print(f"Error: {err}")
# raise(err)
toolic
14.6k5 gold badges29 silver badges204 bronze badges
2 Answers 2
\$\begingroup\$
\$\endgroup\$
13
Not much, but here's my suggested improvement:
import json
def get_worker_by_ssn(access_token, ssn):
# try:
headers = {
"Accept": "application/json;masked=false",
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
data = {
"events": [
{
"serviceCategoryCode": {"codeValue": "hr"},
"eventNameCode": {"codeValue": "worker.read"},
"data": {
"transform": {
"queryParameter": f"$filter=person/governmentIDs[0]/idValue eq '{ssn}' and person/governmentIDs[0]/nameCode eq 'SSN'"
}
},
}
]
}
certificate_path = "./certificate.pem"
private_key_path = "./private_key.key"
response = requests.request(
'POST',
'https://api.adp.com/events/hr/v1/worker.read',
headers=headers,
data=json.dumps(data),
cert=(certificate_path, private_key_path),
)
print("response.status_code", response.status_code)
if response.status_code == 200:
return response.json()
elif response.status_code == 204:
return
# Bad Request [400], Forbidden [403]
elif response.status_code in [400, 403]:
data = response.json()
error_message = data["confirmMessage"]["resourceMessages"][0]['processMessages'][0]["userMessage"][
"messageTxt"]
# print('error_message',error_message)
raise ValueError(error_message)
else:
response.raise_for_status()
# except requests.exceptions.RequestException as err:
# print(f"Error: {err}")
# raise(err)
Primary changes:
- Import
json
outside the function, rather than inside. You probably don't want the runtime and memory addition due tojson
being imported every time you call the function. - As
json.dumps(data)
anddata["confirmMessage"]["resourceMessages"][0]['processMessages'][0]["userMessage"]["messageTxt"]
will beNone
if they areFalse
anyway, there's no need forif data else None
. - No need for
return None
. Just writereturn
instead, as python will automatically returnNone
if you return from a function but don't provide a return value.
-
\$\begingroup\$ Arrrgh, noo! In a function that e.g. promises the caller
... -> dict | None:
, we should explicitlyreturn None
, so the Gentle Reader can quickly visually verify that we're keeping our promise. OTOH withdef foo() -> None:
where we're evaluating for side effects, we should leave off the final return so there's an implicitreturn None
, and if we do a conditional early return it should be justreturn
. This lets the Gentle Reader focus on control flow. // Certainlyimport
s belong up top. But 2nd time we import isn't all that expensive, as it enjoys a cache hit. \$\endgroup\$J_H– J_H2024年08月11日 18:17:26 +00:00Commented Aug 11, 2024 at 18:17 -
\$\begingroup\$ @J_H I must respectfully disagree with you. Type checking, Gentle Reader, linters, ...etc. are not important at all. They just "help" you debug and find errors, but it seems like these days they create issues for people to solve; that is, I observed that many people went into a lot of effort just to satisfy these checker/linters. That, I concluded, was completely off the point. It defies the original meaning and motive of the people who wrote these software. Plus, OP never asked about anything related to Gentle Reader. So I answered the question correctly. \$\endgroup\$Luke L– Luke L2024年08月11日 18:27:43 +00:00Commented Aug 11, 2024 at 18:27
-
\$\begingroup\$ The maintenance engineer we recruit to the team in a few months is the Gentle Reader. Software engineering is always about maintainability in addition to correctness, so that's a focus of the Code Review site. The biggest control flow "whoops!" I typically see from a newly hired maintenance engineer is confusion between returning None vs. raising an exception. We strive to teach good habits here, so currently correct code will continue to be correct even after a new hire has made edits to it. \$\endgroup\$J_H– J_H2024年08月11日 18:31:56 +00:00Commented Aug 11, 2024 at 18:31
-
\$\begingroup\$ @J_H I don't get why you are rambling on about Gentle Reader. Just like I said, OP never mentioned Gentle Reader. I've shouldn't have been thinking and writing about something OP never asked for. Also, saying what your company does doesn't mean every company uses this. It's probably just company preference. \$\endgroup\$Luke L– Luke L2024年08月11日 18:37:32 +00:00Commented Aug 11, 2024 at 18:37
-
\$\begingroup\$ @J_H Maintainability of code is absolutely important, but most experienced Python programmers can immediately recognize that
return
andreturn None
are the same, and I believe that many would agree with me that the former is actually better. Explicit is good, but too over and you get messy code. Again, all experienced python programmers know that if a return value isn't explicitly given, then it'sNone
. \$\endgroup\$Luke L– Luke L2024年08月11日 18:40:28 +00:00Commented Aug 11, 2024 at 18:40
\$\begingroup\$
\$\endgroup\$
2
Here are some suggestions:
- Import
json
once, not on every call. - If the input is user-provided, begin by validating it.
- Do the extensive error indexing in steps.
data = response.json()
if not data:
raise ValueError(None)
resource_messages = data["confirmMessage"]["resourceMessages"]
process_messages = resource_messages[0]['processMessages']
error_message = process_messages[0]["userMessage"]["messageTxt"]
raise ValueError(error_message)
Hope this helps!
answered Aug 7, 2024 at 19:42
-
\$\begingroup\$ Why do the error indexing in steps? Any improvements to the status-code-testing logic? \$\endgroup\$craig– craig2024年08月08日 19:50:34 +00:00Commented Aug 8, 2024 at 19:50
-
\$\begingroup\$ I think it is more readable in steps. Also, you could do validation on the response as you go. \$\endgroup\$Justin Chang– Justin Chang2024年08月08日 23:02:28 +00:00Commented Aug 8, 2024 at 23:02
lang-py