Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use pyfetch with POST #962

Closed
Mailstorm-ctrl opened this issue Nov 19, 2022 · 4 comments
Closed

Unable to use pyfetch with POST #962

Mailstorm-ctrl opened this issue Nov 19, 2022 · 4 comments

Comments

@Mailstorm-ctrl
Copy link

I can't seem to get pyfetch to work with a POST request where the API is expecting specific data. Almost all iterations of my code result in a NetworkError with no clear reason why it failed.

headers = {
  "Content-Type": "application/x-www-form-urlencoded"
  }
body = {"body":f"grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope=token"}
jwt_token = await pyfetch(url="https://id.sophos.com/api/v2/oauth2/token", method="POST", headers=headers, body=json.dumps(body))

The above will result in a network error. Even if I remove headers & and body I will get a network error. The code I posted works when using the requests module. But when porting over to use pyscript, it fails.

@JeffersGlass
Copy link
Member

Hmmm curious!

Can you copy/paste the network error you're getting?

Are you running /latest/pyscript.js or some other version (local, unstable, alpha?)

@JeffersGlass
Copy link
Member

For what it's worth, in general POST pyfetch does work. Here's a brief example with the reqres testing API (written for 2022.09.1) - it should just echo back the provided body parameters, plus a random ID and a timestamp.

import json

import js
from pyodide.http import pyfetch

url = 'https://reqres.in/api/users'
headers = {"Content-Type": "application/json"}
body = json.dumps({"name": "Jeff", "project": "PyScript"})

response = await pyfetch(url, method='POST', headers=headers, body = body)
j = await response.json()
print(f"Result = {j}")
//Result:
Result= {'name': 'Jeff', 'project': 'PyScript', 'id': '808', 'createdAt': '2022-11-19T01:47:38.113Z'}

I can't see how this is significantly different from your code though, with the exception of the content and content type.

@Mailstorm-ctrl
Copy link
Author

Hmmm curious!

Can you copy/paste the network error you're getting?

Are you running /latest/pyscript.js or some other version (local, unstable, alpha?)

Sure can!

WOOOORK
PythonError: Traceback (most recent call last): File "/lib/python3.10/asyncio/futures.py", line 201, in result raise self._exception File "/lib/python3.10/asyncio/tasks.py", line 234, in __step result = coro.throw(exc) File "/lib/python3.10/site-packages/_pyodide/_base.py", line 506, in eval_code_async await CodeRunner( File "/lib/python3.10/site-packages/_pyodide/_base.py", line 359, in run_async await coroutine File "", line 37, in File "/lib/python3.10/site-packages/pyodide/http.py", line 237, in pyfetch raise OSError(e.js_error.message) from None OSError: NetworkError when attempting to fetch resource.

For reference, this is the HTML with sensitive information removed:

<HTML>
<head>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
    <py-config>
        packages = ["matplotlib"]
    </py-config>
</head>
<body>
    <py-script>
        import asyncio
        import json
        import matplotlib.pyplot as plt
        from pyodide.http import pyfetch
        sophos_base_url = "https://api.central.sophos.com"
        
        print("WOOOORK")
        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }
        body = f"grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope=token"
        #print(body)
        jwt_token = await pyfetch(url="https://id.sophos.com/api/v2/oauth2/token", method="POST", headers=headers, body=json.dumps(body))
        print("AHHHH")
        access_token = await jwt_token.json()
        print("Here")
        headers = {
            "Authorization": f"Bearer {access_token['access_token']}"
        }
        partner_id = await pyfetch(url="https://api.central.sophos.com/whoami/v1",method="GET", headers=headers)
        pid = await partner_id,json()['id']
        print("Here 2")
        #return json.loads(partner_id.text)['id']
        
        headers = {
            "Authorization": f"Bearer {access_token['access_token']}",
            "X-Partner-ID": pid
        }
        tenants = await pyfetch(url="https://api.central.sophos.com/partner/v1/tenants?pageTotal=true",method="GET", headers=headers)
        tenants = await tenants.json()
        
        tenant_resource_urls = {}
        for tenant in tenants['items']:
            #We only care for tenants we manage.
            #if tenant['name'].upper() not in sanitized:
            #    continue
            tenant_resource_urls[tenant['name']] = {
                "API Host": tenant['apiHost'],
                "Tenant ID": tenant['id']
                }   
        
        medium_alert_count = 0
        high_alert_count = 0
        
        #EXAMPLE:
        # {
        #   'Tenant1': {
        #       'High': true,
        #       'Medium': false
        #   }
        # }
        alert_tenants = {}
        encountered_error = False
        #print(tenant_resource_urls)
        
        for tenant, values in tenant_resource_urls.items():
            headers = {
                "Authorization": f"Bearer {jwt_token['access_token']}",
                "X-Tenant-ID": values['Tenant ID']
            }
            alerts = await pyfetch(url=f"{values['API Host']}/common/v1/alerts?product=endpoint&?severity=high,medium",method="GET", headers=headers)
            alerts = await alerts.json()
            
            # There was some kind of error in our request. We'll display this in the dashboard.
            if 'error' in alerts:
                encountered_error = True
                continue # Skip to next item in loop
            
            for alert in alerts['items']:
                if alert['severity'] == 'medium':
                    medium_alert_count += 1
                    alert_tenants[alert['tenant']['name']] = {}
                    alert_tenants[alert['tenant']['name']]['Medium'] = True
                if alert['severity'] == 'high':
                    high_alert_count += 1
                    alert_tenants[alert['tenant']['name']] = {}
                    alert_tenants[alert['tenant']['name']]['High'] = True
        
        print(medium_alert_count)
        print(high_alert_count)
        chart_values = [high_alert_count, medium_alert_count]
        print([tenant for tenant in alert_tenants.keys()])
        plt.pie(x=chart_values)
        circle = plt.Circle(xy=(0,0), radius=.75, facecolor='white')
        plt.gca().add_artist(circle)
        plt.show()
    </py-script>
</body>
</HTML>

@WebReflection
Copy link
Contributor

This was not labeled as 3rd party or mainstream but it looks to me that's all it is ... closing as it's been years since the original issue, but feel free to re-open it if you think there's something we can do in here, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants