You are currently viewing the new Anvil Editor Docs.
Switch to the Classic Editor Docs
You are currently viewing the Classic Editor Docs.
Switch to the new Anvil Editor Docs

Creating HTTP APIs

You can build an HTTP API for your app by decorating server functions with the @anvil.server.http_endpoint decorator.

You can use this to give your app a REST API that non-Anvil apps can use to interface with it, in situations where you can’t use the Uplink.

Before you build an HTTP interface for your app, consider using the Uplink instead. It lets you make any Python code behave like an Anvil Server Module.

If you want other people/organisations to interface with your app, they can still use the Uplink safely with the Uplink client key.

The http_endpoint decorator

The @anvil.server.http_endpoint decorator makes your function callable over HTTP. It has one required argument - the path, e.g. /users/list.

import anvil.server

@anvil.server.http_endpoint("/users/list")
def get_user_list():
  return [u['email'] for u in app_tables.users.search()]

Path parameters

You can think of URLs as having two parts: origin and path. Assume you have this URL:

https://<your-app-id>.anvil.app/_/api/users/1234

The origin is https://<your-app-id>.anvil.app/_/api, this tells Anvil how to route requests to your app.

The path is /users/1234. This is what is passed into your @anvil.server.http_endpoint functions.

The path may contain one or more path parameters, denoted by the : character, e.g. /users/:id.

import anvil.server

@anvil.server.http_endpoint("/users/:id")
def get_user(id):
  return f"You requested user {id}"

In the example above, if you navigate to https://<your-app-id>.anvil.app/_/api/users/42, you will receive a response of You requested user 42:

You can also use path parameters in the middle of a path (/users/:id/history) or use multiple path parameters in the same path (/users/:user_id/history/:item_id).

Query strings

The query string is the part of the URL after the question mark (?), such as in this URL:

https://<your-app-id>.anvil.app/_/api/users/42?x=foo

It consists of key/value pairs key=value. If there are multiple key/value pairs, they are separated by &, for example key1=value1&key2=value2.

Query-string parameters will be passed to your function as keyword arguments. In this example, we use Python’s ** notation to capture all query string parameters in the params variable:

import anvil.server

@anvil.server.http_endpoint("/users/:id")
def get_user(id, **params):
  return f"You requested user {id} with params {params}"

In the example above, if you navigate to https://<my-app-id>.anvil.app/_/api/users/42?x=foo, you will receive a response of You requested user 42 with params {'x': 'foo'}.

Optional keyword arguments

To configure your HTTP endpoints more, @anvil.server.http_endpoint takes some optional keyword arguments:

  • methods specifies which HTTP methods this endpoint supports (the default is ['GET','POST'])
  • enable_cors adds CORS HTTP headers (Access-Control-Allow-Origin: *) to your response when set to True. By default, we set CORS headers to permit requests from any web address where your app can be reached (eg xyz.anvil.app, my-custom-domain.com, etc).
  • cross_site_session is described in Cross-site Security.
  • require_credentials and authenticate_users are described in Authentication.

Getting the URL for your API

Getting it manually

If your app is published, your API is at

https://<your-app>.anvil.app/_/api...

or at

https://your-custom-domain.com/_/api...

if you have a custom domain.

If your app is private, the endpoints will be at

https://<your-app-id>.anvil.app/<your private access key>/_/api/...

Getting it automatically

Sometimes you will want to generate URLs that point to your HTTP endpoints without having to hard-code the origin of your app. Instead of writing:

endpoint_url = "https://my-app.anvil.app/_/api/users"

You can call anvil.server.get_api_origin():

endpoint_url = anvil.server.get_api_origin() + "/users"

This has the advantage of returning whichever origin the user is currently connected on, i.e. if you have published a version but you are running your development version in the Anvil editor, get_api_origin() will return a temporary private link to your development version, so you can test your APIs before publishing them!

If you’re running in the editor, get_api_origin() might return a URL that’s private or not permanent. To get the origin for the published version of your app, call get_api_origin('published').

You can also get the origin of the whole app to generate links for a browser:

app_url = anvil.server.get_app_origin()

If you’re using a custom domain, get_app_origin will sometimes still return the .anvil.app domain, if it cannot verify the DNS settings for your custom domain.

If you wish to programmatically construct URLs containing your custom domain, hard-code a constant containing your custom domain and construct URLs from that.

The request object

HTTP requests have far more information associated with them than just path and query-string parameters. This information can be accessed through the anvil.server.request object, which is a global variablenote containing information about the request currently being processed.

import anvil.server

@anvil.server.http_endpoint("/users/:id")
def get_user(id):
  ip = anvil.server.request.remote_address
  return f"You requested user {id} from IP {ip}"

The request object has the following attributes:

  • path - The path of this HTTP request.
  • method - The method of this HTTP request, e.g. GET, POST, etc.
  • query_params - The query-string parameters passed with this request, as a dictionary.
  • form_params - The form parameters passed with this request, as a dictionary.
  • origin - The URL origin of this HTTP request.
  • headers - Headers passed with this request, as a dictionary.
  • remote_address - The IP address of the source of this request.
  • body - The body of this HTTP request, as an anvil.Media object.
  • body_json - For requests with Content-Type: application/json, this is the decoded body as a dictionary. Otherwise None.
  • username - For authenticated requests (see Authentication), returns the provided username. Otherwise None.
  • password - For authenticated requests (see Authentication), returns the provided password. Otherwise None.
  • user - For authenticated requests, returns the row from the Users table representing the authenticated user.
Footnote: Technically, anvil.server.request is thread-local. (^ go back)

Returning a response

Functions decorated with @anvil.server.http_endpoint can return:

  • strings (which will be returned with a Content-Type of text/plain)
  • anvil.Media objects (which will be returned with their attached Content-Type)
  • any JSON-able object like a plain list or dict (which will be returned with Content-Type application/json).
import anvil.server

@anvil.server.http_endpoint("/foo")
def serve_content():
  # This response will have Content-Type application/json
  return {"key": "value"}

HttpResponse object

If you need more control over the response, you can return an anvil.server.HttpResponse object (API Docs), providing a custom status code and response body:

import anvil.server

@anvil.server.http_endpoint("/foo")
def serve_content():
  return anvil.server.HttpResponse(200, "Body goes here")

These can be used for all the standard HTTP response codes that the browser expects.

For instance, here is a redirection response which causes the user’s browser to take them to a different webpage:

import anvil.server

@anvil.server.http_endpoint("/foo")
def serve_content():
  response = anvil.server.HttpResponse(302, "Redirecting to Wikipedia...")
  response.headers['Location'] = "www.wikipedia.org"
  return response

You can use this method to redirect users to another part of your app, after they have triggered some action by hitting a particular HTTP endpoint.

To add custom headers to your response, just add them to the headers dictionary, an attribute of the HttpResponse object.


Do you still have questions?

Our Community Forum is full of helpful information and Anvil experts.