Enchaîner les actions
Comment passer la sortie d’une action directement à la suivante, avec un pipeline de trois étapes détaillé et les cas où l’enchaînement n’est pas le bon outil.
Chaque action prend un PDF en entrée et renvoie un PDF en sortie, de sorte que la sortie d’une action est une entrée valide pour la suivante. Cela vous permet de construire un pipeline en plusieurs étapes à partir d’actions à usage unique : fusionner quelques fichiers, apposer un filigrane sur le résultat, puis le chiffrer, le tout dans un même script, en passant les octets d’un appel à l’autre en mémoire.
Comme l’API est stateless (rien n’est stocké entre les requêtes), il n’y a
aucun identifiant à réutiliser ni aucun nettoyage à faire. Chaque étape se
contente de transmettre le corps de sa réponse à l’étape suivante dans le champ
file.
Comment cela fonctionne
Une action à sortie unique répond avec 200 OK et Content-Type: application/pdf. Le corps est un PDF complet. Pour enchaîner, prenez ce corps
et envoyez-le comme partie file de la requête suivante au lieu de lire un
fichier sur le disque. Seules la toute première entrée et la toute dernière
sortie ont besoin de toucher le système de fichiers ; tout ce qui se trouve entre
les deux reste en mémoire.
Un pipeline de trois étapes
Cet exemple transforme deux fichiers source en un seul document chiffré et filigrané.
POST /v1/merge_documents avec cover.pdf et report.pdf renvoie un seul
PDF combiné. Consultez Fusionner des documents
PDF pour les options d’entrée.
Envoyez ce PDF dans le champ file à POST /v1/add_text_watermark. La
réponse est le même document avec un filigrane sur chaque page.
Envoyez le PDF filigrané à POST /v1/add_password avec un password. La
réponse est le document final, protégé : écrivez-le sur le disque.
La fusion accepte les PDF d’entrée sous forme de parties file répétées ou,
lorsque répéter un nom de champ est peu commode (PHP, Ruby), sous forme de
champs numérotés de file_1 à file_10. Les deux formes sont montrées
ci-dessous ; utilisez file répété lorsque vous en avez plus de dix.
# Each stage reads the previous PDF from stdin via `-F 'file=@-'`.
curl -sS https://api.pdfblocks.com/v1/merge_documents \
-H 'X-API-Key: your_api_key' \
-F file=@cover.pdf \
-F file=@report.pdf |
curl -sS https://api.pdfblocks.com/v1/add_text_watermark \
-H 'X-API-Key: your_api_key' \
-F 'file=@-;filename=merged.pdf;type=application/pdf' \
-F line_1='CONFIDENTIAL' \
-F line_2='ACME, Inc.' |
curl -sS https://api.pdfblocks.com/v1/add_password \
-H 'X-API-Key: your_api_key' \
-F 'file=@-;filename=watermarked.pdf;type=application/pdf' \
-F password='pa$$word' \
-o final.pdf# pip install requests
import requests
BASE = 'https://api.pdfblocks.com'
HEADERS = {'X-API-Key': 'your_api_key'}
# 1. Merge cover.pdf and report.pdf into one document.
with open('cover.pdf', 'rb') as cover, open('report.pdf', 'rb') as report:
merged = requests.post(
f'{BASE}/v1/merge_documents',
headers=HEADERS,
files=[('file', cover), ('file', report)],
)
merged.raise_for_status()
# 2. Watermark the merged bytes: no temp file.
watermarked = requests.post(
f'{BASE}/v1/add_text_watermark',
headers=HEADERS,
files={'file': ('merged.pdf', merged.content, 'application/pdf')},
data={'line_1': 'CONFIDENTIAL', 'line_2': 'ACME, Inc.'},
)
watermarked.raise_for_status()
# 3. Encrypt the watermarked bytes.
final = requests.post(
f'{BASE}/v1/add_password',
headers=HEADERS,
files={'file': ('watermarked.pdf', watermarked.content, 'application/pdf')},
data={'password': 'pa$$word'},
)
final.raise_for_status()
with open('final.pdf', 'wb') as output:
output.write(final.content)// Node.js 18+
import { readFile, writeFile } from 'node:fs/promises';
const BASE = 'https://api.pdfblocks.com';
const headers = { 'X-API-Key': 'your_api_key' };
// Post a multipart form and return the response PDF as bytes.
async function post(path, form) {
const response = await fetch(BASE + path, { method: 'POST', headers, body: form });
if (!response.ok) throw new Error(`${path} failed: ${response.status}`);
return new Uint8Array(await response.arrayBuffer());
}
// 1. Merge cover.pdf and report.pdf.
const mergeForm = new FormData();
mergeForm.append('file', new Blob([await readFile('cover.pdf')]), 'cover.pdf');
mergeForm.append('file', new Blob([await readFile('report.pdf')]), 'report.pdf');
const merged = await post('/v1/merge_documents', mergeForm);
// 2. Watermark the merged bytes.
const watermarkForm = new FormData();
watermarkForm.append('file', new Blob([merged]), 'merged.pdf');
watermarkForm.append('line_1', 'CONFIDENTIAL');
watermarkForm.append('line_2', 'ACME, Inc.');
const watermarked = await post('/v1/add_text_watermark', watermarkForm);
// 3. Encrypt the watermarked bytes.
const passwordForm = new FormData();
passwordForm.append('file', new Blob([watermarked]), 'watermarked.pdf');
passwordForm.append('password', 'pa$$word');
const final = await post('/v1/add_password', passwordForm);
await writeFile('final.pdf', final);<?php
$base = 'https://api.pdfblocks.com';
$headers = ['X-API-Key: your_api_key'];
// Post a multipart form and return the response body, or throw on error.
function post(string $url, array $headers, array $fields): string {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fields,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status !== 200) {
throw new RuntimeException("Request to $url failed with status $status.");
}
return $body;
}
// 1. Merge cover.pdf and report.pdf (numbered fields for the array input).
$merged = post("$base/v1/merge_documents", $headers, [
'file_1' => new CURLFile('cover.pdf', 'application/pdf'),
'file_2' => new CURLFile('report.pdf', 'application/pdf'),
]);
// 2. Watermark the merged bytes in memory (CURLStringFile, PHP 8.1+).
$watermarked = post("$base/v1/add_text_watermark", $headers, [
'file' => new CURLStringFile($merged, 'merged.pdf', 'application/pdf'),
'line_1' => 'CONFIDENTIAL',
'line_2' => 'ACME, Inc.',
]);
// 3. Encrypt the watermarked bytes.
$final = post("$base/v1/add_password", $headers, [
'file' => new CURLStringFile($watermarked, 'watermarked.pdf', 'application/pdf'),
'password' => 'pa$$word',
]);
file_put_contents('final.pdf', $final);# gem install http
require 'http'
require 'stringio'
BASE = 'https://api.pdfblocks.com'
HEADERS = { 'X-API-Key' => 'your_api_key' }
def post(path, fields)
response = HTTP.headers(HEADERS).post("#{BASE}#{path}", form: fields)
raise "#{path} failed: #{response.status}" unless response.status.success?
response.body.to_s
end
# 1. Merge cover.pdf and report.pdf (numbered fields for the array input).
merged = post('/v1/merge_documents',
file_1: HTTP::FormData::File.new('cover.pdf'),
file_2: HTTP::FormData::File.new('report.pdf'))
# 2. Watermark the merged bytes in memory.
watermarked = post('/v1/add_text_watermark',
file: HTTP::FormData::File.new(StringIO.new(merged),
filename: 'merged.pdf', content_type: 'application/pdf'),
line_1: 'CONFIDENTIAL',
line_2: 'ACME, Inc.')
# 3. Encrypt the watermarked bytes.
final = post('/v1/add_password',
file: HTTP::FormData::File.new(StringIO.new(watermarked),
filename: 'watermarked.pdf', content_type: 'application/pdf'),
password: 'pa$$word')
File.write('final.pdf', final)package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
const base = "https://api.pdfblocks.com"
// post sends a multipart form and returns the response PDF bytes.
func post(path string, build func(*multipart.Writer)) []byte {
var buf bytes.Buffer
form := multipart.NewWriter(&buf)
build(form)
form.Close()
req, _ := http.NewRequest("POST", base+path, &buf)
req.Header.Set("Content-Type", form.FormDataContentType())
req.Header.Set("X-API-Key", "your_api_key")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if res.StatusCode != http.StatusOK {
panic(fmt.Sprintf("%s failed: %d", path, res.StatusCode))
}
return body
}
func addFile(form *multipart.Writer, name string, data []byte) {
part, _ := form.CreateFormFile("file", name)
part.Write(data)
}
func main() {
cover, _ := os.ReadFile("cover.pdf")
report, _ := os.ReadFile("report.pdf")
// 1. Merge cover.pdf and report.pdf.
merged := post("/v1/merge_documents", func(form *multipart.Writer) {
addFile(form, "cover.pdf", cover)
addFile(form, "report.pdf", report)
})
// 2. Watermark the merged bytes.
watermarked := post("/v1/add_text_watermark", func(form *multipart.Writer) {
addFile(form, "merged.pdf", merged)
form.WriteField("line_1", "CONFIDENTIAL")
form.WriteField("line_2", "ACME, Inc.")
})
// 3. Encrypt the watermarked bytes.
final := post("/v1/add_password", func(form *multipart.Writer) {
addFile(form, "watermarked.pdf", watermarked)
form.WriteField("password", "pa$$word")
})
os.WriteFile("final.pdf", final, 0644)
}using System.Net.Http.Headers;
const string Base = "https://api.pdfblocks.com";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");
// Post a multipart form and return the response PDF bytes.
async Task<byte[]> Post(string path, Action<MultipartFormDataContent> build)
{
using var form = new MultipartFormDataContent();
build(form);
var response = await client.PostAsync(Base + path, form);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsByteArrayAsync();
}
static void AddFile(MultipartFormDataContent form, string name, byte[] data)
{
var content = new ByteArrayContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(content, "file", name);
}
// 1. Merge cover.pdf and report.pdf.
var merged = await Post("/v1/merge_documents", form =>
{
AddFile(form, "cover.pdf", File.ReadAllBytes("cover.pdf"));
AddFile(form, "report.pdf", File.ReadAllBytes("report.pdf"));
});
// 2. Watermark the merged bytes.
var watermarked = await Post("/v1/add_text_watermark", form =>
{
AddFile(form, "merged.pdf", merged);
form.Add(new StringContent("CONFIDENTIAL"), "line_1");
form.Add(new StringContent("ACME, Inc."), "line_2");
});
// 3. Encrypt the watermarked bytes.
var final = await Post("/v1/add_password", form =>
{
AddFile(form, "watermarked.pdf", watermarked);
form.Add(new StringContent("pa$$word"), "password");
});
await File.WriteAllBytesAsync("final.pdf", final);Vérifiez chaque étape avant de transmettre sa sortie
Une étape en échec renvoie un 4XX avec un corps application/problem+json,
pas un PDF. Si vous injectez ce corps d’erreur dans la requête suivante comme
file, l’étape suivante échouera elle aussi, avec un message déroutant.
Vérifiez le statut de chaque réponse avant d’en transmettre le corps : les
exemples ci-dessus lèvent une erreur sur toute réponse autre que 200.
Consultez Erreurs pour la forme de la réponse.
Apposez le filigrane et fusionnez avant de chiffrer. Une fois qu’Ajouter un mot de passe à un PDF a chiffré un document, les actions suivantes ne peuvent plus l’ouvrir : toute étape de mot de passe a donc sa place à la fin du pipeline. Consultez Protéger et déverrouiller des documents pour toutes les règles d’ordre.
Quand enchaîner, et quand ne pas le faire
Enchaînez lorsque chaque étape est une transformation distincte que vous voulez appliquer en séquence. Faites de chaque étape un appel pur, à usage unique : c’est ce qui fait de la sortie de l’une une entrée valide pour la suivante, et ce qui rend les échecs faciles à localiser.
Certaines tâches ressemblent à un enchaînement sans en être un. Réorganiser et écarter des pages en une seule passe, c’est un unique appel à Réorganiser les pages d’un PDF, pas une extraction suivie d’une fusion. N’ayez recours à un pipeline que lorsque aucune action seule ne fait tout le travail.
Voir aussi
Combinez des fichiers comme première étape d’un pipeline.
Apposez du texte sur les pages de n’importe quel PDF.
Ordonnez correctement les actions de mot de passe et de restriction.
Faites circuler en flux les entrées et sorties d’un pipeline sans mise en mémoire tampon.