PDF Form Submission Acrobat to REST API Server

tanut aran
CODEMONDAY
Published in
3 min readNov 25, 2022

What this solution is for

People who still want the client filled PDF Document.

Mostly because of the government regulation or some legacy work process.

But they are too painful with the PDF human key in mistake or tedious work of doing so.

Warning

This solution is possible in Adobe Acrobat only.

This will never work on subset of software that implement PDF e.g. Google Chrome, MS Edge and almost all online or offline PDF reader.

Prepare the form

You need to create the fillable PDF form like so from Acrobat Pro

On the right hand side go to “Prepare Form”.

Then fill in the editable field then button.

After adding functinoality you config what your button will do.

Don’t confuse by the bad UX. Pick drop down. Click Add.

The actions is ONLY what is in the actions box. You can add multiple actions like clearing the form afterward.

Common mistake

The popup ‘Unkown Format’ URL on Acrobat form submission

Credit to this forum

I spent sometime decrpyting their answer so what exactly we need is

Make the server response with the headers format that make Acrobat happy which are:

Content-Type: application/vnd.fdf
Content-disposition: inline

Note that this is mandatory to get rid of the error message

Popup the success message

When the form success, we have no clue on the submission status.

We have response something from the server and possibly popup the success message from the Acrobat screen.

This can be done by putting the Javascript inside the FDF response body. This must be set at your REST API server

Content-Type: application/vnd.fdf
Content-disposition: inline
Body: %FDF-1.2
1 0 obj
<<
/FDF
<<
/JavaScript
<<
/Doc 2 0 R
/After (confirmSend();)
>>
>>
>>
endobj
2 0 obj
[
(confirmSend) 3 0 R
]
endobj
3 0 obj
<<
>>
stream
function confirmSend()
{
app.alert({
cTitle : 'Submission Result',
cMsg : 'Your form name {{{first_name}}} client id {{{client_id}}} submission is success.',
nIcon : 3
});
}
endstream
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF

Here we go. I think we have done all the must-have function.

See you next time.

Bonus: My Python AWS Lambda REST Server

This code accept Acrobat PDF submission and append it to the CSV file inside S3.

import json
import boto3
import csv
import urllib

BUCKET_NAME = 'my-demo'
OBJECT_NAME = 'sample/output.csv'
LAMBDA_LOCAL_TMP_FILE = '/tmp/test.csv'

FDF_RESPONSE_TEMPLATE = '''
%FDF-1.2
1 0 obj
<<
/FDF
<<
/JavaScript
<<
/Doc 2 0 R
/After (confirmSend();)
>>
>>
>>
endobj
2 0 obj
[
(confirmSend) 3 0 R
]
endobj
3 0 obj
<<
>>
stream
function confirmSend()
{
app.alert({
cTitle : 'Submission Result',
cMsg : 'Your form name {{{first_name}}} client id {{{client_id}}} submission is success.',
nIcon : 3
});
}
endstream
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF
'''

def lambda_handler(event, context):

s3 = boto3.client('s3')
s3.download_file(BUCKET_NAME, OBJECT_NAME, LAMBDA_LOCAL_TMP_FILE)

body = urllib.parse.parse_qs(event['body'])
first_name = body['first_name'][0]
client_id = body['client_id'][0]
country = body['country'][0]

row = [first_name, client_id, country]

with open(LAMBDA_LOCAL_TMP_FILE, 'a') as f:
writer = csv.writer(f)
writer.writerow(row)

s3.upload_file(LAMBDA_LOCAL_TMP_FILE, BUCKET_NAME, OBJECT_NAME)

return {
'statusCode': 200,
'body': FDF_RESPONSE_TEMPLATE.replace('{{{first_name}}}', first_name).replace('{{{client_id}}}', client_id),
'headers': {
'Content-Type': 'application/vnd.fdf',
'Content-disposition' : 'inline'
}

}

--

--