Python, Bottle, MongoDB Create Function 500 Error Code - python

I am creating a REST service using Bottle and MongoDB. The problem is I am getting a 500 error code when trying to insert a document.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Error: 500 Internal Server Error</title>
<style type="text/css">
html {background-color: #eee; font-family: sans;}
body {background-color: #fff; border: 1px solid #ddd;
padding: 15px; margin: 15px;}
pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
</style>
</head>
<body>
<h1>Error: 500 Internal Server Error</h1>
<p>Sorry, the requested URL <tt>'http://localhost:8080/create'</tt>
caused an error:</p>
<pre>Unhandled exception</pre>
</body>
</html>
cURL
curl -H "Content-Type: application/json" -X POST -d '{"id" : "10011-2017-TEST","certificate_number" : 9278833,"business_name" : "ACME TEST INC.","date" : "Feb 20 2017","result" : "No Violation Issued","sector" : "Test Retail Dealer - 101"}' http://localhost:8080/create
The thing is though, I am able to successfully insert a document even though I get the 500 error code. Why am I getting the 500 error code? I have been trying to implement exception handling for both MongoDB and Bottle. Not sure if that is why I am getting the code. If not, how can I properly implement exception handling? I have read up on abort but I have had trouble with that. Also, when I comment out return result , I get a 200 response code, but I want to return the id of the document inserted. Thanks
Source Code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from bson import json_util
import json
import bottle
from bottle import route, run, request, abort, post, error
import pymongo
from pymongo import MongoClient
import datetime as datetime
connection = MongoClient('localhost', 27017)
db = connection['city']
collection = db['inspections']
#route('/create', method='POST')
def insert_document():
try:
data = request.json
result = collection.insert_one(data).inserted_id
except Exception, e:
print ('EXCEPTION: ', e)
return result
if __name__ == '__main__':
run(host='localhost', port=8080)

Change
return result
to
return str(result)
or simply remove the line altogether.

Related

Updating HTML page using Flask

I am making a info screen for a few 3D printers, I have a rest API where I get the data from. The data should be updated continuously and it will be name and time. I however want to just start getting the current name displaying on the HTML site.
I have a working Python program that loops and updating the current name and that output needs to go to a specific field, in this case (HTML file field INPUT NAME 1) I will have multiple printers so needs to be easy to direct the data to the HTML tags... Have been trying flask but I do not know if that is the best for this?
python program:
import sched, time
from time import time, sleep
import flask
from flask import Flask, redirect, url_for, render_template, request, flash
import requests
app=Flask(__name__,template_folder='templates')
#printer-S3-nr1
response_ums3_1 = requests.get("http://192.168.50.203/api/v1/print_job/name")
response_ums5_1 = requests.get("http://192.168.50.201/api/v1/print_job/name")
#app.route("/")
def profile():
while (True):
sleep(10 - time()%10)
#ULTIMAKER S3 NR 1
if response_ums3_1.status_code == 404:
return render_template("server.html", s3name1 = "No Prints Running")
if response_ums3_1.status_code == 200:
return render_template("server.html", s3name1 = response_ums3_1.text.strip('"'))
#ULTIMAKER S3 NR 1
#ULTIMAKER S5 NR 1
if response_ums5_1.status_code == 404:
return render_template("server.html", s5name1 = "No Prints Running")
if response_ums5_1.status_code == 200:
return render_template("server.html", s5name1 = response_ums5_1.text.strip('"'))
#ULTIMAKER S5 NR 1
if __name__ == "__main__":
app.run(debug=True)
```
<!DOCTYPE html>
<html>
<head>
<style>
#customers {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
#customers td,
#customers th {
border: 1px solid #ddd;
padding: 8px;
}
#customers tr:nth-child(even) {
background-color: #f2f2f2;
}
#customers tr:hover {
background-color: #ddd;
}
#customers th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #1b77f7;
color: white;
}
</style>
</head>
<H1 align="center"> Printer Status </H1>
<body>
<table id="customers">
<tr>
<th>Skrivare</th>
<th>Färdig</th>
<th>Namn</th>
<th>Video</th>
</tr>
<tr>
<td>Ultimaker-S5-nr1</td>
<td>INPUT TIME</td>
<td>{{s5name1}}</td>
<td><img src="http://192.168.50.201:8080/?action=stream" alt="Ultimaker-S5-nr1" style="width:202.5px;height:151.85px;" </td>
</tr>
<tr>
<td>Ultimaker S3 nr1</td>
<td>INPUT TIME</td>
<td>{{s3name1}}</td>
<td><img src="http://192.168.50.203:8080/?action=stream" alt="Ultimaker S3 nr1" style="width:202.5px;height:151.85px;" </td>
</tr>
<tr>
</table>
</body>
</html>
```
In Flask, if you want to send data back from server to the front end, then you have to use the return command. Right now, all you're doing is sending output (your print command) to your console. When you return values from your server to the front end, you'll have to use Jinja Template to display the values e.g.
#server code
if response.status_code == 202:
return render_template("index.htm", INPUT_NAME_1 = response.text)
#html page e.g index.htm
....
<td>{{INPUT_NAME_1}}</td>
...
So from the above code (#server code), you're sending a variable called INPUT_NAME_1 back to an html page called index.htm and on that page you get the value of the variable by using the Jinja syntax of double curly brackets i.e. {{}}
Flask is a web framework. It allows you to build web-based applications which use Python. Another framework is Django. If your target is a web application, then you can use any of them.
Note: Right now, your code doesn't include anything to make it web-based. You haven't even imported the Flask libraries to your python code and that brings me to my next point.
Your question shows you're still missing some basics and continuing down this path will lead to more frustration for you. I would advise that you first understand the basics of Flask e.g. read materials that introduce you to Flask. A quick Googling returned the following - https://pymbook.readthedocs.io/en/latest/flask.html,
https://flask.palletsprojects.com/en/2.0.x/
Once you get the basics of Flask, you should then figure out if you want your web application to reside on your local machine or you want to host it on the web. For web hosting, there are cheap (or free) hosts like python anywhere, heroku, Google App Engine. If you decide to go the route of Google App Engine, check out our website where we have a GUI for it

Why am I receiving this JSON Decode Error?

Here's what I'm doing.
I'm sending a get request to a reddit oembed endpoint. I want to parse the returned json and grab the raw html to embed a reddit post onto my django page. The error I receive when I try to do this is
json.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)
Here's an example of that code in action. (It's inside a function)
endpoint = requests.get("https://www.reddit.com/oembed?url=https://www.reddit.com/r/nba/comments/n6l2zu/the_crew_lock_in_their_predictions_and_ernie_has/")
return endpoint.json()['html']
Here is the html it should return. I'm thinking maybe I have to reformat it? Could someone help me out here? Thanks!
'\n <blockquote class="reddit-card" >\n The crew lock in their predictions and Ernie has the Jazz going to the Finals from\n nba\n </blockquote>\n <script async src="https://embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>\n'
EDIT:
Here is the result of printing endpoint.json()
{
"provider_url":"https://www.reddit.com/",
"version":"1.0",
"title":"The crew lock in their predictions and Ernie has the Jazz going to the Finals",
"provider_name":"reddit",
"type":"rich",
"html":"\n <blockquote class=\"reddit-card\" >\n The crew lock in their predictions and Ernie has the Jazz going to the Finals from\n nba\n </blockquote>\n <script async src=\"https://embed.redditmedia.com/widgets/platform.js\" charset=\"UTF-8\"></script>\n",
"author_name":"tanookiben"
}
import requests
import json
def get_response():
endpoint = requests.get("https://www.reddit.com/oembed?url=https://www.reddit.com/r/nba/comments/n6l2zu/the_crew_lock_in_their_predictions_and_ernie_has/")
if endpoint.status_code == 200:
return json.loads(endpoint.text)
return {}
print(get_response())
It seems like reddit responses error message as below when you make requests. So it is better to check response status code first.
<!doctype html>
<html>
<head>
<title>Too Many Requests</title>
<style>
body {
font: small verdana, arial, helvetica, sans-serif;
width: 600px;
margin: 0 auto;
}
h1 {
height: 40px;
background: transparent url(//www.redditstatic.com/reddit.com.header.png) no-repeat scroll top right;
}
</style>
</head>
<body>
<h1>whoa there, pardner!</h1>
<p>we're sorry, but you appear to be a bot and we've seen too many requests
from you lately. we enforce a hard speed limit on requests that appear to come
from bots to prevent abuse.</p>
<p>if you are not a bot but are spoofing one via your browser's user agent
string: please change your user agent string to avoid seeing this message
again.</p>
<p>please wait 6 second(s) and try again.</p>
<p>as a reminder to developers, we recommend that clients make no
more than <a href="http://github.com/reddit/reddit/wiki/API">one
request every two seconds</a> to avoid seeing this message.</p>
</body>
</html>
I wasn't sending a proper header. Kept getting a 429 error back, and because there was no json returned, I was receiving the json decoder error.

Cannot access localhost:8080 from browser

I am running this simple command in my terminal:
python -m http.server 8080
But when I try to access localhost:8080, nothing came out. Why does this happen? Can someone help me?
Thanks in advance.
When I tried another python code provided by the Udacity course:
#!/usr/bin/env python3
#
# A buggy web service in need of a database.
from flask import Flask, request, redirect, url_for
from forumdb import get_posts, add_post
app = Flask(__name__)
# HTML template for the forum page
HTML_WRAP = '''\
<!DOCTYPE html>
<html>
<head>
<title>DB Forum</title>
<style>
h1, form { text-align: center; }
textarea { width: 400px; height: 100px; }
div.post { border: 1px solid #999;
padding: 10px 10px;
margin: 10px 20%%; }
hr.postbound { width: 50%%; }
em.date { color: #999 }
</style>
</head>
<body>
<h1>DB Forum</h1>
<form method=post>
<div><textarea id="content" name="content"></textarea></div>
<div><button id="go" type="submit">Post message</button></div>
</form>
<!-- post content will go here -->
%s
</body>
</html>
'''
# HTML template for an individual comment
POST = '''\
<div class=post><em class=date>%s</em><br>%s</div>
'''
#app.route('/', methods=['GET'])
def main():
'''Main page of the forum.'''
posts = "".join(POST % (date, text) for text, date in get_posts())
html = HTML_WRAP % posts
return html
#app.route('/', methods=['POST'])
def post():
'''New post submission.'''
message = request.form['content']
add_post(message)
return redirect(url_for('main'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
when I tried this for the first time, it worked just fine. But then I closed the terminal. The second time I try to run this python file, I couldn't connect to localhost:8000 anymore.
the same problem keeps coming back.
Sometimes it works fine and I see the page I want. Why is that?
Question:
Do I run the webserver from my virtualMachine or from my macos system?
Firstly, create a python file (server.py) in your project file.
Copy the code below into server.py
import http.server
import socketserver
PORT = 8080
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("",PORT), Handler)
print("Server at PORT : ",PORT)
httpd.serve_forever()
After that, run the following code command=>
python server.py
Maybe nothing comes out because it's an empty server? You have no HTML content.
You can do this
mkdir /tmp/www
echo 'It works' > /tmp/www/index.html
python -m http.server 8080 --directory /tmp/www
And in a new terminal
curl -v http://localhost:8080
You should see something

Get python data in an html/javascript webpage

So I'm trying to make a problem for a ctf, and for a problem, I need to send data from a python script to the javascript. Can anyone tell me how?
My html code is:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1 class="text">text</h1>
<script>
$.get("[website]/cgi-bin/challenge.py",
function(data) {
$(".text").html(data);
});
</script>
</body>
</html>
I replaced the website with [website].
The python code is like this:
#!/usr/bin/python
import json
print "Content-type: text/html\n\n"
json.dumps("It works!")
#!/usr/bin/python
import json
text = json.dumps("It works!")
print "Content-Type: application/json\n"
print text
you can try: https://www.zerorpc.io/ , zerorpc is a communication between server-side processes that lets you transfer data from a server to a client.
in your situation, if you want to transfer data from python to node.js you cand do it like this:
in your python file as a server do:
import zerorpc
class HelloRPC(object):
def hello(self, name):
return "Hello, %s" % name
s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()
and in your node.js code as a client:
var zerorpc = require("zerorpc");
var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
client.invoke("hello", "RPC", function(error, res, more) {
console.log(res);
});
this will print "hello RPC" on the console.

Return binary and parametric data from bottle web service

I am trying to write a web service that performs some data processing. The requests contain a data vector as a binary file, and meta-data and processing parameters as form data. An example using python with requests:
import numpy as np
import requests
url = 'http://localhost:8080/pp'
payload = {'param_a': 4, 'param_b': -2.1}
file = {'binary_data': ('file_name.bin', bytes(np.random.randn(1000))}
r = requests.post(url, data=payload, files=file)
Now on the service side, I have:
import bottle
import numpy as np
#bottle.post('/pp')
def pp():
file_path = '/home/generic_user/howhaveyou.bin'
return_file_path = '/home/generic_user/finethanks.bin'
bin_file = bottle.request.files.get('binary_data')
bin_file.save(file_path, overwrite=True)
param_a = float(bottle.request.forms.get('param_a')
param_b = float(bottle.request.forms.get('param_b')
data_vector = np.fromfile(file_path)
processed_data_vector = (data_vector-param_a)*param_b
processed_data_mean = np.mean(processed_data_vector)
processed_data_samples = len(processed_data_vector)
return_metrics = {'mean': processed_data_mean,
'n_of_samples': processed_data_samples}
with open(return_file_path, 'wb') as return_file:
return_file.write(bytes(processed_data_vector))
return return_metrics, bottle.static_file(return_file_path, '/')
which doesn't quite work. Either of the returns work on their own, but together I get the following response:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Error: 500 Internal Server Error</title>
<style type="text/css">
html {background-color: #eee; font-family: sans;}
body {background-color: #fff; border: 1px solid #ddd;
padding: 15px; margin: 15px;}
pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
</style>
</head>
<body>
<h1>Error: 500 Internal Server Error</h1>
<p>Sorry, the requested URL <tt>'http://localhost:8080/pp'</tt>
caused an error:</p>
<pre>Unsupported response type: <class 'dict'></pre>
</body>
</html>
I have a complete lack of experience with Web Services, so I don't even know if I'm on the right track at all. The point is I wish to return some binary data, along with a few (preferably named) metrics of said data. Is it possible to do this using bottle only? Is there a best practice (with respect to web services, python or both) that I should follow when it comes to this kind of thing?
Note that the client will not be written in python, that is just my test case.
Thanks for any guidance!
The problem with the server-side code is that you cannot return a dictionary (return_metrics) and the contents of a file (return_file_path) with the same response. A solution is to encode the file contents in a string and include it in the returned dict (return_metrics). Then, the client will need to decode the content string to access the data.

Categories

Resources