How to accept a JSON POST? - python

First time here, it says to be specific... So here goes.
I'm doing a small project to connect Salesforce to my Raspberry Pi. The goal is to make a light (Think a beacon, siren-like light) flash when a high priority case comes in from a client in Salesforce. At the moment, clients usually send an email to a certain address, and this creates a case. It goes to the 'Unassigned Queue' and emails the team that this case is there waiting to be assigned.
Salesforce uses REST, so I need to be able to get the Pi to accept JSON so it can easily understand what Salesforce wants it to do.
Currently, I guess I have won half of the battle. I have a web server (Lighttpd) running on the Pi, which hosts an index page and a Python script. I am also using a Python wrapper, which allows me to easily run a command from a Telldus program I have installed. This program controls a USB RF Transmitter that I have connected, it is paired to a RF Socket, which is connected to the mains power supply with a light connected to it.
So the Python script is called power.py, and can be controlled with URL variables, so if I go to power.py?device=1&power=on&time=10&password=hunter2 that turns on device 1 for 10 seconds. I also created a POST form on the index page, which just POSTS to the python script, and runs it in the same way as using the URL variables. That all works great.
So all I need to do, is connect it to Salesforce. I would like to use REST and JSON, so that if I ever move away from Salesforce to another CRM program, it will easily be able to adapt and receive instructions from new places.
I have posted the Python script I am using here:
https://github.com/7ewis/RemotePiControl/blob/master/power.py
The Pi isn't currently allowed out of the local network, so I will need to somehow develop a way to send JSON commands, and the recieve and convert them to work using the correct variables etc. I'm not a programmer, I've just exposure to languages from hacking things and exploring. Hence why I need some guidance with this.
I have never used REST or JSON before, so what would I need to do to achieve this?

Seems like adding Flask http://flask.pocoo.org to your Raspberry Pi Webserver would be a good move. It allows server-side python to be run in response to JQuery ajax (and regular) requests. Check out a couple of examples here:
http://flask.pocoo.org/docs/patterns/jquery/
and this stack overflow question: how can I use data posted from ajax in flask?
Flask is pretty straightforward to get up and running, and is happy working with a number of servers, including Lighttpd. Writing RESTful flask is also a perfectly reasonable proposition, see: http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask
Additionally, lots of people have used flask on the raspberry pi already-- so that could help get you up and running smoothly: http://mattrichardson.com/Raspberry-Pi-Flask/
Good luck!

Firstly don't use a Python script that prints out result directly to CGI. You will be forever debugging it.
Use a light weight framework like Flask. You can do something as simple as
from flask import Flask
application = Flask(__name__)
#application.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# use Flask's build in json decoder
the_data = request.get_json()
# then do something with the data
return "This was a POST request, how interesting..."
else:
# request was GET rather than POST, so do something with else
return "Hello World!"
See how to configure Flask to run with Lighttpd here http://flask.pocoo.org/docs/deploying/fastcgi/
If you want to test this you can either write another Python script to send JSON data to your server (I recommend looking at the Python Requests library for this http://www.python-requests.org/en/latest/), or you can do this manually using a HTTP request builder, such as HTTPRequester for Firefox (https://addons.mozilla.org/en-US/firefox/addon/httprequester/)

Related

how to send data from separate computer to flask app

My use case is I have a flaskapp running
The idea is it'll just display a static page (currently using PySimpleGUI) and upon receiving the information sent from the other computer (such as the name for e.g.) then it'll show the name as a QR code. (so perhaps a constant refresh on the GUI and changing upon receiving the data)
The code setup is this way currently
#app.route('/qrcode', methods=['GET'])
def displayQrCode():
args = request.args
name = args.get('name') #
try:
img = qrcode.make(name)
img.save('checkin-qrcode.png')
# Display QR Code
qrWindowThread = threading.Thread(target=qrCodeWindowShow)
qrWindowThread.start()
print(name)
return 'Success'
except RuntimeError:
return 'Error in GET'
However, being new to Flask i am not sure how to send a string from a separate computer running jupyter notebook to this Flask app. Online tutorials show like having a form field page but i wish to not have an user input.
So for instance if the jupyter notebook code sends a post request to the ipaddress:5000 it should ideally show (correct me here: ipaddress:5000/qrcode?name=JohnDoe)
so the flask app would retrieve this JohnDoe and display it as a QR code. I can hardcode or manually access this page but how would i have it 'listen' to this /qrcode and then Get the value when it's sent. Or am i misunderstanding it all and I need to do it via another way?
EDIT:
Alright third time lucky, I think I understand what you want now. So your use case is a first computer that is displaying a GUI and running a flask server with an route that can take in a string.
There's a second computer that can send a http request to that route with a name and when that happens you want the GUI on the first computer to refresh to display a QR code of the name.
I'd solve this by having the qrcode route write that name to persistent storage. Could be anything sqlite db, an environment variable, a string in a file.
The first computer running the PySimpleGUI interface poles this persistent storage for changes, and if it sees a change then it renders a new QR code for that name and displays it.
There are multiple ways available to do that:
REST API integration
Realtime data transmission using tornado or ??
Through a base origin for data transmission
Hope you get help with this.

A http proxy same as Fiddler AutoResponder

Hey I'm trying to create something like fiddler autoresponder.
I want replace specific url content to other example:
I researched everything but can't found I tried create proxy server, nodejs script, python script. Nothing.
https://randomdomain.com content replace with https://cliqqi.ml
ps I'm doing this because I want intercept electron app getting main game file from site and then just intercept they game file site to my site.
If you're looking for a way to do this programmatically in Node.js, I've written a library you can use to do exactly that, called Mockttp.
You can use Mockttp to create a HTTPS-intercepting & rewriting proxy, which will allow you to send mock responses directly, redirect traffic from one address to another, rewrite anything including the headers & body of existing traffic, or just log everything that's sent & received. There's a full guide here: https://httptoolkit.tech/blog/javascript-mitm-proxy-mockttp/

Slack bot running python functions

I am creating a Slack Bot, I have successfully installed it, although I am not 100% sure what does ngrok do to run it when I have node server running locally. I have followed this guide.
I have a python script that:
Connects to a database
Downloads the entire table and creates a pandas dataframe
In the script, I have declared many variables which takes specific information from the dataframe.
For example:
monday_sales = sum((df['sale_event_time']>=week) & (df['sale_event_time']<=today_real) & ((df['sale_event_time'].apply(lambda x:x.isoweekday()))==1))
Which simply returns how many sales I had on Monday from the dataframe.
My goal is to connect slack bot to my python script, basically being able to run /monday_sales in slack which would print the number that monday_sales variable holds.
I haven't used much of node or js, so linking everything together I find a bit difficult.
First I run ngrok like so:
./ngrok http 4390
Then I run node server locally(?)
var http = require('http');
const PORT=4390;
function handleRequest(request, response){
response.end('My bot is ALIIIIIIVEEEEE');
}
var server = http.createServer(handleRequest);
server.listen(PORT, function(){
console.log("Server listening on: http://localhost:%s", PORT);
});
And when I run /ngrok in slack it prints out 'My bot is ALIIIIIIVEEEEE, although only visible to me.
So the question could be split in to few:
Why do I need ngrok and node.js server running locally?
How can I trigger python functions / variables from slack bot.
Is there a better way of having slack bot only ran by python without node, ngrok?
Thank you very much for your suggestions.
I think your best bet is to ditch this tutorial and Node, as it seems you're only using it as a ngrok wrapper. Instead, since the rest of your bot is in Python, just use pyngrok (full disclosure, I am the developer), which is a Python wrapper for ngrok. It gives you programmatic access to the tunnels and everything else.
If this solves your use case, you can check out the docs here.

Send data from Django to another server

I have an already existing Django app. I would like to add a system that sends data from my Django application to another Python application hosted on another server, so that the Python application receives data from the Django App in json format, possibly.
So for example, i would need to create a view that every tot seconds sends the data from a DB table to this application, or when a form is hit, the data is sent to this external application.
How can i do this? Is there an example for this particular matter? I don't know what tools i'd need to use to create this system, i only know that i would need to use Celery to perform asynchronous tasks, but nothing else; should i use Webhooks maybe? Or Django channels?
Edit: adding some more context:
I have my Django client. Then i have one or two Python applications running on another server. On my Django client i have some forms. Once the form is submitted, the data is saved on the db, but i also want this data to be sent instantly to my Python applications. The Python applications should receive the data from Django in Json format and perform some tasks according to the values submitted by users. Then the application should send a response to Django.
Come on! I'll call your Django app here "DjangoApp" and your Python apps, in Flask or another framework by "OtherApp".
First as you predicted you will need a framework that is capable of performing tasks, the new **Django 3.0 allows this, but I haven't used it yet ... I will pass on to you something that you are using and fully functional with Django 2.8 and Python 3.8**.
On your DjangoApp server you will need to structure the communication well with your Celery, let's leave the tasks to him. You can read Celery Docs and this post, its very ok to make this architecture.
Regardless of how your form or Django App looks, when you want it to activate a task in celery, it is basically the function to transmit data but in the background.
from .tasks import send_data
...
form.save()
# Create a function within the form to get the data the way you want it
# or do it the way you want.
values = form.new_function_serializedata()
send_data.delay(values) # [CALL CELERY TASKS][1]
...
Read too CALL CELERY TASKS
In all your other applications you will need to have a POST route to receive and serialize this data, do this with lightweight frameworks like Pyramid
This way, every time a form is submitted, you will have this data sent to the server within the send_data function.
In my experience, but not knowing much about your problem I would use a similar architecture but using Celery Beat.
CELERY_BEAT_SCHEDULE = {
'send_data': {
'task': 'your_app.tasks.send_data',
'schedule': crontab(), # CONFIGURE YOUR CRON
},
}
Not only is the above code added, but it is something like that.
Within your models I would create one field for sent. And every 2 seconds, 10 seconds .. as long as I wish I would filter all objects with sent = false, and pass all objects for the send_data task.
I don't know if you got confused, that's a lot to explain. But I hope I can help and answer your questions.
import requests
from django import http
def view(request):
url = 'python.app.com' # replace with other python app url or ip
request_data = {'key': 'value'} # replace with data to be sent to other app
response = requests.post(url, json=request_data)
response_data = response.json() # data returned by other app
return http.JsonResponse(response_data)
This is an example of a function based view that uses the requests library to hit an external service. The request lib takes care of encoding/decoding your data to/from json.
Yeah, webhook would be one of the options, but there are other options available too.
-> You can use Rest Apis to send data from one app to another. but In their case, you need to think about synchronization. That depends on your requirement, If you don't want data in synchronize manner then you may use RabbiMq or other async tools. Just push your rest API request in Rabbitmq and Rabbitmq will handle.

Is there a better way to access my public api?

I am new to Flask.
I have a public api, call it api.example.com.
#app.route('/api')
def api():
name = request.args.get('name')
...
return jsonify({'address':'100 Main'})
I am building an app on top of my public api (call it www.coolapp.com), so in another app I have:
#app.route('/make_request')
def index():
params = {'name':'Fred'}
r = requests.get('http://api.example.com', params=params)
return render_template('really_cool.jinja2',address=r.text)
Both api.example.com and www.coolapp.com are hosted on the same server. It seems inefficient the way I have it (hitting the http server when I could access the api directly). Is there a more efficient way for coolapp to access the api and still be able to pass in the params that api needs?
Ultimately, with an API powered system, it's best to hit the API because:
It's user testing the API (even though you're the user, it's what others still access);
You can then scale easily - put a pool of API boxes behind a load balancer if you get big.
However, if you're developing on the same box you could make a virtual server that listens on localhost on a random port (1982) and then forwards all traffic to your api code.
To make this easier I'd abstract the API_URL into a setting in your settings.py (or whatever you are loading in to Flask) and use:
r = requests.get(app.config['API_URL'], params=params)
This will allow you to make a single change if you find using this localhost method isn't for you or you have to move off one box.
Edit
Looking at your comments you are hoping to hit the Python function directly. I don't recommend doing this (for the reasons above - using the API itself is better). I can also see an issue if you did want to do this.
First of all we have to make sure the api package is in your PYTHONPATH. Easy to do, especially if you're using virtualenvs.
We from api import views and replace our code to have r = views.api() so that it calls our api() function.
Our api() function will fail for a couple of reasons:
It uses the flask.request to extract the GET arg 'name'. Because we haven't made a request with the flask WSGI we will not have a request to use.
Even if we did manage to pass the request from the front end through to the API the second problem we have is using the jsonify({'address':'100 Main'}). This returns a Response object with an application type set for JSON (not just the JSON itself).
You would have to completely rewrite your function to take into account the Response object and handle it correctly. A real pain if you do decide to go back to an API system again...
Depending on how you structure your code, your database access, and your functions, you can simply turn the other app into package, import the relevant modules and call the functions directly.
You can find more information on modules and packages here.
Please note that, as Ewan mentioned, there's some advantages to using the API. I would advise you to use requests until you actually need faster requests (this is probably premature optimization).
Another idea that might be worth considering, depending on your particular code, is creating a library that is used by both applications.

Categories

Resources