Passing Data from Form to Anvil Server Function

Hi All,

Hoping for some assistance on an app I’m building.

I’m stuck on making an API call using JSON, and also on how to pass the required data (payload) into the API post request then returning a part of that JSON response to a client readable table.

Here’s the API example (post request) that I need to complete as a server function, and the expected response:

Here is the code I wrote on the servermodule:

On the client side from a button click, I’m trying to send a payload with data pulled from the user completed form into my api request on the server as the required JSON data, have the server return the results of the successful API call, and get just the the “cononicalURL” value from the response to write back to my client viewable table (repeating panel tied to a database).

I know this is a long question, but if anyone has suggestions based on my current code to help out, I would really appreciate it!

Which bit is not doing what you expect?

In the mean time, these jump out at me :

I notice a simple spelling/case mistake - “cononicalURL” in your code as opposed to “canonicalUrl” in your returned json example.

get_wrap.canonicalUrl is probably failing, should probably be
get_wrap['canonicalUrl']

Also, please could you cut/paste code instead of screen grabbing it? That way others can cut/paste to test things locally.

Hi @Dylan, welcome to the Forum!

Having read the code you’ve shown, it looks like it should work, apart from the issue spotted by the eagle-eyed @david.wylie.

If it’s still not working after you’ve fixed that, perhaps you can narrow the problem down by printing out relevant variables at various stages of the process? What does your print(get_wrap['canonicalUrl']) output?


Some small tips

A couple of tips about the add_row statement:

  • It seems logical for the CreatedAt to be datetime.now() - I’m guessing you want to store the date and time the record was created?
  • If the WrapURL is a string, it should probably be get_wrap['canonicalUrl']. Otherwise, you could use a SimpleObject column to store the entire JSON object.

Thank you both for your responses!

This worked perfectly! API call is returning the proper information, and canonical URL is being recorded to the table entry.

I do have another issue with regards to uploading a photo to the database and then utilizing that photo’s URL as a (string) to be passed into my API call.

After lots of reading through the forum today, I figured out how to get the URL of the media object in the table, however when I pass that URL to the “wrap” that I’m building the image doesn’t populate.

Can Anvil’s database host an image at that URL for me indefinitely for continued access? Is access restricted in any way, or does it time out? Should I use Google Drive to host the image upload/url for me?

Just to explain further, a Wrap is essentially a micro website. So the URL I’m passing is looking for an image, similar to if you used an image hosted elsewhere for building a website.

Here’s my code:

Server

@anvil.server.callable
def save_file(file):
  r= app_tables.employee_data.add_row(PhotoURL=file)
  return r['PhotoURL'].get_url(False)

Client (fileloader):

 def file_loader_1_change(self, file, **event_args):
    """This method is called when a new file is loaded into this FileLoader"""
    url= anvil.server.call('save_file', self.file_loader_1.file)
    print (url) 
    
    self.text_box_5.text = url

Client (api call):

 "id": "991b5d30-f897-486e-aa10-0d61ec79f827",
          "data": {
            "first_name": self.text_box_2.text,
            "role": self.drop_down_2.selected_value,
            "employee_email": self.text_box_1.text,
            "phone_number": self.text_box_3.text,
            "photo_url": self.text_box_5.text
          }
        },
        {
          "id": "0c72ea86-93a1-4e7d-a01a-1b871b51c97c"
        }
      ],
      }
    
    
    get_wrap= anvil.server.call(
      'wrapi',
      payload = payload
    )
    
    print (get_wrap)
    
    update_row = self.my_wraps.search()[0].update(CreatedAt=datetime.now(),Email=self.text_box_1.text,FirstName=self.text_box_2.text,LastName=self.text_box_4.text,Market=self.drop_down_1.selected_value,Role=self.drop_down_2.selected_value,PhoneNumber=self.text_box_3.text,WrapURL=get_wrap['canonicalUrl'])
    
    l = list (self.my_wraps.search(tables.order_by("CreatedAt",ascending=False)))
    self.repeating_panel_1.items = l

Thank you for all of your help! I’m almost completed with my first app, and I’m incredibly excited. For someone who started coding and learning Anvil 2 weeks ago, I’m amazed at my progress on this platform. I’m actually building software!

If you print the URL to the media object, what does it show?

I was able to get the URL to print to the text box. But when I then try to push that URL as text from the text box into my JSON payload as a URL, it doesn’t give me an error, but the image can’t be seen on the wrap I built.

The wrap is set up with a databound field for an image URL. via our API I can inject a new URL to then swap out said image.

So, my main question was if images could be hosted and continually accessed from the Anvil database URL on an external site?

Thank you for your help @david.wylie!

**See @meredydd’s answer below **
If you read this before I deleted it - forget it :slight_smile:

Hi @Dylan,

Two parts - first, why what you’re trying isn’t working (and why we built it that way), then what you should do instead:

For security reasons, the url property you get from a Media object in a database is a temporary URL, which only works in the current browser session, and will expire with that session. If those URLs worked everywhere, forever, then you’d be giving every visitor to your app permanent access to everything they see, which probably isn’t what you wanted! We try to make the defaults safe :slight_smile:

(This is covered in the Media objects documentation, although we should probably make it a bit more prominent!)


If you want to make an image available publicly, you can return it from an HTTP endpoint. Here’s an example that uses the database row ID to find a row in a table and return its image:

@anvil.server.http_endpoint('/img/:img_id')
def get_image(img_id):
  row = app_tables.my_images.get_by_id(img_id)
  if row is not None:
    # You can check any other conditions you like here - eg whether this
    # image should be available publicly
    return row['image']

Now you can construct a URL that hits that endpoint for any row from your database:

my_row = app_tables.my_images.get(....)
url = 'https://my-app.anvil.app/_/api/img/' +
           anvil.http.url_encode(my_row.get_id())
2 Likes

Thank you very much David!

You’re welcome, though @meredydd must take credit for the final answer :slight_smile:

@david.wylie, you beat me to it.
@meredydd, thank you very much for providing me this solution! I’m going to try and implement it over the weekend.

I do have one more part of my application that I’m still struggling with and that is getting a successful integration to our SMS endpoint. It let’s us send a “wrap” with parameters for phone_number, body, and type. I can successfully hit the endpoint and send an SMS to my phone via Postman, but can’t replicate it in Anvil.

Should I start a different topic to post my question on this, or continue with it here?

Start a new thread - makes it easier for others to find and follow.

… and do have a look at this :

It might help.

(actually that’s only inbound SMS)