Skip to content

Add batch support to /anonymize and /deanonymize endpoints - #2233

Open
bijay-odyssey wants to merge 1 commit into
data-privacy-stack:mainfrom
bijay-odyssey:feat-bulk-anonymize-deanonymize
Open

Add batch support to /anonymize and /deanonymize endpoints#2233
bijay-odyssey wants to merge 1 commit into
data-privacy-stack:mainfrom
bijay-odyssey:feat-bulk-anonymize-deanonymize

Conversation

@bijay-odyssey

Copy link
Copy Markdown

Closes #1045.

Problem

/analyze already accepts text as either a single string or an array of strings, returning a matching array of results when given a batch (via BatchAnalyzerEngine). /anonymize and /deanonymize never got the same treatment — even though the core package already ships BatchAnonymizerEngine and BatchDeanonymizeEngine, unused by the HTTP layer.

Change

Both endpoints now accept text as a string (unchanged, existing behavior) or an array of strings. In array mode:

  • analyzer_results (for /anonymize) / anonymizer_results (for /deanonymize) must be an array of the same length as text, one list of per-text results.
  • The response becomes a matching array of results (same shape as the single-text response, one object per input text).
  • A length mismatch between text and the results array raises a clear 422 instead of silently misaligning or dropping data.
  • Omitting the results field entirely in batch mode defaults each text to an empty results list (text returned unchanged), matching the existing single-text default-empty behavior.

I went with looping directly over the engines in app.py (rather than reusing BatchAnonymizerEngine.anonymize_list/BatchDeanonymizeEngine.deanonymize_list) because those methods return only the anonymized text string, dropping items — which would make the batch response shape inconsistent with the single-text response. Looping directly preserves full response parity between single and batch modes.

Testing

Added presidio-anonymizer/tests/test_app.py (no HTTP-level test file existed for this service before) using Flask's test client, covering:

  • Single-text behavior is unchanged
  • Batch anonymize returns one result per text
  • Batch anonymize with missing analyzer_results defaults correctly
  • Batch anonymize with mismatched lengths returns 422
  • Batch deanonymize, including a full encrypt → decrypt round trip
  • Batch deanonymize length-mismatch validation

Full existing suite: 282 passed, 0 regressions. ruff check clean.

Docs

Updated docs/api-docs/api-docs.yml (request/response schemas + a batch example) for both endpoints, mirroring exactly how /analyze's existing batch support is already documented there. Validated with openapi-spec-validator.

presidio-analyzer's /analyze endpoint already accepts a list of texts
and returns a matching list of results. presidio-anonymizer's
/anonymize and /deanonymize never got the same treatment, even though
the core package already ships BatchAnonymizerEngine and
BatchDeanonymizeEngine unused by the HTTP layer.

Extend both endpoints so 'text' can be a string (existing behavior,
unchanged) or an array of strings. In array mode, 'analyzer_results'
/ 'anonymizer_results' must be an array of the same length, one list
of results per text, and the response becomes a matching array of
results. A length mismatch raises a 422 with a clear message instead
of failing silently or misaligning results.

Adds tests/test_app.py (no HTTP-level test file existed for this
service before), covering single-text behavior is unchanged, batch
anonymize/deanonymize including a full encrypt/decrypt round trip,
missing-results defaulting, and length-mismatch validation.

Updates docs/api-docs/api-docs.yml (request/response schemas +
batch examples) to match how /analyze's existing batch support is
already documented there.

Closes data-privacy-stack#1045
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please add batching support on HTTP APIs

1 participant