worksome/exchange
Currency exchange for Laravel: convert money between currencies through a clean, driver-based API. Swap exchange-rate providers, cache rates, and keep conversion logic testable and framework-friendly.
Architecture fit
worksome/exchange is a Laravel-oriented currency exchange package built around a driver abstraction (exchange-rate providers) and a Rates value object returned to the application. It slots in as an infrastructure dependency at the service layer: application code asks the package for a Rates instance and consumes base currency, rate map, and retrieval timestamp. This is a good fit for Laravel apps that need quoted FX rates without building provider adapters themselves; it is not an accounting/ledger library, so rounding, precision policy, and rate-source auditability remain our responsibility.
Integration feasibility
Low-to-moderate. Installation is standard Composer + published config, and the driver model means we can select or swap providers via configuration. The main effort in v3.0.0 is mechanical but repo-wide: three deprecated accessors were removed and replaced by public properties on the Rates object. Any call site using method syntax will now fatal rather than warn, so the upgrade is gated on a complete call-site inventory.
Breaking changes in v3.0.0
| Removed (v2.x) | Replacement (v3.0.0) | Risk |
|---|---|---|
$rates->getBaseCurrency() |
$rates->baseCurrency |
Fatal error at runtime if missed |
$rates->getRates() |
$rates->rates |
Fatal error at runtime if missed |
$rates->getRetrievedAt() |
$rates->retrievedAt |
Fatal error at runtime if missed |
Additional changes:
frankfurter driver now targets v2. Self-hosted Frankfurter deployments must expose v2 and update FRANKFURTER_BASE_URL from the /v1 to the /v2 endpoint — an environment/config change that will fail at runtime, not at install time.frankfurter_v2 driver: a parallel driver was introduced before the default driver was switched. This gives a transitional path but also means the codebase may temporarily carry two Frankfurter drivers — worth confirming which one we should standardize on.Rates payloads, the resulting JSON/type may differ from v2.x.dependabot/fetch-metadata): no runtime impact.Technical risk
Key questions
Rates objects cached, queued as serialized payloads, or persisted? If so, does the property/float change alter the serialized contract?=== rate values anywhere that a float cast could disturb?frankfurter (v2) or frankfurter_v2, and is the latter intended as a temporary shim?Stack fit Standard Laravel package integration: Composer dependency, auto-discovered service provider, publishable config for driver and credentials, and an environment variable for the Frankfurter base URL. No new infrastructure is required unless we want a caching layer in front of the provider calls, which we should own.
Migration path
Rates is serialized, cached, queued, or logged; confirm the property-based shape and float cast are acceptable, or add an explicit mapping/DTO at our boundary.FRANKFURTER_BASE_URL from /v1 to /v2 in every environment that points at a self-hosted instance, and verify the endpoint is reachable before deploying code.^3.0, run the full suite, and do a rate-parity spot check against v2.x output for a handful of currency pairs.Compatibility
The getter removal is not shim-able from our side without wrapping the Rates object; if a staged rollout is required, introduce a thin internal adapter over Rates first (in v2.5.x) so that the v3 bump only touches the adapter. The Frankfurter base URL change is a deploy-order concern: code and configuration must move together, and a rollback must revert both.
Sequencing
Pin 2.5.x as the known-good baseline → land the internal adapter / call-site migration while still on v2 → optionally trial the frankfurter_v2 driver in staging to de-risk the API change → coordinate the FRANKFURTER_BASE_URL cutover with the v3 deploy → validate rates and caching behavior in staging → release to production with a rollback plan that includes the config revert.
Maintenance
Low ongoing footprint, but this release is a forcing function: the maintainers are consolidating the public API surface, and the property-based Rates object is likely the stable contract going forward. The dependabot activity and small contributor base suggest active but lean maintenance — budget for periodic minor upgrades rather than assuming long-term API stability. The short-lived coexistence of frankfurter and frankfurter_v2 drivers should be treated as transitional; expect one to be deprecated.
Support Community-supported, no commercial SLA. Our exposure is an external FX provider dependency plus package-maintainer responsiveness. For anything rate-critical (invoicing, pricing, settlement), we should treat the package as a convenience adapter and retain our own fallback source and audit trail.
Scaling
Rate retrieval is an outbound HTTP call per request unless we cache. At any meaningful traffic volume, we must cache Rates with a TTL that matches business tolerance for stale FX, and add a fallback driver or last-known-good cache for provider outages. The float cast on base currency is worth noting for high-precision or high-volume financial calculations — prefer decimal arithmetic downstream.
Failure modes
/v1, or where v2 is unreachable.Rates payloads were written under v2.x.Ramp-up Low for a developer familiar with Laravel: one package, one config file, one value object. The real ramp-up cost is organizational — ensuring every team that consumes exchange rates knows the getters are gone and that the Frankfurter base URL is an environment-level dependency requiring coordinated change. A short internal note plus a static-analysis rule blocking the deprecated getters is sufficient to prevent recurrence.
How can I help you explore Laravel packages today?