I'm working on developing a public-facing API for our SaaS product, similar to what you might see with payment services like Stripe. Right now, our customers are using the same internal APIs that our frontend relies on, which are quite fragile. They have complex URLs, long identifiers, and even massive payloads, making them difficult to work with.
My goal is to create user-friendly Public APIs with simplified contracts that will eventually replace direct access to our internal UI APIs. However, our backend logic is quite complex, with many microservices and frequent changes. If I create a new Public Data Transfer Object (DTO) that maps to our existing Private DTO and logic, I run into several issues:
1. Modifying the UI logic could easily disrupt the Public contract unless I replicate the entire service layer.
2. Database migrations for new features might break the public-facing API
3. I want both the UI and the Public API to tap into the same core business logic without maintaining completely separate codebases.
What are the best practices in the industry for achieving this? How do I handle the mapping without ending up with a confusing mess of DTO conversions or excessive code duplication?
5 Answers
When I worked on this, we made a completely new API, hosted on a different subdomain. Our controllers were set up to maintain backward compatibility while handling different request schemas and permissions. We ensured that all complicated logic was pushed to the business logic layer to avoid redundancy.
To decouple effectively, make sure your controllers are separated from your services. Your controllers should define the API structure, manage authentication, format responses, and call service methods. If done right, creating a new set of controllers for the public API won't mean duplicating code, as they'll interact with the same business logic beneath it.
It's crucial to maintain compatibility with consumers. If your database changes break the API, you're going to run into problems with your users. For our public API, we have a separate service that interfaces with the main endpoints but ensures sensitive data remains protected. Always give your users notice when you're planning to sunsetting old API versions.
A good method is to implement the API Gateway pattern. This means your public API will have its own contract, separate DTOs, and a mapping layer translating between the public and internal services. Define the public contract first, and ensure to maintain this structure to avoid breaking changes. Implementing contract validation in your CI process can help catch issues before they affect your users.
I suggest starting with a new API for your clients and gradually migratethe existing code away from the old legacy API. Also, implementing versioning early on for your new API can help prevent similar issues in the future.

Related Questions
How To: Running Codex CLI on Windows with Azure OpenAI
Set Wordpress Featured Image Using Javascript
How To Fix PHP Random Being The Same
Why no WebP Support with Wordpress
Replace Wordpress Cron With Linux Cron
Customize Yoast Canonical URL Programmatically