POST method to update XML file - python

I'm trying to use the following code to update a particular tag (<a>) text on file.xml
#app.route('/model', methods = ['POST'])
def api_post():
if request.headers['Content-Type'] == 'text/xml':
f = open("/home/file.xml", "w")
f.write(request.data)
f.close()
but the test with curl is not working...
curl -H "Content-type: text/xml" -X POST http://192.168.1.12:8080/model -d "<a>hello</a>"
Could someone help since I can't find any examples of flask and XML for the POST method?

Possibilities:
You're routing /data POSTs to api_post(), but you're sending
your curl test to /model.
HTTP header names are case-insensitive, but Python dictionary keys
are not. You're posting 'Content-type' but checking 'Content-Type'.
Suggestion: Expand upon "not working..." by providing any error messages or log entries which do not make sense to you. If there are no traces of trouble, add diagnostics until there are.

Related

How to specify Accept headers from rest_framework.test.Client?

I'm trying to set up an API endpoint to reply with HTML or JSON depending on the incoming request's Accept headers. I've got it working, testing through curl:
> curl --no-proxy localhost -H "Accept: application/json" -X GET http://localhost:8000/feedback/
{"message":"feedback Hello, world!"}
> curl --no-proxy localhost -H "Accept: text/html" -X GET http://localhost:8000/feedback/
<html><body>
<h1>Root</h1>
<h2>feedback Hello, world!</h2>
</body></html>
I can't figure out how to use the APITestCase().self.client to specify what content should be accepted, though.
My view looks like
class Root(APIView):
renderer_classes = (TemplateHTMLRenderer,JSONRenderer)
template_name="feedback/root.html"
def get(self,request,format=None):
data={"message": "feedback Hello, world!"}
return Response(data)
and my test code looks like
class RootTests(APITestCase):
def test_can_get_json(self):
response = self.client.get('/feedback/',format='json',Accept='application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.accepted_media_type,'application/json')
js=response.json()
self.assertIn('message', js)
self.assertEqual(js['message'],'feedback Hello, world!')
which dies on the test for response.accepted_media_type. What's the right way to do this? All I can find says that the format argument should be sufficient.
As was rightfully stated here, the docs don't seem to say much about how to add headers to the request using the test client. However, the extra parameter can be used for that but the trick is that you have to write it the exact way the http header looks. So you should do this:
self.client.get('/feedback/', HTTP_ACCEPT='application/json')

Posting a file with a REST API: from a curl example to Python code

I'm trying to code the upload of a file to a web service through a REST API in Python. The service's documentation shows a example using curl as client:
curl -X POST -H \
-H "Content-Type: multipart/form-data" \
-F "file=filename.ext" \
-F "property1=value1" \
-F "property2=value2" \
-F "property3=value3" \
https://domain/api/endpoint
The difficulty for me is that this syntax doesn't match multipart form-data examples I found, including the requests documentation. I tried this, which doesn't work (rejected by the API):
import requests
file_data = [
("file", "filename.ext"),
("property1", "value1"),
("property2", "value2"),
("property3", "value3"),
]
response = requests.post("https://domain/api/endpoint",
headers={"Content-Type": "multipart/form-data"}, files=file_data)
With the error: "org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found"
Can anybody help in transposing that curl example to proper Python code?
Thanks!
R.
OK, looks like the web services documentation is wrong, and metadata simply needs to be sent as parameters. Moreover, I found in another request that you shouldn't set the header. So I was starting from a wrong example.

Python - Accept POST (raw body) data

I am completely new to Python. I am using GitLab which offers system hook feature wherein i can specify a URL and it will send event details in the form of JSON POST data. When i create a RequestBin URL and provide that URL in GitLab's system hook, then in case of any event such as project creation, it sends the event details and i can see the same in RequestBin as shown in the snapshot below.
Now, i want to fetch this JSON data in some variable so i can process it as per my need but i'm not sure how to do read that data.
I've seen some posts which explain how to read JSON data but as you can see below in the screenshot, the FORM/POST PARAMETERS is showing as None. It's the raw body that contains all the details (in JSON format):
I have tried reading the data using Java and it works with the code shown below:
String recv;
String recvbuff="";
BufferedReader buffread = new BufferedReader(new InputStreamReader(request.getInputStream()));
while ((recv = buffread.readLine()) != null)
recvbuff += recv;
buffread.close();
System.out.println(recvbuff);
out.println(recvbuff);
Looking for something similar in Python.
I would suggest using CherryPy. It's a neat Python library that allows you to build a simple webserver application, it's fits pretty nicely in your use case: it can easily accept JSON requests (http://docs.cherrypy.org/en/latest/basics.html#dealing-with-json).
If you write a file called myserver.py with the following code:
#!/usr/bin/python3
import cherrypy
class Root(object):
#cherrypy.expose
#cherrypy.tools.json_in()
def index(self):
data = cherrypy.request.json
# You can manipulate here your json data as you wish
print(data['name'])
if __name__ == '__main__':
cherrypy.quickstart(Root(), '/')
You can simply launch the server with the command line:
python3 myserver.py
And test it with the following curl command:
curl -H "Content-Type: application/json" -POST http://127.0.0.1:8080 -d '{"name": "test", "path": "/"}'
You will then see test printed in your server log.
Your Flask application doesn't return any data so you're not going to see anything returned. You need to return something like:
return "test data"
Your screenshot is only showing the request not the response. You sent no form encoded parameters, which is why it's showing "None".
The correct Content-type for JSON is: application/json

How to handle in-body POST request in Cherrypy?

I am new to cherrypy and couldn't find proper doc abt the topic in question.
How can I handle POST body request in Cherrypy ?
NOTE : I have used mod-python. In it req.read() directly gives content of in-body post content, sent like -
curl -X POST -d #test.xml "http://127.0.0.1:80/generate/gen.py"
Here test.xml is file containing xml content.
I want to use cherrypy only ... please don't suggest to use mod-python :P
You can use the cherrypy.request.body.read() method to obtain the XML. For example:
class MyApp(object):
#cherrypy.expose
def my_handler(self):
body = cherrypy.request.body.read()
# process XML from body here...
return "I got %s bytes." % len(body)

Spaces in a URL when using requests and python

I hope I can explain myself. with out making an arse of myself.
I am trying to use python 3.4 to send a url to a sparkcore api.
I have managed to use curl direcly from the windows command line:-
curl https://api.spark.io/v1/devices/xxxxxxxxxxxxxxx/led -d access_token=yyyyyyyyyyyyyyyy -d params=l1,HIGH
All works fine. there is a space between the led and -d, but that is not a problem.
I have read that reting to do this within python using libcurl is a big pain and I saw lots of messaged about using Requests, so I though I would give it a go.
So I wrote a small routine:
import requests
r = requests.get('https://api.spark.io/v1/devices/xxxxxxxxxxxxxxxxxx/led -d access_token=yyyyyyyyyyyyyyyyy -d params=l1,HIGH')
print(r.url)
print(r)
I get as return:
<Response [400]>
When I examine the URL which actually got sent out the spaces in the URL are replaced with %20. This seems to be my actual problem, because the %20 being added by requests are confusing the server which fails
"code": 400,
"error": "invalid_request",
"error_description": "The access token was not found"
I have tried reading up on how to inpractice have the spaces with out having a %20 being added by the encoding, but I really could do with a pointer in the right direction.
Thanks
Liam
URLs cannot have spaces. The curl command you are using is actually making a request to the url https://api.spark.io/v1/devices/xxxxxxxxxxxxxxx/led with some command line arguments (using -d)
The curl man (manual) page says this about the -d command line argument
-d, --data
(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to -F, --form.
-d, --data is the same as --data-ascii. To post data purely binary, you should instead use the --data-binary option. To URL-encode the value of a form field you may use --data-urlencode.
If any of these options is used more than once on the same command line, the data pieces specified will be merged together with a separating &-symbol. Thus, using '-d name=daniel -d skill=lousy' would generate a post chunk that looks like 'name=daniel&skill=lousy'.
If you start the data with the letter #, the rest should be a file name to read the data from, or - if you want curl to read the data from stdin. Multiple files can also be specified. Posting data from a file named 'foobar' would thus be done with --data #foobar. When --data is told to read from a file like that, carriage returns and newlines will be stripped out.
So that says -d is for sending data to the URL with the POST request using the content-type application/x-www-form-urlencoded
The requests documentation has a good example of how to do that using the requests library: http://docs.python-requests.org/en/latest/user/quickstart/#more-complicated-post-requests
So for your curl command, I think this should work
import requests
payload = {'access_token': 'yyyyyyyyyyyyyyyy', 'params': 'l1,HIGH'}
r = requests.post("https://api.spark.io/v1/devices/xxxxxxxxxxxxxxx/led", data=payload)
print(r.text)

Categories