Skip to content
View in the app

A better way to browse. Learn more.

FMForums.com

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Using DynaPDF with Data API for PDF generation

Featured Replies

Did you know that you can use MBS FileMaker Plugin in the Data API and provide an API to the outside world to produce PDFs?

You can have an external request come in to start a script, have the script create a PDF based on the given script parameters and then store it in a contaner field. Then another call can download that specific PDF from the container field. We use a global field here for the temporary storage. On a server script, global fields act like global variables and each session has their own one. So unless you prefer to store the PDF in a new record, you could simply use a global field to keep it until the session is finished.

Let's start with installation. The MBS FileMaker Plugin and the dynapdf library files go into the /FileMaker Server/Web Publishing/publishing-engine/wip/Plugins/ folder. After you copied the plugin there, you need to restart the wip process for Data API to have it load it. Once loaded you see a new log file in the Logs folder. When the dynapdf library is in the same folder as the plugin, we can load it with "" as path. If you registered the MBS server license before on the scripting engine, the MBS FileMaker Plugin for Data API should pick that up. But it is always good to have an MBS register script to apply the license if IsRegistered functions returns a zero.

Here is a sample script to make a PDF with text from the script parameter:

# Initialize DynaPDF if needed If [ MBS("DynaPDF.IsInitialized") ≠ 1 ] Perform Script [ “InitDynaPDF” ; Specified: From list ; Parameter: ] End If # Go to Layout [ “Asset Details” (Assets) ; Animation: None ] # # Start with a new PDF document Set Variable [ $pdf ; Value: MBS("DynaPDF.New") ] # Add page Set Variable [ $r ; Value: MBS("DynaPDF.AppendPage"; $pdf) ] Set Variable [ $r ; Value: MBS("DynaPDF.SetPageCoords"; $pdf; "topdown") ] Set Variable [ $r ; Value: MBS("DynaPDF.SetFont"; $pdf; "Helvetica"; 0; 12) ] # Write some text Set Variable [ $text ; Value: "Parameter: " & Get(ScriptParameter) ] Set Variable [ $r ; Value: MBS("DynaPDF.SetFillColor"; $pdf; 0; 0; 0) ] Set Variable [ $r ; Value: MBS("DynaPDF.WriteStyledTextEx"; $pdf; 10; 10; 300; -1; "justify"; $Text) ] # now figure out how much space we needed to make the page the right size Set Variable [ $height ; Value: MBS("DynaPDF.GetLastTextPosY"; $pdf) ] Set Variable [ $ph ; Value: MBS("DynaPDF.GetPageHeight"; $pdf) ] Set Variable [ $r ; Value: MBS( "DynaPDF.SetBBox"; $PDF; "Media"; 0; $ph; 320; $height - 10 ) ] # close page, document and save PDF Set Variable [ $r ; Value: MBS("DynaPDF.EndPage"; $pdf) ] Set Variable [ $Result ; Value: MBS("DynaPDF.Save"; $pdf; "hello.pdf") ] Set Variable [ $r ; Value: MBS("DynaPDF.Release"; $pdf) ] # Put in Container Set Field [ Assets::PDF ; $Result ] Exit Script [ Text Result: "PDF Created" ]

Let's call this script from the outside. This could be in FileMaker again, but we could use the curl command line tool. We have to make the following API calls:

  1. We start by asking for a new session token. The query goes to the URL of our server, e.g. "https://10.211.55.16" for the local server here. Then we need to specify which database we use and what credentials we have. Also we need to pass some JSON with further options, but since we have none, this is just "{}".

    curl -s -k -X POST \
      "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions" \
      -H "Content-Type: application/json" \
      -u "${USERNAME}:${PASSWORD}" \
      -d "{}"

    From the result, we extract the session token.

  2. We continue with triggering the script. This time we need to specify a layout and for this we made a specific PDFLayout, which only has the fields needed for the script. Here we can pass a parameter, which needs to be URL encoded. But you can pass JSON here if you need structured data.

    curl -s -k \
      "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/script/CreatePDF?script.param=${ENCODED_PARAM}" \
      -H "Authorization: Bearer ${TOKEN}

    The result should indicate the script run through and provide the script result. That allows the script to return the record ID for a new record or a JSON for more detailed structured response. In our case we return the PDF via a global field, so we don't need a record ID.

  3. Time to query the first record to get the URL to download the PDF. We query the records and limit the output to one record. Since FileMaker likes to set a session cookie for the download of the PDF, we need to tell CURL to keep cookies.

    curl -s -k \
      "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/records?_limit=1" \
      -H "Authorization: Bearer ${TOKEN}" \
      -c "${COOKIE_FILE}

    The result is a JSON which contains the PDF download URL.

  4. Once we have the URL, we do the download:

    curl -s -k \
      -H "Authorization: Bearer ${TOKEN}" \
      -b "${COOKIE_FILE}" \
      -o "${OUTPUT_FILE}" \
      "${PDF_URL}"

    This writes the PDF directly to the output file.

  5. On the end of the script, we need to close the session, which also releases the global field:

    curl -s -k -X DELETE \
      "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions/${TOKEN}"

Here is a shell script doing all the steps in Terminal:


#!/usr/bin/env bash

set -euo pipefail

# -----------------------------------------------------------------------------
# Configuration
# -----------------------------------------------------------------------------

BASE_URL="https://10.211.55.16"
DATABASE="Assets"
LAYOUT="PDFLayout"

USERNAME="user"
PASSWORD="user"

SCRIPT_PARAM="Hello World"

COOKIE_FILE="cookies.txt"
OUTPUT_FILE="test.pdf"

# -----------------------------------------------------------------------------
# Step 1: Create session and get token
# -----------------------------------------------------------------------------

echo "Creating session..."

SESSION_RESPONSE=$(curl -s -k -X POST \
  "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions" \
  -H "Content-Type: application/json" \
  -u "${USERNAME}:${PASSWORD}" \
  -d "{}")

echo "Session response:"
echo "${SESSION_RESPONSE}"

TOKEN=$(echo "${SESSION_RESPONSE}" | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')

if ; then
  echo "ERROR: Could not extract token"
  exit 1
fi

echo "Token: ${TOKEN}"

# -----------------------------------------------------------------------------
# Step 2: Run FileMaker script
# -----------------------------------------------------------------------------

ENCODED_PARAM=$(printf '%s' "${SCRIPT_PARAM}" | sed 's/ /%20/g')

echo "Running CreatePDF script..."

SCRIPT_RESPONSE=$(curl -s -k \
  "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/script/CreatePDF?script.param=${ENCODED_PARAM}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -c "${COOKIE_FILE}")

echo "Script response:"
echo "${SCRIPT_RESPONSE}"

# -----------------------------------------------------------------------------
# Step 3: Get one record and extract PDF URL
# -----------------------------------------------------------------------------

echo "Fetching record..."

RECORD_RESPONSE=$(curl -s -k \
  "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/records?_limit=1" \
  -H "Authorization: Bearer ${TOKEN}" \
  -c "${COOKIE_FILE}")

echo "Record response:"
echo "${RECORD_RESPONSE}"

PDF_URL=$(echo "${RECORD_RESPONSE}" | sed -n 's/.*"PDF":"\([^"]*\)".*/\1/p')

# Unescape JSON escaped slashes
PDF_URL=$(echo "${PDF_URL}" | sed 's#\\/#/#g')

if ; then
  echo "ERROR: Could not extract PDF URL"
  exit 1
fi

echo "PDF URL:"
echo "${PDF_URL}"

# -----------------------------------------------------------------------------
# Step 4: Download PDF
# -----------------------------------------------------------------------------

echo "Downloading PDF..."

curl -s -k \
  -H "Authorization: Bearer ${TOKEN}" \
  -b "${COOKIE_FILE}" \
  -o "${OUTPUT_FILE}" \
  "${PDF_URL}"

echo "PDF downloaded to ${OUTPUT_FILE}"

# -----------------------------------------------------------------------------
# Step 5: Delete session
# -----------------------------------------------------------------------------

echo "Deleting session..."

curl -s -k -X DELETE \
  "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions/${TOKEN}"

echo
echo "Session deleted"

# -----------------------------------------------------------------------------
# Step 6: Cleanup
# -----------------------------------------------------------------------------

rm -f "${COOKIE_FILE}"

echo "Cookies removed"
echo "Done"

When you run such a script, you see the following output:

Creating session...
Session response:
{"response":{"token":"5d203f8e9fa48ae10dda519ac3a79513b44ec1a7cc486d9f8a25"},"messages":[{"code":"0","message":"OK"}]}
Token: 5d203f8e9fa48ae10dda519ac3a79513b44ec1a7cc486d9f8a25
Running CreatePDF script...
Script response:
{"response":{"scriptResult":"PDF Created","scriptError":"0"},"messages":[{"code":"0","message":"OK"}]}
Fetching record...
Record response:
{
  "response": {
    "dataInfo": {
      "database": "Assets",
      "layout": "PDFLayout",
      "table": "Assets",
      "totalRecordCount": 25,
      "foundCount": 25,
      "returnedCount": 1
    },
    "data": [
      {
        "fieldData": {
          "PDF": "https://10.211.55.16:443/Streaming/MainDB/77C8957F305297674C98AF4F9DCF
           5847722CC4D1F525316A33B3412DAC81D9B7.pdf?RCType=EmbeddedRCFileProcessor"
        },
        "portalData": {},
        "recordId": "1",
        "modId": "25"
      }
    ]
  },
  "messages": [
    {
      "code": "0",
      "message": "OK"
    }
  ]
}
PDF URL:
https://10.211.55.16:443/Streaming/MainDB/77C8957F305297674C98AF4F9DCF
  5847722CC4D1F525316A33B3412DAC81D9B7.pdf?RCType=EmbeddedRCFileProcessor
Downloading PDF...
PDF downloaded to test.pdf
Deleting session...
{"response":{},"messages":[{"code":"0","message":"OK"}]}
Session deleted
Cookies removed
Done

Please try this. Generating PDF documents on the fly using Data API calls may be very useful. Especially if you use data in the database to fill the records. FileMaker may create a temporary PDF from some records and then you post process them with DynaPDF. e.g. adding page numbers, watermarks or signatures. And this could be called from a custom facing website to download receipts or confirmations on demand.

On the security note, please keep such an API to a separate file with specific logins and only the scripts, records and fields people should see from the outside. Don't let anyone access the whole solution and cause damage.

See also

Create an account or sign in to comment

Important Information

By using this site, you agree to our Terms of Use.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.