pkg_dpd_api_client
A Dart client for DPD (Dynamic Parcel Distribution) SOAP services. It focuses on:
- Building and parsing requests/responses for Shipment, Parcel Lifecycle, and Parcel Shop Finder services.
- Normalizing errors into consistent ModelDpdError instances with DpdErrorCode mapping.
- Hermetic unit tests for parsing/mapping logic without requiring network or environment files.

This package is part of a monorepo and depends on pkg_core via a relative path. Consumers should import the single library entry:
import 'package:pkg_dpd_api_client/pkg_dpd_api_client.dart';
Features
- Rich models for request/response payloads across DPD domains.
- Centralized error handling via DpdErrorHandler and ModelDpdError.
- Resilient SOAP fault parsing using package:xml with namespace-agnostic handling.
- Logging helpers with optional file logging (disabled by default) and secret redaction.
- Well-defined public API - see Public API Guidelines for stable vs internal APIs.
Quick start (contributors)
- Ensure Dart 3.8.x and that ../pkg_core exists and is resolvable.
- From repo root: dart pub get
- Run unit tests: dart test -r expanded (tests are hermetic; no network or .env required)
- Make changes; keep tests focused on parsing/mapping/model behavior.
Usage (library consumers)
- Import the single entrypoint and use services/models as needed.
- Error handling: catch and inspect ModelDpdError; use isRetryable/isAuthenticationError helpers.
- Important: Only use the documented public APIs. See Public API Guidelines for details on what's stable.
Public API Overview
Main Services:
DpdClientFactory - Create service instances with managed HTTP client
DpdShipmentService - Shipment operations
DpdParcelLifecycleService - Tracking and label retrieval
DpdParcelShopFinderService - Find parcel shops
DpdLoginService - Authentication
Utilities:
AddressRequestBuilder - Build addresses with phone validation
DpdErrorHandler - Error normalization
LoggingUtil - Logging setup
Result<T, E> - Safe error handling
Models & Enums:
- All request/response models
- All enums (order types, country codes, etc.)
See Public API Guidelines for complete details and usage examples.
Example (error mapping only, no network):
import 'package:pkg_dpd_api_client/pkg_dpd_api_client.dart';
void main() {
final err = ModelDpdError(message: 'Service unavailable');
if (err.isRetryable) {
// backoff and retry
}
}
Environment variables (for the example app)
The CLI/example at example/pkg_dpd_api_client_example.dart requires a local assets/.env. Do not use these in unit tests.
Common flags:
- DPD_TEST_ENVIRONMENT: true/false to select test vs live endpoints.
Test environment variables (used when DPD_TEST_ENVIRONMENT=true):
- DPD_DELISID_TEST: Test DelisID (username)
- DPD_PASSWORD_TEST: Test password
- DPD_LOGIN_SERVICE_ENDPOINT_TEST: Login service WSDL/SOAP endpoint
- DPD_PARCEL_SHOP_FINDER_SERVICE_ENDPOINT_TEST: Parcel Shop Finder SOAP endpoint
- DPD_PARCEL_LIFECYCLE_SERVICE_ENDPOINT_TEST: Parcel Lifecycle SOAP endpoint
- DPD_SHIPMENT_SERVICE_ENDPOINT_TEST: Shipment SOAP endpoint
- DPD_HHP_DEPOT_NUMBER: Depot number (required for shipments)
- DPD_MESSAGE_LANGUAGE: Two-letter language code (e.g., EN, NL)
- DPD_HHP_EORI_NUMBER: EORI number for HHP
- DPD_HHP_VAT_NUMBER: VAT number for HHP
- DPD_HHP_IBAN_NUMBER: IBAN for HHP
- DPD_HHP_KVK_NUMBER: Chamber of Commerce/registration (KvK) number for HHP
- DPD_HHP_GLN_NUMBER: GLN number for HHP
- DPD_APS_EORI_NUMBER: Optional APS EORI number
- DPD_APS_VAT_NUMBER: Optional APS VAT number
Live environment variables (used when DPD_TEST_ENVIRONMENT=false):
- DPD_DELISID: Live DelisID
- DPD_PASSWORD: Live password
- DPD_LOGIN_SERVICE_ENDPOINT: Login service endpoint
- DPD_PARCEL_SHOP_FINDER_SERVICE_ENDPOINT: Parcel Shop Finder endpoint
- DPD_PARCEL_LIFECYCLE_SERVICE_ENDPOINT: Parcel Lifecycle endpoint
- DPD_SHIPMENT_SERVICE_ENDPOINT: Shipment endpoint
Notes:
- Keep assets/.env out of version control (do not commit secrets).
- The example prints logs to console by default. File logging can be enabled explicitly via LoggingUtil (enableFileLogging=true).
Example (manual) prerequisites
The example at example/pkg_dpd_api_client_example.dart is intended for manual/local runs only and is not used by unit tests.
Prerequisites:
- Create assets/.env with valid DPD credentials and endpoints (see variables above). Do not commit secrets.
- Ensure network access to the configured endpoints.
- Optionally enable file logging if you want logs written under logs/.
Expected behavior:
- With assets/.env present, the example logs environment load status and subsequent service interactions to console (and optionally to logs/ when enabled).
- On missing assets/.env, the example exits with a non-zero code after logging a fatal message.
Developer docs
- Error mapping policy: see docs/error_mapping.md
Example flags
- --dry-run: Build and print the StoreOrders XML payload without loading assets/.env or performing any network calls.
- --save-labels: When not in --dry-run mode, opt-in to saving generated label PDFs to assets/labels.
Usage examples:
- dart run example/pkg_dpd_api_client_example.dart --dry-run
- dart run example/pkg_dpd_api_client_example.dart --save-labels
Tooling pin (optional)
If you use asdf, this repository includes a .tool-versions file pinning Dart 3.8.1. You can also use fvm to pin Dart 3.8.x if preferred.
Error surface: throw vs Result
- Services throw ModelDpdError on failures. Inspect errorCode, httpStatusCode, message, and helpers like isRetryable/isAuthenticationError.
- For non-throwing ergonomics, use DpdShipmentService Result-returning methods (Ok/Err):
final svc = DpdShipmentService(config, httpClient);
final res = await svc.storeOrdersResult(request: req);
res.switch(
(ok) => print('stored: ${ok.storeOrders}'),
(err) => print('error: ${err.errorCode} ${err.message}'),
);
- Low-level services (StoreOrderService, ExportOrderService, etc.) throw ModelDpdError; orchestrator exposes Result variants.
- Network calls and retries are centralized. postWithRetry maps exceptions and 5xx responses to ModelDpdError; services add context so errors are traceable.