What I’m trying to do:
I have a form in Jotforms that I want to use on a website. I want the submitted data to come to anvils database. Not very familiar with API and creating endpoints and so on.
What I’ve tried and what’s not working:
I want to send the information name, email, phone_number to my database called leads.
I checked the logfiles on the server and got this error:
TypeError: receive_leads() missing 3 required positional arguments: 'name', 'email', and 'phone_number'
at /home/anvil/downlink/anvil/_server.py, line 1570
called from /home/anvil/downlink/anvil/_threaded_server.py, line 169
I used webhook to try to send it. What am I missing?
hmm… I have no client side code… Maybe that is what I am missing? In general, how would you set this up to get form info from a 3rd party like Jotforms/typeforms, etc… What would the client-side code look like?
Before Anvil, I tried to use JotForms to collect highly detailed data. (It wasn’t a good fit for my use, but Anvil was. I haven’t touched JotForm since.) Significantly, for this post, the data I downloaded was always in JSON format.
Is it possible that JotForms is POSTing your data as a single value in JSON format? Perhaps wrapped in some metadata?
My understanding is that arguments to endpoints must come from placeholders in the URL. You don’t have any placeholders in your URL, so you shouldn’t have any arguments to your endpoint. Instead, if your data is being passed in JSON, use anvil.server.request.body_json inside your endpoint to get to that.
Which if I understood correctly, nothing is coming from Jotforms is that correct? The question then might be from jotforms side am I understand this correctly?
In general, how would you do set up to receive data to your datatable?
Perhaps nothing is coming in JSON format in a way that Anvil interprets as and converts to JSON.
Try to print other properties of the request and see if you find the JSON value as a plain text, so you can convert it.
In some of my HTTP endpoints I have this, which works when the caller doesn’t setup the request the way Anvil expects it (but doesn’t mean it will work for you):
bb = anvil.server.request.body.get_bytes()
data = json.loads(bb)
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
at /usr/local/lib/python3.10/json/decoder.py, line 355
called from /usr/local/lib/python3.10/json/decoder.py, line 337
called from /usr/local/lib/python3.10/json/__init__.py, line 346
called from lead_receiving, line 20
called from /home/anvil/downlink/anvil/_server.py, line 1570
called from /home/anvil/downlink/anvil/_threaded_server.py, line 169**strong text**
Neither did I! Ideally Anvil ought to be able to ingest that mess (the technical term is “MIME multipart”, and it’s normally only used for file upload) and do something sensible with it.
In the meantime, a little Googling suggests the multipart package. I don’t have a Jotforms account to test with, but something like this might work:
# Make sure you've installed the "multipart" module
from multipart import MultipartParser, parse_options_header
from anvil.server import request
@anvil.server.http_endpoint("/moving-leads", methods=["POST"])
def receive_leads():
data = request.body.get_bytes()
# for debugging
print(request.headers)
separator = parse_options_header(request.headers["content-type"])
parser = MultipartParser(BytesIO(data), separator)
# Now you can loop through all the parts
for part in parser.parts():
print(f"{part.name}: {part.value}")
# Or you can get a particular part
print(part.get("rawRequest")) # Your sample suggests "rawRequest" gets the whole JSON string - you should be able to parse this!
Starting server runtime... Server runtime connected.
NameError: name 'BytesIO' is not defined
at lead_receiving, line 35
called from /home/anvil/downlink/anvil/_server.py, line 1570
called from /home/anvil/downlink/anvil/_threaded_server.py, line 169
{'newrelic': 'eyJ2IjpbMCwxXSwiZCI6eyJ0eSI6IkFwcCIsImFjIjoiNjkxNjIwIiwiYXAiOiIxMzE0NDY2Njk5IiwiaWQiOiJiZDg4Y2RhMTJlMTc0NTMwIiwidHIiOiI4ZGRiNjQyNzkzZGQzMDg4IiwidHgiOiI4ZGRiNjQyNzkzZGQzMDg4IiwicHIiOjEuNTA0MTAsInNhIjp0cnVlLCJ0aSI6MTczNDM5NTI5OTk4Mn19', 'host': 'slymove.anvil.app', 'content-type': 'multipart/form-data; boundary=------------------------xoQPhMsjNpMKKVEBOaSPmJ', 'cookie': None, 'content-length': '3352', 'accept': '*/*', 'tracestate': '691620@nr=0-0-691620-1314466699-bd88cda12e174530-8ddb642793dd3088-1-1.504100-1734395299982', 'x-forwarded-for': '35.226.242.92', 'traceparent': '00-00000000000000008ddb642793dd3088-bd88cda12e174530-01'}
TypeError: can't concat tuple to bytes
at /home/anvil/.env/lib/python3.10/site-packages/multipart.py, line 323
called from /home/anvil/.env/lib/python3.10/site-packages/multipart.py, line 751
called from /home/anvil/.env/lib/python3.10/site-packages/multipart.py, line 722
called from /home/anvil/.env/lib/python3.10/site-packages/multipart.py, line 729
called from lead_receiving, line 38
called from /home/anvil/downlink/anvil/_server.py, line 1570
called from /home/anvil/downlink/anvil/_threaded_server.py, line 169
@jshaffstall Is it generally this complicated to send and receive via API or is it just JotForm’s? haha like I am not married to JotForm’s is the thought that comes to mind. I can use any number of services. I am actually more in favor of Typeform.
Honestly, unless your jotform Form UI is super complicated, I’d say just rewrite it as an anvil app and convert your http server function to an anvil server callable.
Making a simple interest form in Anvil UI is super easy with the drag and drop editor imho.