Supports POSTing a file's contents
Supports sending file data as a binary data stream via the Content-Type: application/octet-stream request header.
This allows uploads of an arbitrary size, including uploads larger than the PHP memory limit.
Ensures that settings/validation constraints of the field to which the file is being uploaded will be respected.
Supports naming the file using the Content-Disposition: file; filename="filename.jpg" header
To use JSON:API's file uploads, you must choose to implement one or both of two different "flows":
Flow 1 requires only a single HTTP request, but will only work when the host entity already exists.
Flow 2 requires two HTTP requests but will work under all circumstances.
TL;DR
I tested uploading files using the requests session from the farmOS.py client and it works great:
We can make this even easier in the farmOS.py client by adding a helper method. This can't be done with the existing methods because file uploads must always be a POST with special headers to unique {entity_type}/{bundle}/{file field} endpoints. This ensures proper files are uploaded to the correct location (the location can vary depending on each bundle field) and all proper validation is performed.
Solution:
# Method to be namespaced as client.file.create()
def create(entity_type, bundle, field, data, filename, id = None):
if id is not None:
path = "{entity_type}/{bundle}/{id}/{field}".format(entity_type, bundle, id, field)
else:
path = "{entity_type}/{bundle}/{field}".format(entity_type, bundle, field)
headers = {'Content-Type': 'application/octet-stream', 'Content-Disposition': "file; filename=\"{filename}\"".format(filename)}
return self.session.post(path, data, headers)
# Usage
# Flow 1: update existing log
data = open('data.csv', 'rb').read()
response = client.file.create('log', 'observation', 'file', data, 'observation_data.csv', '{log_id}')
# Flow 2: upload file then include with a new log.
data = open('data.csv', 'rb').read()
response = client.file.create('log', 'observation', 'file', data, 'observation_data.csv')
file_id = response['data']['id']
log_data = {
'attributes': {'name': 'observation log'},
'relationships': { 'file': {'data': [{'type': 'file--file', 'id': file_id}]}},
}
new_log = client.log.send('observation', log_data)
Some context on this:
An overview:
TL;DR
I tested uploading files using the requests session from the farmOS.py client and it works great:
We can make this even easier in the farmOS.py client by adding a helper method. This can't be done with the existing methods because file uploads must always be a
POST
with special headers to unique{entity_type}/{bundle}/{file field}
endpoints. This ensures proper files are uploaded to the correct location (the location can vary depending on each bundle field) and all proper validation is performed.Solution: