From 0b37cb35d087807240286e7d19170d9b72ba8d85 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 10:26:04 -0500 Subject: [PATCH 01/11] .gitignore: Add from gitignore.io - Local ignores for Perl --- Perl/.gitignore | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Perl/.gitignore diff --git a/Perl/.gitignore b/Perl/.gitignore new file mode 100644 index 00000000..80850866 --- /dev/null +++ b/Perl/.gitignore @@ -0,0 +1,44 @@ +# Created by https://www.toptal.com/developers/gitignore/api/perl +# Edit at https://www.toptal.com/developers/gitignore?templates=perl + +### Perl ### +!Build/ +.last_cover_stats +/META.yml +/META.json +/MYMETA.* +*.o +*.pm.tdy +*.bs + +# Devel::Cover +cover_db/ + +# Devel::NYTProf +nytprof.out + +# Dist::Zilla +/.build/ + +# Module::Build +_build/ +Build +Build.bat + +# Module::Install +inc/ + +# ExtUtils::MakeMaker +/blib/ +/_eumm/ +/*.gz +/Makefile +/Makefile.old +/MANIFEST.bak +/pm_to_blib +/*.zip + +# Carton +local/ + +# End of https://www.toptal.com/developers/gitignore/api/perl \ No newline at end of file From bca604286ed6f8ff45508d0a623435f45615cb01 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 10:27:27 -0500 Subject: [PATCH 02/11] Add AGENTS.md detailing repository guidelines and best practices - Define project structure, coding conventions, and testing process. - Include setup, development, and sample execution instructions. - Provide commit and PR guidelines, as well as security best practices. --- Perl/AGENTS.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Perl/AGENTS.md diff --git a/Perl/AGENTS.md b/Perl/AGENTS.md new file mode 100644 index 00000000..6dc5b0ae --- /dev/null +++ b/Perl/AGENTS.md @@ -0,0 +1,90 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `Endpoint Examples/JSON Payload/`: Two-step samples (upload then operate), e.g., `markdown.pl`. +- `Endpoint Examples/Multipart Payload/`: Single multipart request samples, e.g., `rasterized-pdf.pl`. +- `Complex Flow Examples/`: Multi-step workflows that chain endpoints. +- `.env.example` → copy to `.env` and set `PDFREST_API_KEY`; optional `PDFREST_URL`. +- `README.md`: Setup and usage details for this language folder. + +## Build, Test, and Development Commands +- Install deps from `cpanfile` (recommended): + - `cpanm --installdeps .` +- macOS quick setup: `make install-macos` or run `scripts/setup-macos.sh` +- Run JSON sample: + - `perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf` +- Run Multipart sample: + - `perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf` +- Capture output to file: append `> response.json` + +## Coding Style & Naming Conventions +- Indentation: 4 spaces; enable `use strict; use warnings; use utf8;` at top. +- Naming: `snake_case` for files/variables; script names mirror endpoints (e.g., `markdown.pl`). +- HTTP: prefer `LWP::UserAgent` + `HTTP::Request::Common`. + - Base URL: `$ENV{PDFREST_URL} // 'https://api.pdfrest.com'`. +- I/O: print API responses to STDOUT; send diagnostics to STDERR; exit non‑2xx with non‑zero status. + +## Testing Guidelines +- No formal test suite required for samples. Validate by running against small, known inputs. +- Success: non‑zero exit on failures; JSON body printed to STDOUT on success. +- If adding tests, use `Test::More` under `t/` and run with `prove -lr t`. + +## Commit & Pull Request Guidelines +- Commits: imperative, scoped, and reference endpoint/path (e.g., "Add multipart markdown sample"). +- PRs: include what/why, run commands used for verification, expected response snippet, and linked issues. +- Avoid unrelated changes or large binaries. + +## Security & Configuration Tips +- Do not commit secrets. Provide `.env.example`; load `PDFREST_API_KEY` from environment. +- Optional region override: `PDFREST_URL=https://eu-api.pdfrest.com/` for EU/GDPR routing. +- Never print API keys; rely on concise error messages. Respect proxies via `HTTPS_PROXY` when needed. + +## Troubleshooting +- HTTPS support missing: install `LWP::Protocol::https` and `Mozilla::CA` (included in `cpanfile`). Re-run `cpanm --installdeps .`. +- SSL toolchain: some systems require OpenSSL dev libs (e.g., macOS: `brew install openssl`, Debian/Ubuntu: `apt-get install libssl-dev`) before `cpanm` can build `Net::SSLeay`/`IO::Socket::SSL`. + +--- + +## Audience And Tone (Internal) + +These Perl samples are customer‑facing and intended to help potential customers evaluate pdfRest quickly. Keep all code, comments, and documentation clear, minimal, and task‑focused. Avoid internal jargon and keep meta‑process notes out of `README.md` and the samples. + +Key points: +- Clarity: explain what the sample does in 1–2 bullets. +- Guidance: show how to set up `.env` and how to run the script. +- Region: mention optional `PDFREST_URL` with the EU endpoint for GDPR and proximity. +- Safety: never log secrets; print only response bodies and minimal diagnostics to `STDERR`. +- Errors: exit non‑zero on non‑2xx responses with a concise message. + +## Sample Header Convention (Internal) + +Add this standardized header comment at the top of every Perl sample. This header is customer‑visible; the convention itself is tracked here for us (don’t place this template in `README.md`). + +Template: + +``` +#! +# What this sample does: +# - +# +# Setup (.env): +# - Copy .env.example to .env +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com +# +# Usage: +# perl "" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json +``` + +Notes: +- Match the endpoint name and request style (JSON two‑step vs multipart single request) in the bullets. +- Keep the header concise; list optional parameters near where they are used in code. + +## README Scope (Internal) + +Keep `README.md` focused on user setup, running samples, and high‑level background. Avoid internal conventions or meta‑process content that could confuse customers. Place internal notes and templates in `AGENTS.md` (this file). From d3ebe1f8d5f46153fa9b755f8524f47190aa29d6 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 13:58:39 -0500 Subject: [PATCH 03/11] Add Perl examples for pdfRest API integration - Added JSON and Multipart payload examples for generating Markdown and rasterized PDFs. - Introduced a "Complex Flow" Perl script showcasing file conversion and merging. - Included `.env.example` for API key configuration and optional EU endpoint setup. - Updated `README.md` with instructions for setup, dependencies, and running samples. - Added `cpanfile` for dependency management and setup script for macOS. --- Perl/.env.example | 3 + .../merge-different-file-types.pl | 160 ++++++++++++++++++ .../JSON Payload/markdown.pl | 116 +++++++++++++ .../JSON Payload/rasterized-pdf.pl | 114 +++++++++++++ .../Multipart Payload/markdown.pl | 91 ++++++++++ .../Multipart Payload/rasterized-pdf.pl | 90 ++++++++++ Perl/README.md | 53 ++++++ Perl/cpanfile | 10 ++ Perl/scripts/setup-macos.sh | 33 ++++ 9 files changed, 670 insertions(+) create mode 100644 Perl/.env.example create mode 100644 Perl/Complex Flow Examples/merge-different-file-types.pl create mode 100644 Perl/Endpoint Examples/JSON Payload/markdown.pl create mode 100644 Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl create mode 100644 Perl/Endpoint Examples/Multipart Payload/markdown.pl create mode 100644 Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl create mode 100644 Perl/README.md create mode 100644 Perl/cpanfile create mode 100755 Perl/scripts/setup-macos.sh diff --git a/Perl/.env.example b/Perl/.env.example new file mode 100644 index 00000000..acf0e792 --- /dev/null +++ b/Perl/.env.example @@ -0,0 +1,3 @@ +PDFREST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# Optional: Override API base URL (default https://api.pdfrest.com) +# PDFREST_URL=https://eu-api.pdfrest.com/ \ No newline at end of file diff --git a/Perl/Complex Flow Examples/merge-different-file-types.pl b/Perl/Complex Flow Examples/merge-different-file-types.pl new file mode 100644 index 00000000..c04f9486 --- /dev/null +++ b/Perl/Complex Flow Examples/merge-different-file-types.pl @@ -0,0 +1,160 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(decode_json); +use LWP::UserAgent; +use HTTP::Request; +use HTTP::Request::Common qw(POST); +use URI::Escape qw(uri_escape); + +# Tutorial: Merge different file types into one PDF (Complex Flow) +# +# What this does +# - For each input path: +# - If NOT a PDF: convert to PDF via /pdf and capture outputId. +# - If a PDF: upload to /upload and capture the returned id. +# - Pass all collected IDs to /merged-pdf with matching arrays for id[], pages[]=1-last, and type[]=id. +# +# Why this flow? +# - Demonstrates how to chain endpoints for a real workflow (convert mixed types, then merge). +# +# Setup +# - Put PDFREST_API_KEY in .env at the Perl folder root +# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) +# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ +# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage +# - perl "Complex Flow Examples/merge-different-file-types.pl" file1.png file2.pptx file3.pdf + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../.env"; # one level up from Complex Flow Examples +if (-f $env_path) { + open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; + while (my $line = <$env_fh>) { + chomp $line; + next if $line =~ /^\s*#/; + next if $line !~ /\S/; + if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { + my ($k, $v) = ($1, $2); + $v =~ s/^['"]|['"]$//g; + $ENV{$k} = $v if !exists $ENV{$k}; + } + } + close $env_fh; +} + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my @paths = @ARGV; +if (@paths < 2) { + print STDERR "Usage: perl merge-different-file-types.pl /path/to/file1 /path/to/file2 [/path/to/file3 ...]\n"; + exit 1; +} +for my $p (@paths) { if (!-f $p) { print STDERR "Not a file: $p\n"; exit 1; } } + +sub content_type_for { + my ($path) = @_; + my ($ext) = $path =~ /(\.[^.]+)$/; + $ext = lc($ext // ''); + return 'application/pdf' if $ext eq '.pdf'; + return 'image/png' if $ext eq '.png'; + return 'image/jpeg' if $ext eq '.jpg' || $ext eq '.jpeg'; + return 'image/gif' if $ext eq '.gif'; + return 'image/tiff' if $ext eq '.tif' || $ext eq '.tiff'; + return 'image/bmp' if $ext eq '.bmp'; + return 'image/webp' if $ext eq '.webp'; + return 'application/msword' if $ext eq '.doc'; + return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' if $ext eq '.docx'; + return 'application/vnd.ms-powerpoint' if $ext eq '.ppt'; + return 'application/vnd.openxmlformats-officedocument.presentationml.presentation' if $ext eq '.pptx'; + return 'application/vnd.ms-excel' if $ext eq '.xls'; + return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' if $ext eq '.xlsx'; + return 'text/plain' if $ext eq '.txt'; + return 'application/rtf' if $ext eq '.rtf'; + return 'text/html' if $ext eq '.html' || $ext eq '.htm'; + return 'application/octet-stream'; +} + +my $ua = LWP::UserAgent->new( timeout => 120 ); + +eval { + my @ids; + for my $i (0..$#paths) { + my $p = $paths[$i]; + my $ext = lc(($p =~ /(\.[^.]+)$/)[0] // ''); + if ($ext eq '.pdf') { + # Upload and capture id + open my $fh, '<:raw', $p or do { print STDERR "Unable to read $p: $!\n"; exit 1; }; + my $bytes; { local $/; $bytes = <$fh>; } + close $fh; + my $req = HTTP::Request->new('POST', "$api_base/upload"); + $req->header('api-key' => $api_key); + $req->header('content-filename' => basename($p)); + $req->header('Content-Type' => 'application/octet-stream'); + $req->content($bytes); + my $resp = $ua->request($req); + print STDERR $resp->decoded_content // ''; + if (!$resp->is_success) { print STDERR "\nUpload failed (input #" . ($i+1) . ") status " . $resp->code . "\n"; exit 1; } + my $json = decode_json($resp->decoded_content // '{}'); + my $id = $json->{files} && ref $json->{files} eq 'ARRAY' ? $json->{files}[0]{id} : undef; + if (!$id) { print STDERR "Unexpected upload response format for input #" . ($i+1) . "\n"; exit 1; } + push @ids, $id; + print STDERR "Uploaded PDF (#" . ($i+1) . "); id=$id\n"; + } else { + # Convert to PDF via /pdf and capture outputId + my $ct = content_type_for($p); + my $req = POST("$api_base/pdf", + 'Content_Type' => 'form-data', + 'Content' => [ file => [$p, basename($p), 'Content-Type' => $ct] ] + ); + $req->header('api-key' => $api_key); + my $resp = $ua->request($req); + print STDERR $resp->decoded_content // ''; + if (!$resp->is_success) { print STDERR "\nConversion failed (input #" . ($i+1) . ") status " . $resp->code . "\n"; exit 1; } + my $json = decode_json($resp->decoded_content // '{}'); + my $id = $json->{outputId}; + if (!$id) { print STDERR "Unexpected conversion response format for input #" . ($i+1) . "\n"; exit 1; } + push @ids, $id; + print STDERR "Converted non-PDF (#" . ($i+1) . "); outputId=$id\n"; + } + } + + # Build x-www-form-urlencoded with repeated arrays + my @parts; + for my $id (@ids) { + push @parts, 'id[]=' . uri_escape($id); + push @parts, 'pages[]=' . uri_escape('1-last'); + push @parts, 'type[]=id'; + } + my $body = join('&', @parts); + + my $merge_req = HTTP::Request->new('POST', "$api_base/merged-pdf"); + $merge_req->header('api-key' => $api_key); + $merge_req->header('Content-Type' => 'application/x-www-form-urlencoded'); + $merge_req->content($body); + my $merge_resp = $ua->request($merge_req); + print STDOUT $merge_resp->decoded_content // ''; + if (!$merge_resp->is_success) { print STDERR "\nMerge failed with status " . $merge_resp->code . "\n"; exit 1; } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/JSON Payload/markdown.pl b/Perl/Endpoint Examples/JSON Payload/markdown.pl new file mode 100644 index 00000000..ea42f6fa --- /dev/null +++ b/Perl/Endpoint Examples/JSON Payload/markdown.pl @@ -0,0 +1,116 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(encode_json decode_json); +use LWP::UserAgent; +use HTTP::Request; +use HTTP::Request::Common qw(POST); +use Encode qw(encode); + +# Tutorial: Convert a PDF to Markdown using the JSON-payload style +# +# What this does +# - Step 1: Upload the input PDF to /upload and capture the returned file id. +# - Step 2: Call /markdown with a JSON body that references that id. +# +# Setup +# - Create .env at the Perl folder root with: +# PDFREST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# # Optional EU endpoint (GDPR/compliance & proximity) +# # PDFREST_URL=https://eu-api.pdfrest.com/ +# +# Usage +# perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root (two levels up from this script) +my $env_path = "$Bin/../../.env"; +if (-f $env_path) { + open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; + while (my $line = <$env_fh>) { + chomp $line; + next if $line =~ /^\s*#/; + next if $line !~ /\S/; + if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { + my ($k, $v) = ($1, $2); + $v =~ s/^['"]|['"]$//g; # strip surrounding quotes + $ENV{$k} = $v if !exists $ENV{$k}; + } + } + close $env_fh; +} + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; # trim trailing slashes + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl markdown.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +open my $fh, '<:raw', $pdf_path or do { print STDERR "Unable to read $pdf_path: $!\n"; exit 1; }; +my $file_bytes; { local $/; $file_bytes = <$fh>; } +close $fh; + +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + # Step 1: Upload the file to receive a reusable id + my $upload_req = HTTP::Request->new('POST', "$api_base/upload"); + $upload_req->header('api-key' => $api_key); + $upload_req->header('content-filename' => $filename); + $upload_req->header('Content-Type' => 'application/octet-stream'); + $upload_req->content($file_bytes); + + my $upload_resp = $ua->request($upload_req); + print STDERR $upload_resp->decoded_content // ''; + if (!$upload_resp->is_success) { + print STDERR "\nUpload failed with status " . $upload_resp->code . "\n"; + exit 1; + } + + my $upload_json = decode_json($upload_resp->decoded_content // '{}'); + my $uploaded_id = $upload_json->{files} && ref $upload_json->{files} eq 'ARRAY' + ? $upload_json->{files}[0]{id} + : undef; + if (!$uploaded_id) { + print STDERR "Unexpected response format: missing files[0].id\n"; + exit 1; + } + print STDERR "Successfully uploaded with an id of: $uploaded_id\n"; + + # Step 2: Request Markdown output using the uploaded id + my $markdown_body = encode_json({ id => $uploaded_id, page_break_comments => 'on' }); + my $markdown_req = HTTP::Request->new('POST', "$api_base/markdown"); + $markdown_req->header('api-key' => $api_key); + $markdown_req->header('Content-Type' => 'application/json'); + $markdown_req->content($markdown_body); + + my $markdown_resp = $ua->request($markdown_req); + print STDOUT $markdown_resp->decoded_content // ''; + if (!$markdown_resp->is_success) { + print STDERR "\nMarkdown conversion failed with status " . $markdown_resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl new file mode 100644 index 00000000..7ecb0b97 --- /dev/null +++ b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl @@ -0,0 +1,114 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use JSON::PP qw(encode_json decode_json); +use LWP::UserAgent; +use HTTP::Request; + +# Tutorial: Rasterize a PDF using the JSON-payload style +# +# What this does +# - Step 1: Upload the input PDF to /upload and capture the returned file id. +# - Step 2: Call /rasterized-pdf with a JSON body that references that id. +# +# Why JSON style? +# - Useful when you plan to reuse an uploaded file across multiple operations. +# +# Setup +# - Put PDFREST_API_KEY in .env at the Perl folder root +# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) +# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ +# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage +# - perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" /path/to/input.pdf + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +if (-f $env_path) { + open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; + while (my $line = <$env_fh>) { + chomp $line; + next if $line =~ /^\s*#/; + next if $line !~ /\S/; + if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { + my ($k, $v) = ($1, $2); + $v =~ s/^['"]|['"]$//g; + $ENV{$k} = $v if !exists $ENV{$k}; + } + } + close $env_fh; +} + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl rasterized-pdf.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +open my $fh, '<:raw', $pdf_path or do { print STDERR "Unable to read $pdf_path: $!\n"; exit 1; }; +my $file_bytes; { local $/; $file_bytes = <$fh>; } +close $fh; + +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + # 1) Upload the PDF + my $upload_req = HTTP::Request->new('POST', "$api_base/upload"); + $upload_req->header('api-key' => $api_key); + $upload_req->header('content-filename' => $filename); + $upload_req->header('Content-Type' => 'application/octet-stream'); + $upload_req->content($file_bytes); + my $upload_resp = $ua->request($upload_req); + print STDERR $upload_resp->decoded_content // ''; + if (!$upload_resp->is_success) { + print STDERR "\nUpload failed with status " . $upload_resp->code . "\n"; + exit 1; + } + my $upload_json = decode_json($upload_resp->decoded_content // '{}'); + my $uploaded_id = $upload_json->{files} && ref $upload_json->{files} eq 'ARRAY' + ? $upload_json->{files}[0]{id} + : undef; + if (!$uploaded_id) { + print STDERR "Unexpected response format: missing files[0].id\n"; + exit 1; + } + print STDERR "Successfully uploaded with an id of: $uploaded_id\n"; + + # 2) Call /rasterized-pdf with JSON body + my $body = encode_json({ id => $uploaded_id }); + my $ras_req = HTTP::Request->new('POST', "$api_base/rasterized-pdf"); + $ras_req->header('api-key' => $api_key); + $ras_req->header('Content-Type' => 'application/json'); + $ras_req->content($body); + my $ras_resp = $ua->request($ras_req); + print STDOUT $ras_resp->decoded_content // ''; + if (!$ras_resp->is_success) { + print STDERR "\nRasterization failed with status " . $ras_resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/Multipart Payload/markdown.pl b/Perl/Endpoint Examples/Multipart Payload/markdown.pl new file mode 100644 index 00000000..584482ed --- /dev/null +++ b/Perl/Endpoint Examples/Multipart Payload/markdown.pl @@ -0,0 +1,91 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use LWP::UserAgent; +use HTTP::Request::Common qw(POST); + +# Tutorial: Convert a PDF to Markdown using the Multipart style +# +# What this does +# - Sends the input file and options in a single multipart/form-data request to /markdown. +# +# Why Multipart style? +# - Simpler for one-off operations (no separate upload step). Re-uploads the file each time. +# +# Setup +# - Put PDFREST_API_KEY in .env at the Perl folder root +# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) +# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ +# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage +# - perl "Endpoint Examples/Multipart Payload/markdown.pl" /path/to/input.pdf + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +if (-f $env_path) { + open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; + while (my $line = <$env_fh>) { + chomp $line; + next if $line =~ /^\s*#/; + next if $line !~ /\S/; + if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { + my ($k, $v) = ($1, $2); + $v =~ s/^['"]|['"]$//g; + $ENV{$k} = $v if !exists $ENV{$k}; + } + } + close $env_fh; +} + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl markdown.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + my $req = POST("$api_base/markdown", + 'Content_Type' => 'form-data', + 'Content' => [ + file => [$pdf_path, $filename, 'Content-Type' => 'application/pdf'], + output => 'pdfrest_markdown', + page_break_comments => 'on', + # Optional: page_range => '1-3', + ] + ); + $req->header('api-key' => $api_key); + + my $resp = $ua->request($req); + print STDOUT $resp->decoded_content // ''; + if (!$resp->is_success) { + print STDERR "\nMarkdown conversion failed with status " . $resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl new file mode 100644 index 00000000..edb02af3 --- /dev/null +++ b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl @@ -0,0 +1,90 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use utf8; +use FindBin qw($Bin); +use File::Basename qw(basename); +use LWP::UserAgent; +use HTTP::Request::Common qw(POST); + +# Tutorial: Rasterize a PDF using the Multipart style +# +# What this does +# - Sends the input PDF and options in a single multipart/form-data request to /rasterized-pdf. +# +# Why Multipart style? +# - Simpler for one-off operations (no separate upload step). Re-uploads the file each time. +# +# Setup +# - Put PDFREST_API_KEY in .env at the Perl folder root +# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) +# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ +# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +# +# Usage +# - perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf + +binmode STDOUT, ':raw'; +binmode STDERR, ':encoding(UTF-8)'; + +# Load .env from the Perl folder root +my $env_path = "$Bin/../../.env"; +if (-f $env_path) { + open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; + while (my $line = <$env_fh>) { + chomp $line; + next if $line =~ /^\s*#/; + next if $line !~ /\S/; + if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { + my ($k, $v) = ($1, $2); + $v =~ s/^['"]|['"]$//g; + $ENV{$k} = $v if !exists $ENV{$k}; + } + } + close $env_fh; +} + +my $api_key = $ENV{PDFREST_API_KEY} // ''; +if (!$api_key || $api_key =~ /^\s*$/) { + print STDERR "Missing PDFREST_API_KEY in .env or environment\n"; + exit 1; +} + +my $api_base = $ENV{PDFREST_URL} // $ENV{PDFREST_API} // 'https://api.pdfrest.com'; +$api_base =~ s{/+$}{}; + +my $pdf_path = shift @ARGV; +if (!$pdf_path || !-f $pdf_path) { + print STDERR "Usage: perl rasterized-pdf.pl /path/to/file.pdf\n"; + exit 1; +} + +my $filename = basename($pdf_path); +my $ua = LWP::UserAgent->new( timeout => 60 ); + +eval { + my $req = POST("$api_base/rasterized-pdf", + 'Content_Type' => 'form-data', + 'Content' => [ + file => [$pdf_path, $filename, 'Content-Type' => 'application/pdf'], + output => 'pdfrest_rasterize', + # Optional: dpi => '300', color_space => 'rgb', page_range => '1-3', + ] + ); + $req->header('api-key' => $api_key); + + my $resp = $ua->request($req); + print STDOUT $resp->decoded_content // ''; + if (!$resp->is_success) { + print STDERR "\nRasterization failed with status " . $resp->code . "\n"; + exit 1; + } + 1; +} or do { + my $err = $@ || 'Unknown error'; + $err =~ s/\s+$//; + print STDERR "Error: $err\n"; + exit 1; +}; + +__END__ diff --git a/Perl/README.md b/Perl/README.md new file mode 100644 index 00000000..2a3dffc7 --- /dev/null +++ b/Perl/README.md @@ -0,0 +1,53 @@ +# pdfRest Perl Samples + +A set of Perl scripts that demonstrate how to call the pdfRest API. Samples are organized by request style and include a multi‑step “Complex Flow” example. + +- JSON Payload: upload first, then call the endpoint by `id`. +- Multipart Payload: send the file and options in a single request. + +## Prerequisites +- Perl 5.26+ on macOS/Linux/WSL. +- A pdfRest API key (get one at https://pdfrest.com/getstarted/). +- cpanm (cpanminus) to install dependencies. + +### Install cpanm +- macOS (Homebrew): `brew install cpanminus` +- Debian/Ubuntu: `sudo apt-get install cpanminus` +- CPAN: `perl -MCPAN -e 'install App::cpanminus'` +- Curl (alternative): `curl -L https://cpanmin.us | perl - --sudo App::cpanminus` + +## Setup +1) Copy environment template and set your key +- `cp .env.example .env` +- Edit `.env` and set `PDFREST_API_KEY=your_api_key_here` +- Optional EU endpoint for GDPR/proximity: `PDFREST_URL=https://eu-api.pdfrest.com/` + +2) Install dependencies from `cpanfile` +- Standard: `cpanm --installdeps .` +- macOS (Homebrew OpenSSL + HTTPS stack): `make install-macos` or `scripts/setup-macos.sh` + - This installs `openssl@3` and builds `Net::SSLeay`, `IO::Socket::SSL`, etc. + +## EU/GDPR Endpoint +- Default base URL is `https://api.pdfrest.com` (US). +- For GDPR compliance and improved performance in Europe, set in `.env`: + - `PDFREST_URL=https://eu-api.pdfrest.com/` +- If `PDFREST_URL` is not set, the default US endpoint is used. +- More information: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +## Run the Samples +- JSON Markdown: `perl "Endpoint Examples/JSON Payload/markdown.pl" input.pdf` +- JSON Rasterize: `perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" input.pdf` +- Multipart Markdown: `perl "Endpoint Examples/Multipart Payload/markdown.pl" input.pdf` +- Multipart Rasterize: `perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" input.pdf` +- Complex Flow Merge: `perl "Complex Flow Examples/merge-different-file-types.pl" file1.png file2.pptx file3.pdf` +- Save output: append `> response.json` + +## Troubleshooting +- HTTPS modules missing: `cpanm --installdeps .` (includes `LWP::Protocol::https`, `IO::Socket::SSL`, `Mozilla::CA`). +- Net::SSLeay fails to build: install OpenSSL dev tools. + - macOS: `xcode-select --install && brew install openssl@3 pkg-config` then `make install-macos`. + - Debian/Ubuntu: `sudo apt-get install -y build-essential libssl-dev pkg-config` then `cpanm --reinstall Net::SSLeay IO::Socket::SSL`. +- Verify TLS: `perl -MIO::Socket::SSL -e 'print $IO::Socket::SSL::VERSION, qq(\n)'` and `perl -MLWP::Protocol::https -e 'print qq(https OK\n)'`. + +Notes +- Scripts read `.env` from the Perl folder root and print API responses to stdout; diagnostics go to stderr and non‑zero exit on errors. diff --git a/Perl/cpanfile b/Perl/cpanfile new file mode 100644 index 00000000..734f6880 --- /dev/null +++ b/Perl/cpanfile @@ -0,0 +1,10 @@ +requires 'LWP::UserAgent'; +requires 'HTTP::Request::Common'; +requires 'JSON::PP'; +requires 'Try::Tiny'; +requires 'LWP::Protocol::https'; +# Recommended for certificate bundle +requires 'Mozilla::CA'; +requires 'IO::Socket::SSL'; +requires 'Net::SSLeay'; +requires 'URI'; diff --git a/Perl/scripts/setup-macos.sh b/Perl/scripts/setup-macos.sh new file mode 100755 index 00000000..b0599496 --- /dev/null +++ b/Perl/scripts/setup-macos.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Installing prerequisites (Xcode tools, Homebrew OpenSSL, pkg-config)..." +if ! xcode-select -p >/dev/null 2>&1; then + xcode-select --install || true +fi + +if ! command -v brew >/dev/null 2>&1; then + echo "Homebrew is required. Install from https://brew.sh and re-run." >&2 + exit 1 +fi + +brew install openssl@3 pkg-config || true + +OPENSSL_PREFIX="$(brew --prefix openssl@3)" +export PKG_CONFIG_PATH="$OPENSSL_PREFIX/lib/pkgconfig" +export CPATH="$OPENSSL_PREFIX/include" +export LIBRARY_PATH="$OPENSSL_PREFIX/lib" + +echo "Building Perl SSL modules against OpenSSL at $OPENSSL_PREFIX..." +cpanm --verbose --notest --reinstall --configure-args="--openssl-prefix=$OPENSSL_PREFIX" Net::SSLeay +cpanm IO::Socket::SSL LWP::Protocol::https Mozilla::CA + +echo "Installing application dependencies from cpanfile..." +cpanm --installdeps . + +echo "Verifying HTTPS support..." +perl -MIO::Socket::SSL -e 'print $IO::Socket::SSL::VERSION, qq(\n)' +perl -MLWP::Protocol::https -e 'print qq(https OK\n)' + +echo "Done. You can now run:" +echo " perl \"Endpoint Examples/JSON Payload/markdown.pl\" /path/to/input.pdf" From 244de353bc394f98ce6357b95d9eb7271c7e0ba0 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 14:14:32 -0500 Subject: [PATCH 04/11] Standardize Perl example headers and comments - Updated all Perl examples to include consistent headers explaining functionality, setup, usage, and output. - Simplified and clarified setup instructions for API key and optional EU endpoint configuration. - Improved usage guidance with tips for handling output and non-2xx responses. --- .../merge-different-file-types.pl | 30 +++++++++---------- .../JSON Payload/markdown.pl | 25 +++++++++------- .../JSON Payload/rasterized-pdf.pl | 28 ++++++++--------- .../Multipart Payload/markdown.pl | 27 +++++++++-------- .../Multipart Payload/rasterized-pdf.pl | 27 +++++++++-------- 5 files changed, 70 insertions(+), 67 deletions(-) diff --git a/Perl/Complex Flow Examples/merge-different-file-types.pl b/Perl/Complex Flow Examples/merge-different-file-types.pl index c04f9486..a7db76c3 100644 --- a/Perl/Complex Flow Examples/merge-different-file-types.pl +++ b/Perl/Complex Flow Examples/merge-different-file-types.pl @@ -10,25 +10,23 @@ use HTTP::Request::Common qw(POST); use URI::Escape qw(uri_escape); -# Tutorial: Merge different file types into one PDF (Complex Flow) +#! +# What this sample does: +# - Merges multiple inputs (PDFs and non-PDFs) into a single PDF. +# - Non-PDFs are converted to PDF; PDFs are uploaded. Collected IDs are merged via /merged-pdf. # -# What this does -# - For each input path: -# - If NOT a PDF: convert to PDF via /pdf and capture outputId. -# - If a PDF: upload to /upload and capture the returned id. -# - Pass all collected IDs to /merged-pdf with matching arrays for id[], pages[]=1-last, and type[]=id. +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com # -# Why this flow? -# - Demonstrates how to chain endpoints for a real workflow (convert mixed types, then merge). +# Usage: +# perl "Complex Flow Examples/merge-different-file-types.pl" /path/to/file1 /path/to/file2 [/path/to/file3 ...] # -# Setup -# - Put PDFREST_API_KEY in .env at the Perl folder root -# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) -# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ -# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work -# -# Usage -# - perl "Complex Flow Examples/merge-different-file-types.pl" file1.png file2.pptx file3.pdf +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; diff --git a/Perl/Endpoint Examples/JSON Payload/markdown.pl b/Perl/Endpoint Examples/JSON Payload/markdown.pl index ea42f6fa..d6a5221b 100644 --- a/Perl/Endpoint Examples/JSON Payload/markdown.pl +++ b/Perl/Endpoint Examples/JSON Payload/markdown.pl @@ -10,20 +10,23 @@ use HTTP::Request::Common qw(POST); use Encode qw(encode); -# Tutorial: Convert a PDF to Markdown using the JSON-payload style +#! +# What this sample does: +# - Converts a PDF to Markdown using pdfRest. +# - Uses a JSON payload in two steps: upload to /upload, then call /markdown with the returned id. # -# What this does -# - Step 1: Upload the input PDF to /upload and capture the returned file id. -# - Step 2: Call /markdown with a JSON body that references that id. +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com # -# Setup -# - Create .env at the Perl folder root with: -# PDFREST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -# # Optional EU endpoint (GDPR/compliance & proximity) -# # PDFREST_URL=https://eu-api.pdfrest.com/ -# -# Usage +# Usage: # perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf +# +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; diff --git a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl index 7ecb0b97..04b7e438 100644 --- a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl @@ -8,23 +8,23 @@ use LWP::UserAgent; use HTTP::Request; -# Tutorial: Rasterize a PDF using the JSON-payload style +#! +# What this sample does: +# - Creates a rasterized version of a PDF using pdfRest. +# - Uses a JSON payload in two steps: upload to /upload, then call /rasterized-pdf with the returned id. # -# What this does -# - Step 1: Upload the input PDF to /upload and capture the returned file id. -# - Step 2: Call /rasterized-pdf with a JSON body that references that id. +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com # -# Why JSON style? -# - Useful when you plan to reuse an uploaded file across multiple operations. +# Usage: +# perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" /path/to/input.pdf # -# Setup -# - Put PDFREST_API_KEY in .env at the Perl folder root -# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) -# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ -# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work -# -# Usage -# - perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" /path/to/input.pdf +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; diff --git a/Perl/Endpoint Examples/Multipart Payload/markdown.pl b/Perl/Endpoint Examples/Multipart Payload/markdown.pl index 584482ed..b95c37d1 100644 --- a/Perl/Endpoint Examples/Multipart Payload/markdown.pl +++ b/Perl/Endpoint Examples/Multipart Payload/markdown.pl @@ -7,22 +7,23 @@ use LWP::UserAgent; use HTTP::Request::Common qw(POST); -# Tutorial: Convert a PDF to Markdown using the Multipart style +#! +# What this sample does: +# - Converts a PDF to Markdown using pdfRest. +# - Sends a single multipart/form-data request directly to /markdown with the file. # -# What this does -# - Sends the input file and options in a single multipart/form-data request to /markdown. +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com # -# Why Multipart style? -# - Simpler for one-off operations (no separate upload step). Re-uploads the file each time. +# Usage: +# perl "Endpoint Examples/Multipart Payload/markdown.pl" /path/to/input.pdf # -# Setup -# - Put PDFREST_API_KEY in .env at the Perl folder root -# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) -# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ -# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work -# -# Usage -# - perl "Endpoint Examples/Multipart Payload/markdown.pl" /path/to/input.pdf +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; diff --git a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl index edb02af3..94040f2a 100644 --- a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl @@ -7,22 +7,23 @@ use LWP::UserAgent; use HTTP::Request::Common qw(POST); -# Tutorial: Rasterize a PDF using the Multipart style +#! +# What this sample does: +# - Creates a rasterized version of a PDF using pdfRest. +# - Sends a single multipart/form-data request directly to /rasterized-pdf with the file. # -# What this does -# - Sends the input PDF and options in a single multipart/form-data request to /rasterized-pdf. +# Setup (.env): +# - Copy .env.example to .env (Perl folder root) +# - Set PDFREST_API_KEY=your_api_key_here +# - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +# PDFREST_URL=https://eu-api.pdfrest.com # -# Why Multipart style? -# - Simpler for one-off operations (no separate upload step). Re-uploads the file each time. +# Usage: +# perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf # -# Setup -# - Put PDFREST_API_KEY in .env at the Perl folder root -# - Optionally set PDFREST_URL (defaults to https://api.pdfrest.com) -# - EU/GDPR routing and proximity: https://eu-api.pdfrest.com/ -# More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work -# -# Usage -# - perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf +# Output: +# - Prints the API JSON response to stdout. Non-2xx responses exit with a concise message. +# - Tip: pipe output to a file: perl ... > response.json binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; From 79bc23f5646d8cc95f03c3d43db24965ccf97f01 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 17:26:43 -0500 Subject: [PATCH 05/11] Add GDPR API call information links to Perl examples and `.env.example` - Added URL for GDPR compliance details across Perl examples, `AGENTS.md`, and `.env.example`. --- Perl/.env.example | 3 ++- Perl/AGENTS.md | 2 ++ Perl/Complex Flow Examples/merge-different-file-types.pl | 1 + Perl/Endpoint Examples/JSON Payload/markdown.pl | 1 + Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl | 1 + Perl/Endpoint Examples/Multipart Payload/markdown.pl | 1 + Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl | 1 + 7 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Perl/.env.example b/Perl/.env.example index acf0e792..82c65d4c 100644 --- a/Perl/.env.example +++ b/Perl/.env.example @@ -1,3 +1,4 @@ PDFREST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # Optional: Override API base URL (default https://api.pdfrest.com) -# PDFREST_URL=https://eu-api.pdfrest.com/ \ No newline at end of file +# PDFREST_URL=https://eu-api.pdfrest.com/ +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work diff --git a/Perl/AGENTS.md b/Perl/AGENTS.md index 6dc5b0ae..fecdb16c 100644 --- a/Perl/AGENTS.md +++ b/Perl/AGENTS.md @@ -17,6 +17,7 @@ - `perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf` - Capture output to file: append `> response.json` + ## Coding Style & Naming Conventions - Indentation: 4 spaces; enable `use strict; use warnings; use utf8;` at top. - Naming: `snake_case` for files/variables; script names mirror endpoints (e.g., `markdown.pl`). @@ -72,6 +73,7 @@ Template: # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "" /path/to/input.pdf diff --git a/Perl/Complex Flow Examples/merge-different-file-types.pl b/Perl/Complex Flow Examples/merge-different-file-types.pl index a7db76c3..10eb44cb 100644 --- a/Perl/Complex Flow Examples/merge-different-file-types.pl +++ b/Perl/Complex Flow Examples/merge-different-file-types.pl @@ -20,6 +20,7 @@ # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "Complex Flow Examples/merge-different-file-types.pl" /path/to/file1 /path/to/file2 [/path/to/file3 ...] diff --git a/Perl/Endpoint Examples/JSON Payload/markdown.pl b/Perl/Endpoint Examples/JSON Payload/markdown.pl index d6a5221b..b66aa141 100644 --- a/Perl/Endpoint Examples/JSON Payload/markdown.pl +++ b/Perl/Endpoint Examples/JSON Payload/markdown.pl @@ -20,6 +20,7 @@ # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "Endpoint Examples/JSON Payload/markdown.pl" /path/to/input.pdf diff --git a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl index 04b7e438..6082fec9 100644 --- a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl @@ -18,6 +18,7 @@ # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "Endpoint Examples/JSON Payload/rasterized-pdf.pl" /path/to/input.pdf diff --git a/Perl/Endpoint Examples/Multipart Payload/markdown.pl b/Perl/Endpoint Examples/Multipart Payload/markdown.pl index b95c37d1..5112acc1 100644 --- a/Perl/Endpoint Examples/Multipart Payload/markdown.pl +++ b/Perl/Endpoint Examples/Multipart Payload/markdown.pl @@ -17,6 +17,7 @@ # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "Endpoint Examples/Multipart Payload/markdown.pl" /path/to/input.pdf diff --git a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl index 94040f2a..4b2f78d2 100644 --- a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl @@ -17,6 +17,7 @@ # - Set PDFREST_API_KEY=your_api_key_here # - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work # # Usage: # perl "Endpoint Examples/Multipart Payload/rasterized-pdf.pl" /path/to/input.pdf From db600efd41844dca3710f461bf7261899acb59e2 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Thu, 4 Sep 2025 09:28:12 -0500 Subject: [PATCH 06/11] Use Dotenv for environment variable management in Perl examples - Replaced custom `.env` file parsing logic with `Dotenv` library across all Perl examples. - Updated `cpanfile` to include `Dotenv` as a dependency. - Adjusted related documentation in `AGENTS.md` to reflect the usage of `Dotenv`. --- Perl/AGENTS.md | 8 ++++++++ .../merge-different-file-types.pl | 20 ++++--------------- .../JSON Payload/markdown.pl | 16 ++------------- .../JSON Payload/rasterized-pdf.pl | 16 ++------------- .../Multipart Payload/markdown.pl | 16 ++------------- .../Multipart Payload/rasterized-pdf.pl | 16 ++------------- Perl/cpanfile | 1 + 7 files changed, 21 insertions(+), 72 deletions(-) diff --git a/Perl/AGENTS.md b/Perl/AGENTS.md index fecdb16c..acac095e 100644 --- a/Perl/AGENTS.md +++ b/Perl/AGENTS.md @@ -25,6 +25,14 @@ - Base URL: `$ENV{PDFREST_URL} // 'https://api.pdfrest.com'`. - I/O: print API responses to STDOUT; send diagnostics to STDERR; exit non‑2xx with non‑zero status. +### Environment Loading +- Use `Dotenv` to read `.env` into `%ENV` (do not hand‑roll parsing). +- Add dependency in `cpanfile`: `requires 'Dotenv';`. +- Load with a guarded call so missing files are fine: + - JSON/Multipart examples: `my $env_path = "$Bin/../../.env"; -e $env_path and Dotenv->load($env_path);` + - Complex Flow examples: `my $env_path = "$Bin/../.env"; -e $env_path and Dotenv->load($env_path);` +- Do not override pre‑existing environment variables; rely on library defaults (no explicit override). + ## Testing Guidelines - No formal test suite required for samples. Validate by running against small, known inputs. - Success: non‑zero exit on failures; JSON body printed to STDOUT on success. diff --git a/Perl/Complex Flow Examples/merge-different-file-types.pl b/Perl/Complex Flow Examples/merge-different-file-types.pl index 10eb44cb..8dc3e48f 100644 --- a/Perl/Complex Flow Examples/merge-different-file-types.pl +++ b/Perl/Complex Flow Examples/merge-different-file-types.pl @@ -9,6 +9,7 @@ use HTTP::Request; use HTTP::Request::Common qw(POST); use URI::Escape qw(uri_escape); +use Dotenv; #! # What this sample does: @@ -32,22 +33,9 @@ binmode STDOUT, ':raw'; binmode STDERR, ':encoding(UTF-8)'; -# Load .env from the Perl folder root -my $env_path = "$Bin/../.env"; # one level up from Complex Flow Examples -if (-f $env_path) { - open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; - while (my $line = <$env_fh>) { - chomp $line; - next if $line =~ /^\s*#/; - next if $line !~ /\S/; - if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { - my ($k, $v) = ($1, $2); - $v =~ s/^['"]|['"]$//g; - $ENV{$k} = $v if !exists $ENV{$k}; - } - } - close $env_fh; -} +# Load .env from the Perl folder root (one level up from this script) +my $env_path = "$Bin/../.env"; +-e $env_path and Dotenv->load($env_path); my $api_key = $ENV{PDFREST_API_KEY} // ''; if (!$api_key || $api_key =~ /^\s*$/) { diff --git a/Perl/Endpoint Examples/JSON Payload/markdown.pl b/Perl/Endpoint Examples/JSON Payload/markdown.pl index b66aa141..f6d6746f 100644 --- a/Perl/Endpoint Examples/JSON Payload/markdown.pl +++ b/Perl/Endpoint Examples/JSON Payload/markdown.pl @@ -9,6 +9,7 @@ use HTTP::Request; use HTTP::Request::Common qw(POST); use Encode qw(encode); +use Dotenv; #! # What this sample does: @@ -34,20 +35,7 @@ # Load .env from the Perl folder root (two levels up from this script) my $env_path = "$Bin/../../.env"; -if (-f $env_path) { - open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; - while (my $line = <$env_fh>) { - chomp $line; - next if $line =~ /^\s*#/; - next if $line !~ /\S/; - if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { - my ($k, $v) = ($1, $2); - $v =~ s/^['"]|['"]$//g; # strip surrounding quotes - $ENV{$k} = $v if !exists $ENV{$k}; - } - } - close $env_fh; -} +-e $env_path and Dotenv->load($env_path); my $api_key = $ENV{PDFREST_API_KEY} // ''; if (!$api_key || $api_key =~ /^\s*$/) { diff --git a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl index 6082fec9..e5045407 100644 --- a/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/JSON Payload/rasterized-pdf.pl @@ -7,6 +7,7 @@ use JSON::PP qw(encode_json decode_json); use LWP::UserAgent; use HTTP::Request; +use Dotenv; #! # What this sample does: @@ -32,20 +33,7 @@ # Load .env from the Perl folder root my $env_path = "$Bin/../../.env"; -if (-f $env_path) { - open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; - while (my $line = <$env_fh>) { - chomp $line; - next if $line =~ /^\s*#/; - next if $line !~ /\S/; - if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { - my ($k, $v) = ($1, $2); - $v =~ s/^['"]|['"]$//g; - $ENV{$k} = $v if !exists $ENV{$k}; - } - } - close $env_fh; -} +-e $env_path and Dotenv->load($env_path); my $api_key = $ENV{PDFREST_API_KEY} // ''; if (!$api_key || $api_key =~ /^\s*$/) { diff --git a/Perl/Endpoint Examples/Multipart Payload/markdown.pl b/Perl/Endpoint Examples/Multipart Payload/markdown.pl index 5112acc1..bbe2a81a 100644 --- a/Perl/Endpoint Examples/Multipart Payload/markdown.pl +++ b/Perl/Endpoint Examples/Multipart Payload/markdown.pl @@ -6,6 +6,7 @@ use File::Basename qw(basename); use LWP::UserAgent; use HTTP::Request::Common qw(POST); +use Dotenv; #! # What this sample does: @@ -31,20 +32,7 @@ # Load .env from the Perl folder root my $env_path = "$Bin/../../.env"; -if (-f $env_path) { - open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; - while (my $line = <$env_fh>) { - chomp $line; - next if $line =~ /^\s*#/; - next if $line !~ /\S/; - if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { - my ($k, $v) = ($1, $2); - $v =~ s/^['"]|['"]$//g; - $ENV{$k} = $v if !exists $ENV{$k}; - } - } - close $env_fh; -} +-e $env_path and Dotenv->load($env_path); my $api_key = $ENV{PDFREST_API_KEY} // ''; if (!$api_key || $api_key =~ /^\s*$/) { diff --git a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl index 4b2f78d2..e0ad6152 100644 --- a/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl +++ b/Perl/Endpoint Examples/Multipart Payload/rasterized-pdf.pl @@ -6,6 +6,7 @@ use File::Basename qw(basename); use LWP::UserAgent; use HTTP::Request::Common qw(POST); +use Dotenv; #! # What this sample does: @@ -31,20 +32,7 @@ # Load .env from the Perl folder root my $env_path = "$Bin/../../.env"; -if (-f $env_path) { - open my $env_fh, '<:encoding(UTF-8)', $env_path or die "Cannot open $env_path: $!\n"; - while (my $line = <$env_fh>) { - chomp $line; - next if $line =~ /^\s*#/; - next if $line !~ /\S/; - if ($line =~ /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/) { - my ($k, $v) = ($1, $2); - $v =~ s/^['"]|['"]$//g; - $ENV{$k} = $v if !exists $ENV{$k}; - } - } - close $env_fh; -} +-e $env_path and Dotenv->load($env_path); my $api_key = $ENV{PDFREST_API_KEY} // ''; if (!$api_key || $api_key =~ /^\s*$/) { diff --git a/Perl/cpanfile b/Perl/cpanfile index 734f6880..3f512600 100644 --- a/Perl/cpanfile +++ b/Perl/cpanfile @@ -8,3 +8,4 @@ requires 'Mozilla::CA'; requires 'IO::Socket::SSL'; requires 'Net::SSLeay'; requires 'URI'; +requires 'Dotenv'; From 381a0bd9eb4a09f4966ddd0706f01c5912e30895 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 16:45:59 -0500 Subject: [PATCH 07/11] Add AGENTS.md for VB.NET samples repository guidelines - Define project structure, coding conventions, and testing process. - Include setup, development, and sample execution instructions. - Provide commit and PR guidelines, along with security best practices. - Specify tone and audience for customer-facing samples, with a standardized header template for examples. --- VB.NET/AGENTS.md | 112 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 VB.NET/AGENTS.md diff --git a/VB.NET/AGENTS.md b/VB.NET/AGENTS.md new file mode 100644 index 00000000..5a6e14f0 --- /dev/null +++ b/VB.NET/AGENTS.md @@ -0,0 +1,112 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `VBNetSamples.vbproj`: Single root console project compiling all VB samples. +- `Program.vb`: Dispatcher routing `dotnet run -- ` to a specific sample. +- `Endpoint Examples/JSON Payload/`: Two-step samples (upload then operate), e.g., `markdown.vb`. +- `Endpoint Examples/Multipart Payload/`: Single multipart request samples, e.g., `rasterized-pdf.vb`. +- `Complex Flow Examples/`: Multi-step workflows chaining several endpoints. +- `.env.example` → copy to `.env` and set `PDFREST_API_KEY` (loaded by DotNetEnv at startup). +- `README.md`: High-level setup and usage for VB.NET samples. + +## Build, Test, and Development Commands +- Install .NET SDK (8.0+): verify with `dotnet --version`. +- Restore/build: `dotnet restore VBNetSamples.vbproj && dotnet build VBNetSamples.vbproj`. +- Run a sample via dispatcher: `dotnet run --project VBNetSamples.vbproj -- [args]`. + - Example: `dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf`. +- Dependencies: + - `.env` loading is included via `DotNetEnv`. + - Optional JSON helper: `dotnet add VBNetSamples.vbproj package Newtonsoft.Json` (only if a sample uses it). +- File-focused testing: keep each sample self-contained (accept input path as first arg; minimal edits). + +## Coding Style & Naming Conventions +- VB style: 4-space indentation, `PascalCase` for types/methods, `camelCase` for locals/parameters. +- File naming: match pdfRest endpoint with hyphenated lowercase, e.g., `markdown.vb`, `rasterized-pdf.vb`. +- Sample structure: each sample exposes `Public Async Function Execute(args() As String) As Task` and lives under a namespace mirroring its folder. Use underscores for folder segments that contain spaces: + - JSON two-step: `Namespace VBNetSamples.Endpoint_Examples.JSON_Payload` + - Multipart: `Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload` + - Complex flows: `Namespace VBNetSamples.Complex_Flow_Examples` + - Note: This satisfies IDE checks like “Namespace does not correspond to file location”. +- Dispatcher: `Program.vb` contains `Sub Main` and routes commands to `...Execute(args)`; do not add additional `Main` methods in samples. +- Env config: read `PDFREST_API_KEY` and optional `PDFREST_URL`; `.env` is auto-loaded by `DotNetEnv`. +- HTTP: use `HttpClient` with explicit `Accept`/`Content-Type`; set `Api-Key` per request; use `MultipartFormDataContent`; default base URL `https://api.pdfrest.com` with `PDFREST_URL` override. +- Errors: check `response.IsSuccessStatusCode`; on failure, write a concise error to `Console.Error` and exit non-zero. + +## Testing Guidelines +- No formal test suite required. Validate by running samples against known inputs. +- Success criteria: exit non-zero on failures; print API JSON response to stdout on success. +- New samples: accept input path as first argument when practical; document optional params inline near usage. + +## Commit & Pull Request Guidelines +- Commits: imperative mood and focused scope (e.g., "Add multipart markdown VB sample"). +- Describe what changed and why; reference endpoint and path. +- PRs: include clear description, run commands used for verification, expected response snippet, and any notes on options. +- Link related issues; avoid unrelated changes in the same PR. + +## Security & Configuration Tips +- Keep secrets out of VCS: do not commit `.env`; include a `.env.example` with placeholder keys if the folder uses `.env`. +- Support proxies via standard env vars (e.g., `HTTPS_PROXY`) when applicable. +- Never log API keys; print response bodies and minimal diagnostics only (send diagnostics to `Console.Error`). +- API base override: set `PDFREST_URL` to change regions. For EU GDPR compliance and improved performance in Europe, you may use `https://eu-api.pdfrest.com/`. More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +--- + +## Audience And Tone (Internal) + +These samples are customer-facing and intended to help potential customers evaluate pdfRest quickly. Keep all code, comments, and documentation clear, minimal, and task-focused. Avoid internal jargon and advanced implementation details in customer-visible files. Do not surface internal process notes in `README.md` or the samples. + +Key points: +- Clarity: explain what the sample does in 1–2 bullets. +- Guidance: show how to set the API key and how to run. +- Region: mention optional `PDFREST_URL` with the EU endpoint for GDPR and proximity. +- Safety: never log secrets; print only response bodies and minimal diagnostics to stderr. +- Errors: exit non‑zero on non‑2xx with a concise message. + +## Sample Header Convention (Internal) + +Add this standardized header comment at the top of every VB.NET sample. This header is customer-visible but the convention itself is for us to remember here (do not duplicate these instructions in README). + +Template: + +''' +' What this sample does: +' - +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- ... > response.json +''' + +Notes: +- Match the endpoint name and request style (JSON two‑step vs multipart single request) in the bullets. +- Keep the header concise; avoid adding options unless essential. +- If a sample accepts optional parameters, mention them inline in code near where they are used. + +## README Scope (Internal) + +Keep `README.md` focused on user setup, running samples, and high‑level background. Avoid internal conventions or meta‑process content that could confuse customers. Place internal notes and templates in `AGENTS.md` (this file). + +--- + +## VB.NET Implementation Notes (Internal) +- Dispatcher entry point: `Program.vb` exposes `Sub Main` (wrapping an async method) and selects a sample based on the first CLI argument. Only one entry point exists. +- Add a new sample: + - Create a `.vb` file under the appropriate folder. + - Namespace as noted above; expose `Public Async Function Execute(args() As String) As Task`. + - Update `Program.vb` `Select Case` to map a command (e.g., `png`) to the new module’s `Execute`. +- JSON parsing: prefer `System.Text.Json`; if using `Newtonsoft.Json`, add the NuGet package and import `Newtonsoft.Json.Linq` for simple extraction. +- Multipart uploads: `New MultipartFormDataContent()` with `ByteArrayContent` or `StreamContent`. Set `Content-Type` and filename as needed. +- Headers: set `Api-Key` per request; always send `Accept: application/json`. +- Base URL: default `https://api.pdfrest.com`; support `PDFREST_URL` override. +- Env loader: `.env` is loaded automatically via `DotNetEnv` at startup. +- Errors: prefer `If Not response.IsSuccessStatusCode Then ... Environment.Exit(1)`. From 3bd47bbabf098f424b82f4e915d9fb27c6ffd33b Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 16:46:28 -0500 Subject: [PATCH 08/11] Add VB.NET examples for pdfRest API integration - Implement JSON and Multipart payload examples for Markdown and rasterized PDF generation. - Add a "Complex Flow" script to demonstrate merging PDFs and non-PDFs into a single PDF. - Introduce `.env.example` for API key configuration and optional EU endpoint setup. - Create a `Program.vb` dispatcher to route commands to corresponding samples. - Write detailed README with setup instructions, usage examples, and project structure. - Ensure consistent headers and comments across all samples. - Include GDPR API call information and usage tips. --- VB.NET/.env.example | 5 + .../merge-different-file-types.vb | 174 ++++++++++++++++++ .../JSON Payload/markdown.vb | 126 +++++++++++++ .../JSON Payload/rasterized-pdf.vb | 124 +++++++++++++ .../Multipart Payload/markdown.vb | 94 ++++++++++ .../Multipart Payload/rasterized-pdf.vb | 95 ++++++++++ VB.NET/Program.vb | 87 +++++++++ VB.NET/README.md | 71 +++++++ VB.NET/VBNetSamples.vbproj | 22 +++ 9 files changed, 798 insertions(+) create mode 100644 VB.NET/.env.example create mode 100644 VB.NET/Complex Flow Examples/merge-different-file-types.vb create mode 100644 VB.NET/Endpoint Examples/JSON Payload/markdown.vb create mode 100644 VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb create mode 100644 VB.NET/Endpoint Examples/Multipart Payload/markdown.vb create mode 100644 VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb create mode 100644 VB.NET/Program.vb create mode 100644 VB.NET/README.md create mode 100644 VB.NET/VBNetSamples.vbproj diff --git a/VB.NET/.env.example b/VB.NET/.env.example new file mode 100644 index 00000000..409ea2e5 --- /dev/null +++ b/VB.NET/.env.example @@ -0,0 +1,5 @@ +# Set your pdfRest API key +PDFREST_API_KEY=your_api_key_here + +# Optional: override the API base URL (e.g., for EU region) +# PDFREST_URL=https://eu-api.pdfrest.com diff --git a/VB.NET/Complex Flow Examples/merge-different-file-types.vb b/VB.NET/Complex Flow Examples/merge-different-file-types.vb new file mode 100644 index 00000000..2c8f3462 --- /dev/null +++ b/VB.NET/Complex Flow Examples/merge-different-file-types.vb @@ -0,0 +1,174 @@ +''' +' What this sample does: +' - Merges multiple inputs (PDFs and non-PDFs) into a single PDF. +' - Non-PDF files are first converted to PDF; PDFs are uploaded as-is. All resulting IDs are then merged. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- merge-different-file-types /path/to/file1 /path/to/file2 [...] +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- merge-different-file-types ... > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Complex_Flow_Examples + Module MergeDifferentFileTypes + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 2 Then + Console.Error.WriteLine("Usage: dotnet run -- merge-different-file-types /path/to/file1 /path/to/file2 [/path/to/file3 ...]") + Environment.Exit(1) + End If + + Dim allExist = Array.TrueForAll(args, Function(p) File.Exists(p)) + If Not allExist Then + Console.Error.WriteLine("One or more input files do not exist.") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim collectedIds As New List(Of String)() + + For i = 0 To args.Length - 1 + Dim p As String = args(i) + Dim ext As String = Path.GetExtension(p).ToLowerInvariant() + If ext = ".pdf" Then + ' Upload PDFs to get an id + Dim uploadReq As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim pdfBytes As Byte() = File.ReadAllBytes(p) + Dim uploadContent As New ByteArrayContent(pdfBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(p)) + uploadReq.Content = uploadContent + + Dim uploadResp = Await httpClient.SendAsync(uploadReq) + Dim uploadBody = Await uploadResp.Content.ReadAsStringAsync() + If Not uploadResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed for input #{i + 1}: {CInt(uploadResp.StatusCode)} {uploadResp.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + Dim id As String = Nothing + Using doc = JsonDocument.Parse(uploadBody) + id = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + collectedIds.Add(id) + Else + ' Convert non-PDF to PDF to get an outputId + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(p) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue(ContentTypeFor(p)) + multipart.Add(fileContent, "file", Path.GetFileName(p)) + + Dim convReq As New HttpRequestMessage(HttpMethod.Post, "pdf") + convReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + convReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + convReq.Content = multipart + + Dim convResp = Await httpClient.SendAsync(convReq) + Dim convBody = Await convResp.Content.ReadAsStringAsync() + If Not convResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Conversion failed for input #{i + 1}: {CInt(convResp.StatusCode)} {convResp.ReasonPhrase}") + Console.Error.WriteLine(convBody) + Environment.Exit(1) + End If + + Using doc = JsonDocument.Parse(convBody) + Dim outputId = doc.RootElement.GetProperty("outputId").GetString() + collectedIds.Add(outputId) + End Using + End If + Next + + ' Build x-www-form-urlencoded body with arrays + Dim pairs As New List(Of KeyValuePair(Of String, String))() + For Each id In collectedIds + pairs.Add(New KeyValuePair(Of String, String)("id[]", id)) + pairs.Add(New KeyValuePair(Of String, String)("pages[]", "1-last")) + pairs.Add(New KeyValuePair(Of String, String)("type[]", "id")) + Next + + Dim mergeReq As New HttpRequestMessage(HttpMethod.Post, "merged-pdf") + mergeReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + mergeReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + mergeReq.Content = New FormUrlEncodedContent(pairs) + + Dim mergeResp = Await httpClient.SendAsync(mergeReq) + Dim mergeBody = Await mergeResp.Content.ReadAsStringAsync() + If Not mergeResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Merge failed: {CInt(mergeResp.StatusCode)} {mergeResp.ReasonPhrase}") + Console.Error.WriteLine(mergeBody) + Environment.Exit(1) + End If + + Console.WriteLine(mergeBody) + End Using + End Function + + Private Function ContentTypeFor(filePath As String) As String + Dim ext = System.IO.Path.GetExtension(filePath).ToLowerInvariant() + Select Case ext + Case ".pdf" : Return "application/pdf" + Case ".png" : Return "image/png" + Case ".jpg", ".jpeg" : Return "image/jpeg" + Case ".gif" : Return "image/gif" + Case ".tif", ".tiff" : Return "image/tiff" + Case ".bmp" : Return "image/bmp" + Case ".webp" : Return "image/webp" + Case ".doc" : Return "application/msword" + Case ".docx" : Return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + Case ".ppt" : Return "application/vnd.ms-powerpoint" + Case ".pptx" : Return "application/vnd.openxmlformats-officedocument.presentationml.presentation" + Case ".xls" : Return "application/vnd.ms-excel" + Case ".xlsx" : Return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + Case ".txt" : Return "text/plain" + Case ".rtf" : Return "application/rtf" + Case ".html", ".htm" : Return "text/html" + Case Else : Return "application/octet-stream" + End Select + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/JSON Payload/markdown.vb b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb new file mode 100644 index 00000000..c09550f9 --- /dev/null +++ b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb @@ -0,0 +1,126 @@ +''' +' What this sample does: +' - Converts a PDF to Markdown using pdfRest. +' - Uses a JSON payload in two steps: first uploads, then calls /markdown with the uploaded id. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.JSON_Payload + Module Markdown + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- markdown /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + ' 1) Upload + Dim uploadRequest As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim uploadContent As New ByteArrayContent(fileBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(inputPath)) + uploadRequest.Content = uploadContent + + Dim uploadResponse As HttpResponseMessage = Await httpClient.SendAsync(uploadRequest) + Dim uploadBody As String = Await uploadResponse.Content.ReadAsStringAsync() + + If Not uploadResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed: {CInt(uploadResponse.StatusCode)} {uploadResponse.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + ' Optional: print upload JSON + Console.WriteLine(uploadBody) + + Dim uploadedId As String = Nothing + Try + Using doc As JsonDocument = JsonDocument.Parse(uploadBody) + uploadedId = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + Catch ex As Exception + Console.Error.WriteLine("Failed to parse upload response JSON for file id.") + Console.Error.WriteLine(ex.Message) + Environment.Exit(1) + End Try + + ' 2) Markdown via JSON payload + Dim markdownRequest As New HttpRequestMessage(HttpMethod.Post, "markdown") + markdownRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + markdownRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim payload As New Dictionary(Of String, String) From { + {"id", uploadedId} + } + Dim payloadJson As String = JsonSerializer.Serialize(payload) + markdownRequest.Content = New StringContent(payloadJson, Encoding.UTF8, "application/json") + + Dim markdownResponse As HttpResponseMessage = Await httpClient.SendAsync(markdownRequest) + Dim markdownBody As String = Await markdownResponse.Content.ReadAsStringAsync() + + If Not markdownResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Markdown request failed: {CInt(markdownResponse.StatusCode)} {markdownResponse.ReasonPhrase}") + Console.Error.WriteLine(markdownBody) + Environment.Exit(1) + End If + + Console.WriteLine(markdownBody) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb new file mode 100644 index 00000000..03d1d973 --- /dev/null +++ b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb @@ -0,0 +1,124 @@ +''' +' What this sample does: +' - Creates a rasterized version of a PDF using pdfRest. +' - Uses a JSON payload in two steps: first uploads, then calls /rasterized-pdf with the uploaded id. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Collections.Generic +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Text.Json +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.JSON_Payload + Module RasterizedPdf + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- rasterized-pdf /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + ' 1) Upload step + Dim uploadRequest As New HttpRequestMessage(HttpMethod.Post, "upload") + uploadRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey) + uploadRequest.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim uploadContent As New ByteArrayContent(fileBytes) + uploadContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream") + uploadContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(inputPath)) + uploadRequest.Content = uploadContent + + Dim uploadResponse As HttpResponseMessage = Await httpClient.SendAsync(uploadRequest) + Dim uploadBody As String = Await uploadResponse.Content.ReadAsStringAsync() + + If Not uploadResponse.IsSuccessStatusCode Then + Console.Error.WriteLine($"Upload failed: {CInt(uploadResponse.StatusCode)} {uploadResponse.ReasonPhrase}") + Console.Error.WriteLine(uploadBody) + Environment.Exit(1) + End If + + ' Optional: print upload JSON + Console.WriteLine(uploadBody) + + Dim uploadedId As String = Nothing + Try + Using doc As JsonDocument = JsonDocument.Parse(uploadBody) + uploadedId = doc.RootElement.GetProperty("files")(0).GetProperty("id").GetString() + End Using + Catch ex As Exception + Console.Error.WriteLine("Failed to parse upload response JSON for file id.") + Console.Error.WriteLine(ex.Message) + Environment.Exit(1) + End Try + + ' 2) Rasterized PDF request (JSON) + Dim rasterReq As New HttpRequestMessage(HttpMethod.Post, "rasterized-pdf") + rasterReq.Headers.TryAddWithoutValidation("Api-Key", apiKey) + rasterReq.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + + Dim payload As New Dictionary(Of String, String) From {{"id", uploadedId}} + Dim payloadJson As String = JsonSerializer.Serialize(payload) + rasterReq.Content = New StringContent(payloadJson, Encoding.UTF8, "application/json") + + Dim rasterResp As HttpResponseMessage = Await httpClient.SendAsync(rasterReq) + Dim rasterBody As String = Await rasterResp.Content.ReadAsStringAsync() + + If Not rasterResp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Rasterized-pdf request failed: {CInt(rasterResp.StatusCode)} {rasterResp.ReasonPhrase}") + Console.Error.WriteLine(rasterBody) + Environment.Exit(1) + End If + + Console.WriteLine(rasterBody) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb new file mode 100644 index 00000000..0f943c8a --- /dev/null +++ b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb @@ -0,0 +1,94 @@ +''' +' What this sample does: +' - Converts a PDF to Markdown using pdfRest. +' - Sends a single multipart/form-data request directly to /markdown with the file. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload + Module Markdown + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- markdown-multipart /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue("application/pdf") + multipart.Add(fileContent, "file", Path.GetFileName(inputPath)) + + ' Optional parameters + multipart.Add(New StringContent("pdfrest_markdown", Encoding.UTF8), "output") + multipart.Add(New StringContent("on", Encoding.UTF8), "page_break_comments") + ' e.g., page range: multipart.Add(New StringContent("1-3", Encoding.UTF8), "page_range") + + Dim req As New HttpRequestMessage(HttpMethod.Post, "markdown") + req.Headers.TryAddWithoutValidation("Api-Key", apiKey) + req.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + req.Content = multipart + + Dim resp As HttpResponseMessage = Await httpClient.SendAsync(req) + Dim body As String = Await resp.Content.ReadAsStringAsync() + If Not resp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Markdown (multipart) failed: {CInt(resp.StatusCode)} {resp.ReasonPhrase}") + Console.Error.WriteLine(body) + Environment.Exit(1) + End If + + Console.WriteLine(body) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb new file mode 100644 index 00000000..d4887952 --- /dev/null +++ b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb @@ -0,0 +1,95 @@ +''' +' What this sample does: +' - Creates a rasterized version of a PDF using pdfRest. +' - Sends a single multipart/form-data request directly to /rasterized-pdf with the file. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage (via dispatcher): +' dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf +' +' Output: +' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf > response.json +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.IO +Imports System.Net.Http +Imports System.Net.Http.Headers +Imports System.Text +Imports System.Threading.Tasks + +Namespace VBNetSamples.Endpoint_Examples.Multipart_Payload + Module RasterizedPdf + Public Async Function Execute(args As String()) As Task + If args Is Nothing OrElse args.Length < 1 Then + Console.Error.WriteLine("Usage: dotnet run -- rasterized-pdf-multipart /path/to/input.pdf") + Environment.Exit(1) + End If + + Dim inputPath As String = args(0) + If Not File.Exists(inputPath) Then + Console.Error.WriteLine($"Input file not found: {inputPath}") + Environment.Exit(1) + End If + + Dim apiKey As String = Environment.GetEnvironmentVariable("PDFREST_API_KEY") + If String.IsNullOrWhiteSpace(apiKey) Then + Console.Error.WriteLine("Missing environment variable PDFREST_API_KEY.") + Environment.Exit(1) + End If + + Dim baseUrl As String = Environment.GetEnvironmentVariable("PDFREST_URL") + If String.IsNullOrWhiteSpace(baseUrl) Then baseUrl = "https://api.pdfrest.com" + + Dim baseUri As Uri + Try + baseUri = New Uri(baseUrl) + Catch ex As Exception + Console.Error.WriteLine($"Invalid PDFREST_URL: {baseUrl}") + Environment.Exit(1) + Return + End Try + + Using httpClient As New HttpClient() + httpClient.BaseAddress = baseUri + + Dim multipart As New MultipartFormDataContent() + Dim fileBytes As Byte() = File.ReadAllBytes(inputPath) + Dim fileContent As New ByteArrayContent(fileBytes) + fileContent.Headers.ContentType = New MediaTypeHeaderValue("application/pdf") + multipart.Add(fileContent, "file", Path.GetFileName(inputPath)) + + multipart.Add(New StringContent("pdfrest_rasterize", Encoding.UTF8), "output") + ' Optional settings: + ' multipart.Add(New StringContent("300", Encoding.UTF8), "dpi") + ' multipart.Add(New StringContent("rgb", Encoding.UTF8), "color_space") + ' multipart.Add(New StringContent("1-3", Encoding.UTF8), "page_range") + + Dim req As New HttpRequestMessage(HttpMethod.Post, "rasterized-pdf") + req.Headers.TryAddWithoutValidation("Api-Key", apiKey) + req.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) + req.Content = multipart + + Dim resp As HttpResponseMessage = Await httpClient.SendAsync(req) + Dim body As String = Await resp.Content.ReadAsStringAsync() + If Not resp.IsSuccessStatusCode Then + Console.Error.WriteLine($"Rasterized-pdf (multipart) failed: {CInt(resp.StatusCode)} {resp.ReasonPhrase}") + Console.Error.WriteLine(body) + Environment.Exit(1) + End If + + Console.WriteLine(body) + End Using + End Function + End Module +End Namespace diff --git a/VB.NET/Program.vb b/VB.NET/Program.vb new file mode 100644 index 00000000..7cdf129a --- /dev/null +++ b/VB.NET/Program.vb @@ -0,0 +1,87 @@ +''' +' What this sample does: +' - Provides a command dispatcher for VB.NET samples in this folder. +' - Routes `dotnet run -- ` to the corresponding sample module. +' +' Setup (environment): +' - Copy .env.example to .env +' - Set PDFREST_API_KEY=your_api_key_here +' - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use: +' PDFREST_URL=https://eu-api.pdfrest.com +' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work +' +' Usage: +' dotnet run --project VBNetSamples.vbproj -- [args] +' e.g., dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf +' +' Output: +' - Each command prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. +''' + +Option Strict On +Option Explicit On + +Imports System +Imports System.Linq +Imports System.Threading.Tasks +Imports DotNetEnv + +Module Program + Public Sub Main(args As String()) + MainAsync(args).GetAwaiter().GetResult() + End Sub + + Private Async Function MainAsync(args As String()) As Task + ' Load environment variables from .env if present (via DotNetEnv) + Env.Load() + If args Is Nothing OrElse args.Length = 0 Then + PrintUsage() + Environment.Exit(1) + End If + + Dim cmd As String = args(0).Trim().ToLowerInvariant() + Dim rest As String() + If args.Length > 1 Then + rest = args.Skip(1).ToArray() + Else + rest = Array.Empty(Of String)() + End If + + Select Case cmd + Case "markdown", "markdown-json" + Await VBNetSamples.Endpoint_Examples.JSON_Payload.Markdown.Execute(rest) + Case "rasterized-pdf", "rasterize-json" + Await VBNetSamples.Endpoint_Examples.JSON_Payload.RasterizedPdf.Execute(rest) + Case "markdown-multipart" + Await VBNetSamples.Endpoint_Examples.Multipart_Payload.Markdown.Execute(rest) + Case "rasterized-pdf-multipart", "rasterize-multipart" + Await VBNetSamples.Endpoint_Examples.Multipart_Payload.RasterizedPdf.Execute(rest) + Case "merge-different-file-types", "merge" + Await VBNetSamples.Complex_Flow_Examples.MergeDifferentFileTypes.Execute(rest) + Case Else + Console.Error.WriteLine($"Unknown command: {cmd}") + PrintUsage() + Environment.Exit(1) + End Select + End Function + + ' DotNetEnv handles .env loading; no manual parser needed. + + Private Sub PrintUsage() + Console.Error.WriteLine("Usage: dotnet run -- [args]") + Console.Error.WriteLine("") + Console.Error.WriteLine("Commands:") + Console.Error.WriteLine(" markdown | markdown-json Upload then convert to Markdown (JSON two-step)") + Console.Error.WriteLine(" rasterized-pdf | rasterize-json Upload then rasterize PDF (JSON two-step)") + Console.Error.WriteLine(" markdown-multipart Convert to Markdown (single multipart request)") + Console.Error.WriteLine(" rasterized-pdf-multipart Rasterize PDF (single multipart request)") + Console.Error.WriteLine(" merge-different-file-types|merge Merge PDFs and non-PDFs into one PDF") + Console.Error.WriteLine("") + Console.Error.WriteLine("Examples:") + Console.Error.WriteLine(" dotnet run -- markdown /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- rasterized-pdf /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- markdown-multipart /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- rasterized-pdf-multipart /path/to/input.pdf") + Console.Error.WriteLine(" dotnet run -- merge-different-file-types file1.pdf file2.docx image.png") + End Sub +End Module diff --git a/VB.NET/README.md b/VB.NET/README.md new file mode 100644 index 00000000..af4dd0e8 --- /dev/null +++ b/VB.NET/README.md @@ -0,0 +1,71 @@ +# pdfRest VB.NET Samples + +These VB.NET samples demonstrate how to call pdfRest APIs using HttpClient. A single console project (`VBNetSamples.vbproj`) acts as a dispatcher so you can run any sample with a simple command. + +## Prerequisites +- .NET SDK 8.0 or newer (check with `dotnet --version`). +- A pdfRest API key. +- Internet access to reach `https://api.pdfrest.com` (or the EU endpoint below). + +## Quick Start +1) From this `VB.NET/` folder, copy the environment template and set your API key: +- `cp .env.example .env` +- Edit `.env` and set `PDFREST_API_KEY=your_api_key_here` + +2) Optional: EU/GDPR endpoint for European data residency and performance: +- In `.env`, set `PDFREST_URL=https://eu-api.pdfrest.com` +- More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work + +3) Restore and build the project: +- `dotnet restore VBNetSamples.vbproj` +- `dotnet build VBNetSamples.vbproj` + +4) Run a sample (examples below). The dispatcher pattern is: +- `dotnet run --project VBNetSamples.vbproj -- [args]` + +## How It’s Organized +- `VBNetSamples.vbproj`: single console app that compiles all VB samples in this folder. +- `Program.vb`: a small dispatcher that routes `` to a specific sample’s `Execute` method. +- `Endpoint Examples/JSON Payload/`: two‑step samples (upload, then operate with a JSON body). +- `Endpoint Examples/Multipart Payload/`: single multipart/form-data request per operation. +- `Complex Flow Examples/`: multi-step workflows combining endpoints. +- `.env`: holds configuration (`PDFREST_API_KEY`, optional `PDFREST_URL`). Loaded automatically via DotNetEnv. + +## Available Samples +JSON two‑step (upload → operate via JSON): +- `markdown` — Convert PDF to Markdown + - Run: `dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf` +- `rasterized-pdf` — Rasterize a PDF + - Run: `dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf` + +Multipart single request (send file directly): +- `markdown-multipart` — Convert PDF to Markdown + - Run: `dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf` +- `rasterized-pdf-multipart` — Rasterize a PDF + - Run: `dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf` + +Complex flow: +- `merge-different-file-types` — Merge multiple inputs (PDFs and non‑PDFs) + - Run: `dotnet run --project VBNetSamples.vbproj -- merge-different-file-types file1.pdf file2.docx image.png` + +## Output & Error Handling +- Successful calls print the API’s JSON response to stdout. +- Failures write a concise message to stderr and exit with a non‑zero code. +- Tip: redirect output to a file, e.g., `... > response.json`. + +## Troubleshooting +- Missing API key: + - Ensure `.env` exists with `PDFREST_API_KEY` set, or export it in your shell before running. +- EU endpoint: + - If using the EU endpoint, verify `PDFREST_URL=https://eu-api.pdfrest.com` in `.env`. +- .NET version: + - Check with `dotnet --version`. Use .NET 8.0 or newer. +- Clean build: + - `rm -rf bin obj && dotnet build VBNetSamples.vbproj` +- Proxy environments: + - If your network requires a proxy, set standard environment variables like `HTTPS_PROXY`. + +## Notes +- These are focused samples to help you evaluate pdfRest quickly. +- Do not commit secrets. Keep `.env` out of version control. +- For more APIs, options, and regions, see the pdfRest documentation and pricing page. diff --git a/VB.NET/VBNetSamples.vbproj b/VB.NET/VBNetSamples.vbproj new file mode 100644 index 00000000..5241f19f --- /dev/null +++ b/VB.NET/VBNetSamples.vbproj @@ -0,0 +1,22 @@ + + + Exe + VBNetSamples + net8.0 + On + On + On + VBNetSamples.Program + false + + + + + + + + + + + + From 70acb415ed146c34b3d408b7d06d06c80dcaf4e9 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 16:48:32 -0500 Subject: [PATCH 09/11] Add .gitignore --- VB.NET/.gitignore | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 VB.NET/.gitignore diff --git a/VB.NET/.gitignore b/VB.NET/.gitignore new file mode 100644 index 00000000..831821e4 --- /dev/null +++ b/VB.NET/.gitignore @@ -0,0 +1,79 @@ +# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,visualbasic +# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,visualbasic + +### DotnetCore ### +# .NET Core build folders +bin/ +obj/ + +# Common node modules locations +/node_modules +/wwwroot/node_modules + +### VisualBasic ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +.DS_Store +.Trashes +*.vbw +*.csi +*.exp +*.lib +*.lvw +*.dca +*.scc +*.tmp +*.exe +*.bat +*.bak +*.zip +*.old +*.enc +*.key +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,visualbasic \ No newline at end of file From 8e217d131860fd923523489d8fdd66357639369c Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Wed, 3 Sep 2025 17:23:46 -0500 Subject: [PATCH 10/11] Simplify VB.NET dispatcher commands and update usage examples - Removed `--project VBNetSamples.vbproj` argument for all `dotnet` commands across documentation and sample scripts. - Updated all usage examples in `README.md`, `AGENTS.md`, and VB.NET examples for consistency. - Refined build and run instructions to align with cleaner syntax. - Improved tip section formatting for piping output to files. --- VB.NET/AGENTS.md | 12 +++++------ .../merge-different-file-types.vb | 4 ++-- .../JSON Payload/markdown.vb | 4 ++-- .../JSON Payload/rasterized-pdf.vb | 4 ++-- .../Multipart Payload/markdown.vb | 4 ++-- .../Multipart Payload/rasterized-pdf.vb | 4 ++-- VB.NET/Program.vb | 4 ++-- VB.NET/README.md | 20 +++++++++---------- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/VB.NET/AGENTS.md b/VB.NET/AGENTS.md index 5a6e14f0..114de461 100644 --- a/VB.NET/AGENTS.md +++ b/VB.NET/AGENTS.md @@ -11,12 +11,12 @@ ## Build, Test, and Development Commands - Install .NET SDK (8.0+): verify with `dotnet --version`. -- Restore/build: `dotnet restore VBNetSamples.vbproj && dotnet build VBNetSamples.vbproj`. -- Run a sample via dispatcher: `dotnet run --project VBNetSamples.vbproj -- [args]`. - - Example: `dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf`. +- Restore/build (from VB.NET folder): `dotnet restore && dotnet build`. +- Run a sample via dispatcher: `dotnet run -- [args]`. + - Example: `dotnet run -- markdown /path/to/input.pdf`. - Dependencies: - `.env` loading is included via `DotNetEnv`. - - Optional JSON helper: `dotnet add VBNetSamples.vbproj package Newtonsoft.Json` (only if a sample uses it). + - Optional JSON helper: `dotnet add package Newtonsoft.Json` (only if a sample uses it). - File-focused testing: keep each sample self-contained (accept input path as first arg; minimal edits). ## Coding Style & Naming Conventions @@ -80,11 +80,11 @@ Template: ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- /path/to/input.pdf +' dotnet run -- /path/to/input.pdf ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- ... > response.json +' - Tip: pipe output to a file: dotnet run -- ... > response.json ''' Notes: diff --git a/VB.NET/Complex Flow Examples/merge-different-file-types.vb b/VB.NET/Complex Flow Examples/merge-different-file-types.vb index 2c8f3462..ad8797d6 100644 --- a/VB.NET/Complex Flow Examples/merge-different-file-types.vb +++ b/VB.NET/Complex Flow Examples/merge-different-file-types.vb @@ -11,11 +11,11 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- merge-different-file-types /path/to/file1 /path/to/file2 [...] +' dotnet run -- merge-different-file-types /path/to/file1 /path/to/file2 [...] ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- merge-different-file-types ... > response.json +' - Tip: pipe output to a file: dotnet run -- merge-different-file-types ... > response.json ''' Option Strict On diff --git a/VB.NET/Endpoint Examples/JSON Payload/markdown.vb b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb index c09550f9..c18b0eed 100644 --- a/VB.NET/Endpoint Examples/JSON Payload/markdown.vb +++ b/VB.NET/Endpoint Examples/JSON Payload/markdown.vb @@ -11,11 +11,11 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf +' dotnet run -- markdown /path/to/input.pdf ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf > response.json +' - Tip: pipe output to a file: dotnet run -- markdown /path/to/input.pdf > response.json ''' Option Strict On diff --git a/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb index 03d1d973..a2c1cede 100644 --- a/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb +++ b/VB.NET/Endpoint Examples/JSON Payload/rasterized-pdf.vb @@ -11,11 +11,11 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf +' dotnet run -- rasterized-pdf /path/to/input.pdf ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf > response.json +' - Tip: pipe output to a file: dotnet run -- rasterized-pdf /path/to/input.pdf > response.json ''' Option Strict On diff --git a/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb index 0f943c8a..46cdadd8 100644 --- a/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb +++ b/VB.NET/Endpoint Examples/Multipart Payload/markdown.vb @@ -11,11 +11,11 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf +' dotnet run -- markdown-multipart /path/to/input.pdf ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf > response.json +' - Tip: pipe output to a file: dotnet run -- markdown-multipart /path/to/input.pdf > response.json ''' Option Strict On diff --git a/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb index d4887952..4bbd997f 100644 --- a/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb +++ b/VB.NET/Endpoint Examples/Multipart Payload/rasterized-pdf.vb @@ -11,11 +11,11 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage (via dispatcher): -' dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf +' dotnet run -- rasterized-pdf-multipart /path/to/input.pdf ' ' Output: ' - Prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. -' - Tip: pipe output to a file: dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf > response.json +' - Tip: pipe output to a file: dotnet run -- rasterized-pdf-multipart /path/to/input.pdf > response.json ''' Option Strict On diff --git a/VB.NET/Program.vb b/VB.NET/Program.vb index 7cdf129a..99734dbf 100644 --- a/VB.NET/Program.vb +++ b/VB.NET/Program.vb @@ -11,8 +11,8 @@ ' For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work ' ' Usage: -' dotnet run --project VBNetSamples.vbproj -- [args] -' e.g., dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf +' dotnet run -- [args] +' e.g., dotnet run -- markdown /path/to/input.pdf ' ' Output: ' - Each command prints the API JSON response to stdout. Non-2xx responses write a concise message to stderr and exit non-zero. diff --git a/VB.NET/README.md b/VB.NET/README.md index af4dd0e8..3f895ced 100644 --- a/VB.NET/README.md +++ b/VB.NET/README.md @@ -16,12 +16,12 @@ These VB.NET samples demonstrate how to call pdfRest APIs using HttpClient. A si - In `.env`, set `PDFREST_URL=https://eu-api.pdfrest.com` - More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work -3) Restore and build the project: -- `dotnet restore VBNetSamples.vbproj` -- `dotnet build VBNetSamples.vbproj` +3) Restore and build the project (from this folder): +- `dotnet restore` +- `dotnet build` 4) Run a sample (examples below). The dispatcher pattern is: -- `dotnet run --project VBNetSamples.vbproj -- [args]` +- `dotnet run -- [args]` ## How It’s Organized - `VBNetSamples.vbproj`: single console app that compiles all VB samples in this folder. @@ -34,19 +34,19 @@ These VB.NET samples demonstrate how to call pdfRest APIs using HttpClient. A si ## Available Samples JSON two‑step (upload → operate via JSON): - `markdown` — Convert PDF to Markdown - - Run: `dotnet run --project VBNetSamples.vbproj -- markdown /path/to/input.pdf` + - Run: `dotnet run -- markdown /path/to/input.pdf` - `rasterized-pdf` — Rasterize a PDF - - Run: `dotnet run --project VBNetSamples.vbproj -- rasterized-pdf /path/to/input.pdf` + - Run: `dotnet run -- rasterized-pdf /path/to/input.pdf` Multipart single request (send file directly): - `markdown-multipart` — Convert PDF to Markdown - - Run: `dotnet run --project VBNetSamples.vbproj -- markdown-multipart /path/to/input.pdf` + - Run: `dotnet run -- markdown-multipart /path/to/input.pdf` - `rasterized-pdf-multipart` — Rasterize a PDF - - Run: `dotnet run --project VBNetSamples.vbproj -- rasterized-pdf-multipart /path/to/input.pdf` + - Run: `dotnet run -- rasterized-pdf-multipart /path/to/input.pdf` Complex flow: - `merge-different-file-types` — Merge multiple inputs (PDFs and non‑PDFs) - - Run: `dotnet run --project VBNetSamples.vbproj -- merge-different-file-types file1.pdf file2.docx image.png` + - Run: `dotnet run -- merge-different-file-types file1.pdf file2.docx image.png` ## Output & Error Handling - Successful calls print the API’s JSON response to stdout. @@ -61,7 +61,7 @@ Complex flow: - .NET version: - Check with `dotnet --version`. Use .NET 8.0 or newer. - Clean build: - - `rm -rf bin obj && dotnet build VBNetSamples.vbproj` + - `rm -rf bin obj && dotnet build` - Proxy environments: - If your network requires a proxy, set standard environment variables like `HTTPS_PROXY`. From 896034609ed47cb6d60e23fcee7bca17849e6ec3 Mon Sep 17 00:00:00 2001 From: "Kevin A. Mitchell" Date: Thu, 4 Sep 2025 18:52:17 -0500 Subject: [PATCH 11/11] Add GDPR API call details link in .env.example for clarification --- VB.NET/.env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/VB.NET/.env.example b/VB.NET/.env.example index 409ea2e5..77fcddd0 100644 --- a/VB.NET/.env.example +++ b/VB.NET/.env.example @@ -3,3 +3,4 @@ PDFREST_API_KEY=your_api_key_here # Optional: override the API base URL (e.g., for EU region) # PDFREST_URL=https://eu-api.pdfrest.com +# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work \ No newline at end of file