Dictionary type params in query string - python-requests

I'm trying to feed the following URL structure into requests:
https://inventory.data.gov/api/action/datastore_search?resource_id=8ea44bc4-22ba-4386-b84c-1494ab28964b&filters={"City":"Las Vegas","State":"NV"}
I wanted to break up the URL into params, but am having a terrible time getting the filters portion to work properly. I ended up using the below code:
url = 'https://inventory.data.gov/api/action/datastore_search?' \
'resource_id=8ea44bc4-22ba-4386-b84c-1494ab28964b&' \
'filters={"City":"' + city + '","State":"' + state + '"}'
resp = requests.get(url=url)
print resp.url
Does anybody know how I can modify this to work with requests like requests.get(url=url, params=params)?

That looks like JSON data. You can convert a Python object to a JSON string with the json module:
import json
import requests
city = 'Las Vegas'
state = 'NV'
filters = {
'City': city,
'State': state
}
params = {
'resource_id': '8ea44bc4-22ba-4386-b84c-1494ab28964b',
'filters': json.dumps(filters)
}
response = requests.get('http://www.example.com/', params=params)
This sends a request to:
http://www.example.com/?filters=%7B%22City%22%3A+%22Las+Vegas%22%2C+%22State%22%3A+%22NV%22%7D&resource_id=8ea44bc4-22ba-4386-b84c-1494ab28964b
where
%7B%22City%22%3A+%22Las+Vegas%22%2C+%22State%22%3A+%22NV%22%7D
is the URL-encoded version of
{"City": "Las Vegas", "State": "NV"}

Related

error creating event with Meetup's api (Python)

I am trying to use Meetup's api to automatically post events on the network, and I am following their guide but I still getting b'Must provide query string.' as a return.
Does anyone know what I may be doing wrong?
import requests
authent_url = "https://api.meetup.com/gql"
params = {
"Authorization" : "Bearer [API KEY HERE]",
}
creating_event = {"mutation": '{createEvent(input: {"groupUrlname": "MY NAME", "title": "Arraial do Cabo", "description": "Trip para arraial", "startDateTime": "2022-09-10 15:00:00.000"}) {event {id} errors {message code field}}}'}
query_by_title = requests.post(authent_url, headers=params, json=creating_event)
query_by_title.content
I don't know what else to do, any help?
EDIT:
Remade the query here and got it
https://splunktool.com/post-graphql-mutation-with-python-requests

Python requests for Google Book API. How to create url?

I'm using this API to search through books. I need to create a request with given parameters. When I use requests library and params argument it creates bad URL which gives me wrong response. Let's look at the examples:
import requests
params = {'q': "", 'inauthor': 'keyes', 'intitle': 'algernon'}
r = requests.get('https://www.googleapis.com/books/v1/volumes?', params=params)
print('URL', r.url)
The URL is https://www.googleapis.com/books/v1/volumes?q=&inauthor=keyes&intitle=algernon
Which works but gives a different response than when the link is as Working Wolumes tells.
Should be: https://www.googleapis.com/books/v1/volumes?q=inauthor:keyes+intitle:algernon
Documentation of requests tells only about params and separates them with &.
I'm looking for a library or any solution. Hopefully, I don't have to create them using e.g. f-strings
You need to create a parameter to send the url, the way you are doing it now is not what you wanted.
In this code you are saying that you need to send 3 query parameters, but that is not what you wanted. You actually want to send 1 parameter with a value.
import requests
params = {'q': "", 'inauthor': 'keyes', 'intitle': 'algernon'}
r = requests.get('https://www.googleapis.com/books/v1/volumes?', params=params)
print('URL', r.url)
try below code instead which is doing what you require:
import requests
params = {'inauthor': 'keyes', 'intitle': 'algernon'}
new_params = 'q='
new_params += '+'.join('{}:{}'.format(key, value) for key, value in params.items())
print(new_params)
r = requests.get('https://www.googleapis.com/books/v1/volumes?', params=new_params)
print('URL', r.url)

FastAPI file upload

I am trying to upload JSON data + file (binary) to FastAPI 'POST' endpoint using requests.
This is the server code:
#app.post("/files/")
async def create_file(
file: bytes = File(...), fileb: UploadFile = File(...), timestamp: str = Form(...)
):
return {
"file_size": len(file),
"timestamp": timestamp,
"fileb_content_type": fileb.content_type,
}
This is the client code:
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(max_retries=0)
session.mount('http://', adapter)
jpg_image = open(IMG_PATH, 'rb').read()
timestamp_str = datetime.datetime.now().isoformat()
files = {
'timestamp': (None, timestamp_str),
'file': ('image.jpg', jpg_image),
}
request = requests.Request('POST',
FILE_UPLOAD_ENDPOINT,
files=files)
prepared_request = request.prepare()
response = session.send(prepared_request)
The server fails with
"POST /files/ HTTP/1.1" 422 Unprocessable Entity
FastAPI endpoints usually respond 422 when the request body is missing a required field, or there are non-expected fields, etc.
It seems that you are missing the fileb from your request body.
If this field is optional, you must declare it as follows in the endpoint definition:
fileb: Optional[UploadFile] = File(None)
You will also need to make some checks inside your endpoint code...
If it is a required field then you need to add it to your request body.

Sending headers to post request

I have this python code that does not work as expected.
import requests
import json
API_ENDPOINT = "https://lkokpdvhc4.execute-api.us-east-1.amazonaws.com/mycall"
data = {'mnumber':'9819838466'}
r = requests.post(url = API_ENDPOINT, data = json.dumps(data))
print (r.text)
This will return an error:
{"stackTrace": [["/var/task/index.py", 5, "handler", "return
mydic[code]"]], "errorType": "KeyError", "errorMessage": "''"}
When I test the API using Amazon console's gateway, I get the expected output (i.e. string like "mumbai"). It means this is client side issue. I have confirmed this by using "postman" as well that returns the same error as mentioned above. How do I send correct headers to post request?
You can create a dictionary with the headers such as
headers = {
"Authorization": "Bearer 12345",
"Content-Type": "application/json",
"key" : "value"
}
Then at the point of making the request pass it as a keyword argument to the request method i.e .post() or .get() or .put
This will be
response = requests.post(API_ENDPOINT, data=json.dumps(data), headers=headers)

Using HTTPBuilder to execute a HTTP DELETE request

I'm trying to use the Groovy HTTPBuilder library to delete some data from Firebase via a HTTP DELETE request. If I use curl, the following works
curl -X DELETE https://my.firebase.io/users/bob.json?auth=my-secret
Using the RESTClient class from HTTPBuilder works if I use it like this:
def client = new RESTClient('https://my.firebase.io/users/bob.json?auth=my-secret')
def response = client.delete(requestContentType: ContentType.ANY)
However, when I tried breaking down the URL into it's constituent parts, it doesn't work
def client = new RESTClient('https://my.firebase.io')
def response = client.delete(
requestContentType: ContentType.ANY,
path: '/users/bob.json',
query: [auth: 'my-secret']
)
I also tried using the HTTPBuilder class instead of RESTClient
def http = new HTTPBuilder('https://my.firebase.io')
// perform a POST request, expecting TEXT response
http.request(Method.DELETE, ContentType.ANY) {
uri.path = '/users/bob.json'
uri.query = [auth: 'my-secret']
// response handler for a success response code
response.success = { resp, reader ->
println "response status: ${resp.statusLine}"
}
}
But this also didn't work. Surely there's a more elegant approach than stuffing everything into a single string?
There's an example of using HttpURLClient in the tests to do a delete, which in its simplest form looks like:
def http = new HttpURLClient(url:'https://some/path/')
resp = http.request(method:DELETE, contentType:JSON, path: "destroy/somewhere.json")
def json = resp.data
assert json.id != null
assert resp.statusLine.statusCode == 200
Your example is very close to the test for the delete in a HTTPBuilder.
A few differences I see are:
Your path is absolute and not relative
Your http url path doesn't end with trailing slash
You're using content type ANY where test uses JSON. Does the target need the content type to be correct? (Probably not as you're not setting it in curl example unless it's doing some voodoo on your behalf)
Alternatively you could use apache's HttpDelete but requires more boiler plate. For a HTTP connection this is some code I've got that works. You'll have to fix it for HTTPS though.
def createClient() {
HttpParams params = new BasicHttpParams()
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1)
HttpProtocolParams.setContentCharset(params, "UTF-8")
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true)
SchemeRegistry registry = new SchemeRegistry()
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80))
ClientConnectionManager ccm = new PoolingClientConnectionManager(registry)
HttpConnectionParams.setConnectionTimeout(params, 8000)
HttpConnectionParams.setSoTimeout(params, 5400000)
HttpClient client = new DefaultHttpClient(ccm, params)
return client
}
HttpClient client = createClient()
def url = new URL("http", host, Integer.parseInt(port), "/dyn/admin/nucleus$component/")
HttpDelete delete = new HttpDelete(url.toURI())
// if you have any basic auth, you can plug it in here
def auth="USER:PASS"
delete.setHeader("Authorization", "Basic ${auth.getBytes().encodeBase64().toString()}")
// convert a data map to NVPs
def data = [:]
List<NameValuePair> nvps = new ArrayList<NameValuePair>(data.size())
data.each { name, value ->
nvps.add(new BasicNameValuePair(name, value))
}
delete.setEntity(new UrlEncodedFormEntity(nvps))
HttpResponse response = client.execute(delete)
def status = response.statusLine.statusCode
def content = response.entity.content
I adopted the code above from a POST version, but the principle is the same.

Resources