Skip to content

Improve request payload docs #1566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 19, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 172 additions & 24 deletions docs/deployments/realtime-api/predictors.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,58 +492,206 @@ If your application requires additional dependencies, you can install additional

## API requests

The type of the `payload` parameter in `predict(self, payload)` can vary based on the content type of the request. The `payload` parameter is parsed according to the `Content-Type` header in the request:
The type of the `payload` parameter in `predict(self, payload)` can vary based on the content type of the request. The `payload` parameter is parsed according to the `Content-Type` header in the request. Here are the parsing rules (see below for examples):

1. For `Content-Type: application/json`, `payload` will be the parsed JSON body.
1. For `Content-Type: multipart/form-data` / `Content-Type: application/x-www-form-urlencoded`, `payload` will be `starlette.datastructures.FormData` (key-value pairs where the value is a `string` for form data, or `starlette.datastructures.UploadFile` for file uploads, see [Starlette's documentation](https://www.starlette.io/requests/#request-files)).
1. For `Content-Type: multipart/form-data` / `Content-Type: application/x-www-form-urlencoded`, `payload` will be `starlette.datastructures.FormData` (key-value pairs where the values are strings for text data, or `starlette.datastructures.UploadFile` for file uploads; see [Starlette's documentation](https://www.starlette.io/requests/#request-files)).
1. For all other `Content-Type` values, `payload` will be the raw `bytes` of the request body.

The `payload` parameter type will be a Python object (*lists*, *dicts*, *numbers*) if a request with a JSON payload is made:
Here are some examples:

### JSON data

#### Making the request

##### Curl

```bash
$ curl http://***.amazonaws.com/my-api \
$ curl https://***.amazonaws.com/my-api \
-X POST -H "Content-Type: application/json" \
-d '{"key": "value"}'
```

The `payload` parameter type will be a `bytes` object if a request with a `Content-Type: application/octet-stream` is made:
Or if you have a json file:

```bash
$ curl http://***.amazonaws.com/my-api \
-X POST -H "Content-Type: application/octet-stream" \
--data-binary @file.bin
$ curl https://***.amazonaws.com/my-api \
-X POST -H "Content-Type: application/json" \
-d @file.json
```

The `payload` parameter type will be a `bytes` object if a request doesn't have the `Content-Type` set:
##### Python

```bash
$ curl http://***.amazonaws.com/my-api \
-X POST -H "Content-Type:" \
-d @sample.txt
```python
import requests

url = "https://***.amazonaws.com/my-api"
requests.post(url, json={"key": "value"})
```

The `payload` parameter type will be a `starlette.datastructures.FormData` object if a request with a `Content-Type: multipart/form-data` is made:
Or if you have a json string:

```python
import requests
import json

url = "https://***.amazonaws.com/my-api"
jsonStr = json.dumps({"key": "value"})
requests.post(url, data=jsonStr, headers={"Content-Type": "application/json"})
```

#### Reading the payload

When sending a JSON payload, the `payload` parameter will be a Python object:

```python
class PythonPredictor:
def __init__(self, config):
pass

def predict(self, payload):
print(payload["key"]) # prints "value"
```

### Binary data

#### Making the request

##### Curl

```bash
$ curl http://***.amazonaws.com/my-api \
-X POST -H "Content-Type: multipart/form-data" \
-F "fieldName=@file.txt"
$ curl https://***.amazonaws.com/my-api \
-X POST -H "Content-Type: application/octet-stream" \
--data-binary @object.pkl
```

##### Python

```python
import requests
import pickle

url = "https://***.amazonaws.com/my-api"
pklBytes = pickle.dumps({"key": "value"})
requests.post(url, data=pklBytes, headers={"Content-Type": "application/octet-stream"})
```

#### Reading the payload

Since the `Content-Type: application/octet-stream` header is used, the `payload` parameter will be a `bytes` object:

```python
import pickle

class PythonPredictor:
def __init__(self, config):
pass

def predict(self, payload):
obj = pickle.loads(payload)
print(obj["key"]) # prints "value"
```

The `payload` parameter type will be a `starlette.datastructures.FormData` object if a request with a `Content-Type: application/x-www-form-urlencoded` is made:
Here's an example if the binary data is an image:

```python
from PIL import Image
import io

class PythonPredictor:
def __init__(self, config):
pass

def predict(self, payload, headers):
img = Image.open(io.BytesIO(payload)) # read the payload bytes as an image
print(img.size)
```

### Form data (files)

#### Making the request

##### Curl

```bash
$ curl http://***.amazonaws.com/my-api \
-X POST -H "Content-Type: application/x-www-form-urlencoded" \
-d @file.txt
$ curl https://***.amazonaws.com/my-api \
-X POST \
-F "text=@text.txt" \
-F "object=@object.pkl" \
-F "image=@image.png"
```

##### Python

```python
import requests
import pickle

url = "https://***.amazonaws.com/my-api"
files = {
"text": open("text.txt", "rb"),
"object": open("object.pkl", "rb"),
"image": open("image.png", "rb"),
}

requests.post(url, files=files)
```

#### Reading the payload

When sending files via form data, the `payload` parameter will be `starlette.datastructures.FormData` (key-value pairs where the values are `starlette.datastructures.UploadFile`, see [Starlette's documentation](https://www.starlette.io/requests/#request-files)). Either `Content-Type: multipart/form-data` or `Content-Type: application/x-www-form-urlencoded` can be used (typically `Content-Type: multipart/form-data` is used for files, and is the default in the examples above).

```python
from PIL import Image
import pickle

class PythonPredictor:
def __init__(self, config):
pass

def predict(self, payload):
text = payload["text"].file.read()
print(text.decode("utf-8")) # prints the contents of text.txt

obj = pickle.load(payload["object"].file)
print(obj["key"]) # prints "value" assuming `object.pkl` is a pickled dictionary {"key": "value"}

img = Image.open(payload["image"].file)
print(img.size) # prints the dimensions of image.png
```

The `payload` parameter type will be a `starlette.datastructures.FormData` object if no headers are added to the request:
### Form data (text)

#### Making the request

##### Curl

```bash
$ curl http://***.amazonaws.com/my-api \
$ curl https://***.amazonaws.com/my-api \
-X POST \
-d @file.txt
-d "key=value"
```

##### Python

```python
import requests

url = "https://***.amazonaws.com/my-api"
requests.post(url, data={"key": "value"})
```

#### Reading the payload

When sending text via form data, the `payload` parameter will be `starlette.datastructures.FormData` (key-value pairs where the values are strings, see [Starlette's documentation](https://www.starlette.io/requests/#request-files)). Either `Content-Type: multipart/form-data` or `Content-Type: application/x-www-form-urlencoded` can be used (typically `Content-Type: application/x-www-form-urlencoded` is used for text, and is the default in the examples above).

```python
class PythonPredictor:
def __init__(self, config):
pass

def predict(self, payload):
print(payload["key"]) # will print "value"
```

## API responses
Expand Down