File upload support has been added to JSON:API. This makes JSON:API as capable as Drupal core REST and also adds a new feature above and beyond core REST.
Base64 is a group of binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. By consisting only in ASCII characters, base64 strings are generally url-safe, and that's why they can be used to encode data in Data URLs.
What does that mean?
JSON:API now:
- Supports
POST
ing 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.
Flow 1 (single HTTP request; host entity must already exist)
You must send a
POST
request, like so:The response for this request will be the JSON:API response for a newly created file entity, as if you were to request
GET /jsonapi/file/file/{UUID of new file entity}
.Flow 2 (two HTTP requests; no restrictions)
Step 1
You must send a
You must send a
POST
request, like so:The response for this request will be the JSON:API response for a newly created file entity, as if you were to request
GET /jsonapi/file/file/{UUID of new file entity}
Step 2
To ensure that Drupal does not automatically delete this newly created file on cron, you must 'use' the file by creating an entity reference to it. JSON:API supports both
To ensure that Drupal does not automatically delete this newly created file on cron, you must 'use' the file by creating an entity reference to it. JSON:API supports both
POST
and PATCH
on entity references if the entity already exists. Typically, you will want to use POST
unless you intend to replace any already referenced files. In both cases, you will need to parse and extract the UUID of new file entity from the response to your first request.When the entity does not already exist (this will be the case when the file is needed for a required field), you will need to create the entity using a
POST
:Wondering about something?
If you wonder why it is designed to work this way, see the very detailed issue summary of #1927648: Allow creation of file entities from binary data via REST requests, which explains every key design decision!
And, as always, feel free to open a support request.
How to send binary data with curl?
Module developers
- Log in or register to post comments
Comments
I tried converting the base64
I tried converting the base64 for the image and when I attached the body post : [..binarydata..] it creates a blank image on the rest?
and no documentations are provided on what binary data should we provide?
- Log in or register to post comments
File Upload using JSON:API
Use function to decode the Image
=> Use base64_decode to decode the Image if it is base64 Encoded Image
=> Use base64_decode to decode the Image if it is base64 Encoded Image
Can also upload binary data
Convert Image into binary and then upload.
Convert Image into binary and then upload.
- Log in or register to post comments
Get a Response 500
I tried to upload image files into an image filed using the JSON API. However, I get an error (response 500) when I try to do Step 1 of Flow 2. Below is my python code. Where did I do wrong? Really appreciate some help here. I am using JSON API Version: 8.x-2.4.
- Log in or register to post comments
Update Allowed Headers
briangonzalezmia commented
Did you remember to update the allowed headers in your CORS config to include 'content-disposition'? That was my issue when I first tried to upload files. See my config below.
- Log in or register to post comments
What is 'binary file data'?
gabesullice commented
It seems that that many people are equating 'binary' with 'base64' (in this thread and on Slack). These are not the same thing:
binary ! base64
.You do not need to convert your data at all before sending it to Drupal.
The file sent, byte-for-byte, exactly as it sits in your filesystem. You do not need to encode the file. Just send it 'as-is'.
If you're working in JavaScript, this typically means that you should be setting the
data
attribute of your request to a Blob
or File
object.Here is an example of uploading a file using the browser's
fetch
API with a file form input. (this example is not using Drupal, but it does demonstrate how to add 'binary file data' to a request).- Log in or register to post comments
These two images show how to use postman to test this
These two images show how to use postman to test file upload by JSON:API
- Log in or register to post comments
File Upload using JSON:API
1. Send a POST request using POSTMAN
POST /jsonapi/node/article/field_image
[example:{{url}}/jsonapi/node/test/field_image]
1.1. In Authorization tab
Select Type [example: OAuth 2.0 ]
Enter Access Token [example: eyJ0eXAiOiJKV1Qi.....]
1.2. In Headers Tab
Add the following key and value
1. Content-Type application/octet-stream
2. Accept application/vnd.api+json
3. Content-Disposition file; filename='Testing1.jpg'
1.3. In Body Tab
Select Binary and select file with .txt
=> sample.txt [Image file converted to binary or base64]
POST /jsonapi/node/article/field_image
[example:{{url}}/jsonapi/node/test/field_image]
1.1. In Authorization tab
Select Type [example: OAuth 2.0 ]
Enter Access Token [example: eyJ0eXAiOiJKV1Qi.....]
1.2. In Headers Tab
Add the following key and value
1. Content-Type application/octet-stream
2. Accept application/vnd.api+json
3. Content-Disposition file; filename='Testing1.jpg'
1.3. In Body Tab
Select Binary and select file with .txt
=> sample.txt [Image file converted to binary or base64]
If success you should get a status message 201 Created
2. Get newly created file entity
GET /jsonapi/file/file/{UUID of new file entity}
[example:{{url}}/jsonapi/file/file/56256e3a-a5c1-46fd-aac7-a1cad1b51e97]
GET /jsonapi/file/file/{UUID of new file entity}
[example:{{url}}/jsonapi/file/file/56256e3a-a5c1-46fd-aac7-a1cad1b51e97]
If exists you should get a status message 200 OK
3. Create the entity using a POST and add the file required for image field
POST /jsonapi/node/article
[example:{{url}}/jsonapi/node/test]
3.1. In Authorization tab
Select Type [example: OAuth 2.0 ]
Enter Access Token [example: eyJ0eXAiOiJKV1Qi.....]
3.2. In Headers Tab
Add the following key and value
1. Content-Type application/vnd.api+json
2. Accept application/vnd.api+json
3.3. In Body Tab
Select raw and add the following
{
'data': {
'type': 'node--test',
'attributes': {
'title': 'Testing1'
},
'relationships': {
'field_image': {
'data': {
'type': 'file--file',
'id': '56256e3a-a5c1-46fd-aac7-a1cad1b51e97', {UUID of new file entity}
'meta': {
'alt': 'Json Uploaded Testing1',
'title': 'Json Uploaded Testing1',
'width': null,
'height': null
}
}
}
}
}
}
POST /jsonapi/node/article
[example:{{url}}/jsonapi/node/test]
3.1. In Authorization tab
Select Type [example: OAuth 2.0 ]
Enter Access Token [example: eyJ0eXAiOiJKV1Qi.....]
3.2. In Headers Tab
Add the following key and value
1. Content-Type application/vnd.api+json
2. Accept application/vnd.api+json
3.3. In Body Tab
Select raw and add the following
{
'data': {
'type': 'node--test',
'attributes': {
'title': 'Testing1'
},
'relationships': {
'field_image': {
'data': {
'type': 'file--file',
'id': '56256e3a-a5c1-46fd-aac7-a1cad1b51e97', {UUID of new file entity}
'meta': {
'alt': 'Json Uploaded Testing1',
'title': 'Json Uploaded Testing1',
'width': null,
'height': null
}
}
}
}
}
}
If success you should get a status message 201 Created
4. If the text file uploaded is base64 encoded, Image will not be displayed properly
Create a custom module with hook_node_presave function to decode the Image
=> Use base64_decode to decode the Image
Create a custom module with hook_node_presave function to decode the Image
=> Use base64_decode to decode the Image
- Log in or register to post comments