Should I use API route or server action to fetch data on client (stripe customer's cards info)?
Answered
Nebelung posted this in #help-forum
NebelungOP
If in client component I need to make a call to Stripe API to display customer's cards in a dialog should I fetch it using server actions or API route or maybe something completely different? I don't want to fetch this in server component because i don't want to make a call to this api on every page refresh.
i tried with api route but passing stripe customer id like this seems to me a bit dangerous:
In stripe/api/route I tried this:
thank you for help
i tried with api route but passing stripe customer id like this seems to me a bit dangerous:
const response = await fetch(
`/api/stripe/route?customerId=${stripeCustomerId}`
);In stripe/api/route I tried this:
export async function GET(req: Request) {
cookies();
// pass customerId to the function retrievePaymentMethods
// GOAL: call retrievePaymentMethods from stripe/server.ts file to get payment methods
const url = new URL(req.url);
const customerId = url.searchParams.get('customerId');
if (!customerId) {
return new Response('Customer ID is required', { status: 400 });
}
try {
const paymentMethods = await retrievePaymentMethods(customerId);
return new Response(JSON.stringify(paymentMethods), {
status: 200,
headers: {
'Content-Type': 'application/json'
}
});
} catch (error) {
return new Response(error.message, { status: 500 });
}
}thank you for help
Answered by Ray
yes, it can be used with
useEffect and event handler too but it make a POST request instead of GET17 Replies
Entlebucher Mountain Dog
is
retrievePyamentMethods() server action? then you call this action in server component.NebelungOP
It's a function calling to stripe.
export async function retrievePaymentMethods(customerId: string) {
try {
const paymentMethods =
await stripe.customers.listPaymentMethods(customerId);
console.log('Payment methods from server stripe', paymentMethods);
return paymentMethods;
} catch (error) {
console.error(error);
throw new Error('Could not retrieve payment methods.');
}
}But how do I call this function if I want to on button "Show used cards" click fetch this data?
I have it like this atm:
I have it like this atm:
'use client'
...
export default function BillingInfo(stripeCustomerId) {
...
const handleDisplayPaymentMethods = async () => {
// fetch data
}
}
return (
<DialogTrigger>
<Button
variant="slim"
loading={isSubmitting}
onClick={(e) => handleDisplayPaymentMethods(e)}
>
Update payment method
</Button>
</DialogTrigger>
...
)
}I feel like I'm overcomplicating the problem.
This should be done without api route, right?
This should be done without api route, right?
const handleDisplayPaymentMethods = async () => {
// safely fetch data from stripe
const data = await retrievePaymentMethods(stripeCustomerId);
console.log('data', data);
};retrievePaymentMethods function is executed only on the server.
@Nebelung But how do I call this function if I want to on button "Show used cards" click fetch this data?
I have it like this atm:
'use client'
...
export default function BillingInfo(stripeCustomerId) {
...
const handleDisplayPaymentMethods = async () => {
// fetch data
}
}
return (
<DialogTrigger>
<Button
variant="slim"
loading={isSubmitting}
onClick={(e) => handleDisplayPaymentMethods(e)}
>
Update payment method
</Button>
</DialogTrigger>
...
)
}
Entlebucher Mountain Dog
you need to make a server component to run server action
NebelungOP
I don't think that's true. From nextjs docs:
Server Actions are asynchronous functions that are executed on the server. They can be used in Server and Client Components to handle form submissions and data mutations in Next.js applications.
Entlebucher Mountain Dog
yes, it is. and server action runs only on server side too.
NebelungOP
i wasn't sure if server actions aren't meant only for forms or not but sounds like it's valid to use them. they seem to be easier to write so i'll stick with it. thank you @Ray
@Nebelung i wasn't sure if server actions aren't meant only for forms or not but sounds like it's valid to use them. they seem to be easier to write so i'll stick with it. thank you <@743561772069421169>
yes, it can be used with
useEffect and event handler too but it make a POST request instead of GETAnswer
NebelungOP
I think the retrievePaymentMethods will be making POST request because it's a server action.
Where exactly would you use useEffect?
Where exactly would you use useEffect?
'use client'
...
export default function BillingInfo(stripeCustomerId) {
...
const handleDisplayPaymentMethods = async () => {
// safely fetch data from stripe (retrievePaymentMethods is server action)
try {
const data = await retrievePaymentMethods(stripeCustomerId);
if (data.length > 0 ) {
setPaymentMethods(data.map((method) => method.card.brand));
}
} catch (error) {
console.error('Failed to retrieve payment methods:', error);
}
// [
// {
// billing_details: {...},
// card: {brand: 'visa'}
// }
// ]
}
}
return (
<DialogTrigger>
<Button
variant="slim"
loading={isSubmitting}
onClick={(e) => handleDisplayPaymentMethods(e)}
>
Update payment method
</Button>
</DialogTrigger>
...
<DialogDescription>
<ul className="">
{paymentMethods.length > 0 ? (
paymentMethods.map((brand, index) => (
<li key={index}>Card: {brand}</li>
))
) : (
<li>Loading...</li>
)}
</ul>
</DialogDescription>
)
}NebelungOP
but it works already with onClick and the data is returned correctly from the api call.
@Nebelung but it works already with onClick and the data is returned correctly from the api call.
yea I meant server action can be used with
useEffect or event handlerand also form
NebelungOP
ahh okay, thank you