Organization of server actions
Unanswered
Sun bear posted this in #help-forum
Sun bearOP
How do people organize their various server actions?
Generally I try to build things so that everything to do with a "module" is in one place, so like if a server action was specific to a form on a certain page then it would make sense to me to place it in the same directory as all the other stuff to do with that form.
However I'm worried that server actions are a special case, since each one technically opens up a publicly accessible API in your application. It seems like if code that runs privileged on the server was scattered all over the code base, it would be hard to keep track of what the various endpoints can do and make sure they all have correct security / permissions checking etc. This seems especially problematic in a large team where you'd end up with actions scattered all over the place.
would it be better to just collect them all in a single directory like "actions"? š¤
Generally I try to build things so that everything to do with a "module" is in one place, so like if a server action was specific to a form on a certain page then it would make sense to me to place it in the same directory as all the other stuff to do with that form.
However I'm worried that server actions are a special case, since each one technically opens up a publicly accessible API in your application. It seems like if code that runs privileged on the server was scattered all over the code base, it would be hard to keep track of what the various endpoints can do and make sure they all have correct security / permissions checking etc. This seems especially problematic in a large team where you'd end up with actions scattered all over the place.
would it be better to just collect them all in a single directory like "actions"? š¤
12 Replies
i use a (series of) higher order functions, something like this
export function createAuthenticatedAction<T, P extends unknown[] = []>(
callback: (...data: P) => T | Promise<T>,
): (...data: P) => Promise<T> {
return async (...data: P) => {
const auth = await getAuth()
if (!auth.user) redirect(...);
const result = await callback(...data);
};
}
export const updateName = createAuthenticatedAction(async (name: string) => ...);
perhaps decorators would work too, though i never tried that approach
you can customise the function signature and behaviour of these HOFs in any way you want
š .... hippity hoppity, your code is now my property
was thinking of the "authed" actions just right now
nest them together
this is code i wrote for my company though so i can't copy-paste it here for you, this is left as an exercise for the readers
Sun bearOP
and with that pattern you're also colocating the actions with the clientside code that needs them? part of what im struggling with right now is the sense that because there's a fuzzy boundary between the client and server its hard to keep track of what code is intended just for the server, and where that code is. That includes things like utilities
you can just have all the server actions in
lib/actions.ts
file or something similar, and add 'use server'
at the topatleast that's how I do it
Sun bearOP
would be kind of nice to have an IDE plugin that like colours a file differently if it detects it is part of the server-only bundle or not..