Microsoft Graph API Nest JSON Request is failed - python

I am developing App leveraging Microsoft Graph using Python 3.6.
I am getting very strange behavior when requesting Graph API which uses request data as nested JSON.
This is a successful request:
url = f "https://graph.microsoft.com/v1.0/users/{user_id}"
headers = {
'Authorization': f 'Bearer {office365_access_token}',
'Content-Type': 'application/json'
}
data = {
"city": "Tokyo"
}
req = urllib.request.Request(url, json.dumps(data).encode("utf-8"), headers = headers, method = 'PATCH')
urllib.request.urlopen(req)
The next snipped fails with an HTTP Error 400 error. The documentation states that the skills property is a String Collection, so I used an Array of String values:
url = f "https://graph.microsoft.com/v1.0/users/{user_principal_name}"
headers = {
'Authorization': f 'Bearer {office365_access_token}',
'Content-Type': 'application/json'
}
data = {
"skills": ["swift", "python"]
}
req = urllib.request.Request(url, json.dumps(data).encode("utf-8"), headers = headers, method = 'PATCH')
urllib.request.urlopen(req)
The only difference is whether the value is a string or not. I can dump the data dictionary to a JSON string, so I don't think the code is wrong but I do not know why this error occurres.

It appears to be a bug related with Microsoft Graph itself, specifically with User update operation. For example the following query:
PATCH https://graph.microsoft.com/v1.0/me
Content-type: application/json
{
"skills": [
"Fortran",
"Cobol"
],
"city": "Helsinki"
}
indeed fails and returns the following error:
{
"error": {
"code": "BadRequest",
"message": "The request is currently not supported on the targeted entity set"
}
}
At the same time updating another User properties, for example User.otherMails property which has the same Collection(Edm.String) type as User.skills:
PATCH https://graph.microsoft.com/v1.0/me
Content-type: application/json
{
"otherMails": [
"office365admin#gmail.com",
"office365admin#yahoo.com"
],
"city": "Helsinki"
}
completes successfully.
Workaround
It appears it fails when skills property of User resource is getting updated along with another properties. But if only a skills property is getting updated
PATCH https://graph.microsoft.com/v1.0/me
Content-type: application/json
{
"skills": [
"Fortran",
"Cobol",
"C"
]
}
no error occurs and the operation successfully completes.

Related

Creating Jira issue with REST API

Having issues with trying to create an issue with Jira through the APIs, below is a sample of my code. We are using enterprise jira, I have to replace certain sections with so I hope it wont effect your ability to provide help.
from requests.auth import HTTPBasicAuth
import requests
user = '<ID>'
password = '<password>'
url = 'https://<enterprise>jira.<domain>.com/projects/<MYKEY>/rest/api/3/issue'
headers = {
'Content-Type': 'application/json',
}
json_data = {
"fields": {
"project": {
"key": "<MYKEY>"
},
"summary": "Creating From Collection",
"description": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "This is an autogenerated issue from a demo."
}
]
}
]
},
"issuetype": {
"name": "Task"
}
}
}
response = requests.post(
url,
headers=headers,
json=json_data,
verify=False,
auth=(user, password),
)
I get error code 405 and the following message when running print(response.text):
<!doctype html>HTTP Status 405 – Method Not Allowedbody {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}HTTP Status 405 – Method Not AllowedType Status ReportMessage HTTP method POST is not supported by this URLDescription The method received in the request-line is known by the origin server but not supported by the target resource.Apache Tomcat/8.5.78
Im sure I'm doing something wrong so any help will be appreciated.
Also I have verified I have the right access by manually going to the project and creating an issue.
Your URL is wrong. For creating a Jira issue you want to use the create issue endpoint.
For server/datacenter:
url = 'https://<enterprise>jira.<domain>.com/rest/api/2/issue'
For cloud:
url = 'https://<enterprise>jira.<domain>.com/rest/api/3/issue'
You need to use a POST request to either of these endpoints.

Adding multiple CC's using Zenpy

I am working on an automation script to push out emails based on tickets we receive from our CRM.
Is there a way for the collaborator_ids to take multiple emails? I've tried using email_ccs and email_ccs_ids with no luck. Below is what I am currently using to include one CC'd email address.
zenpy_client.tickets.update(Ticket(id=i.id, requester=User(email=roster_email, name=name), collaborator_ids=cc_email))
I've also tried: collaborator_ids=(cc_email, cc_email2)
This will work (even if there are internal notes in the ticket):
# Add CC
url = "https://{sub}.zendesk.com/api/v2/tickets/{id}"
payload = json.dumps({
"ticket": {
"email_ccs": [
{
"user_email": "new#email.com",
"action": "put"
}
]
}
})
headers = {
'Authorization': 'Basic {token}',
'Content-Type': 'application/json'
}
response = requests.request("PUT", url, headers=headers, data=payload)
print(response.text)
You could get the ticket ID from ZenPy like facetoe showed here:
ticket_audit = zenpy_client.tickets.create(Ticket(description='test', subject='test'))
print(ticket_audit.ticket.id) # Ticket ID of last created ticket

How do I read a .txt file from my One Drive Documents folder with Python?

I have registered the app, added read-write permissions on it, gotten admin consent, and gotten the token. When I make a GET request I get an error.
This my Python code:
import requests, sys, os, json
# Get token
params = {
'client_id': clientID,
'scope': 'https://graph.microsoft.com/.default',
'client_secret': clientSecret,
'grant_type': 'client_credentials'
}
response = requests.post('https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token', data=params)
jresp = response.json()
access_token = jresp['access_token']
# Get item
header = {'Authorization': 'Bearer ' + access_token}
response = requests.get('https://graph.microsoft.com/v1.0/me/drive/root:/Documents/WildRydes.txt', headers = header)
print response
print response.text
print response.content
sys.exit()
This is what is returned:
<Response [500]>
{
"error": {
"code": "BadRequest",
"message": "Unable to retrieve user's mysite URL.",
"innerError": {
"request-id": ,
"date": "2020-04-29T12:42:06"
}
}
}
I have been following the Microsoft Graph API documentation for the past two days straight. They are very good at theory but rubbish at showing concrete examples. Or maybe they're good at hiding where those are.

logging into the MATCHBOOK API with Python Requests

I am trying (legitimately and with the go ahead from the site)to log into the betting exchange matchbook.com through their api.
The documentation states:
To Login: https://www.matchbook.com/bpapi/rest/security/session
and
Example Request
POST /security/session
{
"username": "j_henry",
"password": "******"
}
Example Response
{
"session-token": "1418_1234567890",
"user-id": 1418,
"account": { // Same as GET /account API response.
...
}
}
I am using Requests and have the following code:
payload = {"username": "********", "password": "************"}
r = requests.post('https://www.matchbook.com/edge/rest/security/session', data=payload)
print (r.status_code)
I get error code 415? I must be getting the wrong type of response??
I have looked at a lot of very similar posts on here, and I am about to ask matchbook's team, but before I do has anybody got any ideas?
You might have to specify Content-Type, try to add a header to tell the server it's JSON formatted:
payload = {"username": "********", "password": "************"}
headers = {"Content-Type": "application/json;"}
r = requests.post('https://www.matchbook.com/edge/rest/security/session', data=payload, headers=headers)
print (r.status_code)
It does not appear from your code that you are JSON-encoding your payload. The endpoint is likely expecting JSON.
Try this:
payload = '{"username": "********", "password": "************"}'

How can I make a Post Request on Python with urllib3?

I've been trying to make a request to an API, I have to pass the following body:
{
"description":"Tenaris",
"ticker":"TS.BA",
"industry":"Metalúrgica",
"currency":"ARS"
}
Altough the code seems to be right and it finished with "Process finished with exit code 0", it's not working well. I have no idea of what I'm missing but this is my code:
http = urllib3.PoolManager()
http.urlopen('POST', 'http://localhost:8080/assets', headers={'Content-Type':'application/json'},
data={
"description":"Tenaris",
"ticker":"TS.BA",
"industry":"Metalúrgica",
"currency":"ARS"
})
By the way, this the first day working with Python so excuse me if I'm not specific enough.
Since you're trying to pass in a JSON request, you'll need to encode the body as JSON and pass it in with the body field.
For your example, you want to do something like:
import json
encoded_body = json.dumps({
"description": "Tenaris",
"ticker": "TS.BA",
"industry": "Metalúrgica",
"currency": "ARS",
})
http = urllib3.PoolManager()
r = http.request('POST', 'http://localhost:8080/assets',
headers={'Content-Type': 'application/json'},
body=encoded_body)
print r.read() # Do something with the response?
Edit: My original answer was wrong. Updated it to encode the JSON. Also, related question: How do I pass raw POST data into urllib3?
I ran into this issue when making a call to Gitlab CI. Since the above did not work for me (gave me some kind of error about not being able to concatenate bytes to a string), and because the arguments I was attempting to pass were nested, I thought I would post what ended up working for me:
API_ENDPOINT = "https://gitlab.com/api/v4/projects/{}/pipeline".format(GITLAB_PROJECT_ID)
API_TOKEN = "SomeToken"
data = {
"ref": ref,
"variables": [
{
"key": "ENVIRONMENT",
"value": some_env
},
{ "key": "S3BUCKET",
"value": some_bucket
},
]
}
req_headers = {
'Content-Type': 'application/json',
'PRIVATE-TOKEN': API_TOKEN,
}
http = urllib3.PoolManager()
encoded_data = json.dumps(data).encode('utf-8')
r = http.request('POST', API_ENDPOINT,
headers=req_headers,
body=encoded_data)
resp_body = r.data.decode('utf-8')
resp_dict = json.loads(r.data.decode('utf-8'))
logger.info('Response Code: {}'.format(r.status))
logger.info('Response Body: {}'.format(resp_body))
if 'message' in resp_body:
logfile_msg = 'Failed Gitlab Response-- {} {message}'.format(r.status, **resp_dict)
I recently became interested in using urllib3, and came across this problem. If you read the urllib3 "User Guide" page, you will see this:
For POST and PUT requests, you need to manually encode query parameters in the URL
Your code should be adjusted to look like this:
import urllib3
from urllib.parse import urlencode
data = {"description":"Tenaris",
"ticker":"TS.BA",
"industry":"Metalúrgica",
"currency":"ARS"}
http = urllib3.PoolManager()
encoded_data = urlencode(data)
http.request('POST',
'http://localhost:8080/assets?'+encoded_data,
headers={'Content-Type':'application/json'})

Categories