What We Are Going To Cover Today
- Idea Of Dependency Inversion
- Problem/Solution With Payment Gateways Stripe/Paypal
- Real Scenario You Can use in your E-commerce Project
Dependency inversion
- High level Modules should not depend on low level modules Both Should Depend on Abstraction
- Or We Can Say Any higher classes should always depend upon the abstraction of the class rather than the detail.
From This Definition We Can Say That
We Just want Our Code Depends On The Wrapper We Created Not The Actual Implementation Of Dependency We're Using
The Problem We Have
- Change Payment Gateway From Stripe >> Paypal Will Be Very Hard and We Will Change tons Of Code
- Our Code Depends on the Actual Implementation Of The Payment Service and This Going to be Hard to Maintain
- Testing Everything From Scratch Again
- Making any Transaction Going To Be Really Hard to Trace Later
Solution
- Create Intermediate Layer This Layer Going to Be Wrapper Around Payment Gateway Services
- e.g StripeServiceWrapper, PaypalServiceWrapper
- So We Just Abstract the Payment Gateways Idea Using These Wrappers it's
- Our Code Now Depends On These Wrappers Not The Actual Implementation Of Dependency We're Using
Let's Start By Some Code Snippets
Payment Store
Here We Are Going to Inject The Wrapper And Makes The Transaction With Anyone We Want Easily
import PaymentService from "./PaymentService";
class PaymentStore {
constructor(paymentWrapper) {
this.paymentWrapper = paymentWrapper;
this.paymentService = new PaymentService();
}
async makeTransaction(chargeData) {
const charge = await this.paymentWrapper.createCharge(chargeData);
await this.paymentService.addNewCharge(charge);
return charge;
}
}
export default PaymentStore;
Stripe Wrapper
import Stripe from "stripe";
import mockPayment from "./Stripe/mockPayment";
class StripeServiceWrapper {
constructor() {
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
}
async createCharge() {
const { amount, currency, description, source } = mockPayment;
const charge = await this.stripe.charges.create({
amount,
currency,
description,
source,
});
return charge;
}
async createCustomer(customerData) {
const { name, email, source, address, phone } = customerData;
const customer = await stripe.customers.create({
address,
name,
email,
phone,
source,
});
return customer;
}
}
export default StripeServiceWrapper;
Paypal Wrapper
import paypal from "paypal-rest-sdk";
import "./PayPal/PayPalConfig";
class PayPalServiceWrapper {
createCharge({ payment_object, paymentId }) {
return new Promise(function (resolve, reject) {
paypal.payment.execute(paymentId, payment_object, function (error, payment) {
if (error) reject(error);
else {
const { id, transactions } = payment;
resolve({ id, amount: parseInt(transactions[0].amount.total) });
}
});
});
}
paymentExecutionLink(paymentObject) {
return new Promise(function (resolve, reject) {
paypal.payment.create(paymentObject, function (error, payment) {
if (error) reject(error);
else resolve(payment);
});
});
}
getRedirectLink(links) {
for (let i = 0; i < links.length; i++) {
if (links[i].rel === "approval_url") return links[i].href;
}
}
}
export default PayPalServiceWrapper;
So Now At Our Controller It's Going to Be Very Easy To Switch From Stripe To Paypal
const post = async (req, res) => {
const store = new PaymentStore(new StripeServiceWrapper());
await store.makeTransaction();
return res.status(200).send({SUCCESS_MESSAGE});
};
You Can Find The Code And How to Start Easy At
https://github.com/eslamelkholy/Payment-Gateway-Stripe-Paypal-Using-Dependency-Inversion
References
https://en.wikipedia.org/wiki/Dependency_inversion_principle
https://www.geeksforgeeks.org/dependecy-inversion-principle-solid/
https://dev.to/educative/s-o-l-i-d-principles-of-object-oriented-programming-in-c-2m98#dependency
Top comments (0)