alixi
alixi11mo ago

Public/private function duplication

I’m often finding myself writing two versions of the same function: a public one with a user guard (using convex-helpers custom functions) and an internal one where i pass the user identity in using the arguments. i’ve just been extracting out the handler function so i can use it in both functions, but it’s a lot of boilerplate code and it’s sometimes annoying to have to refactor a bunch of public functions after i realize i also want to call them internally. i was wondering if anyone else has this experience or has any suggestions for a nice way to deal with it?
4 Replies
erquhart
erquhart11mo ago
I felt this a lot until I split my backend into database and api layers, meaning I have a set of files that only handle direct database interactions, and are the only place where ctx.db is used. The rest of my backend formed the api, both public and private. With this setup, most of the reused parts between public and private functions are already split off into that db layer. For me, this has more or less eliminated the dynamic you're describing.
sshader
sshader11mo ago
In a similar vein, when I've written my own Convex apps, I'll put almost all of my logic in functions like function foo(ctx: QueryCtx, args) (or MutationCtx / ActionCtx based on where this function can be used). And then have a very thin layer defining my API (public and internal) with the query / mutation / action wrappers that basically just does argument validation and then calls into one or two of the existing helper functions. This is kind of just proactively doing the refactor to pull out of your logic into a helper For the user identity thing in particular, I might try having two wrappers like publicLoggedInQuery and internalQueryWithUser that both add user to ctx (but the former reading from ctx.auth and the latter reading from arguments) and then making most of my helper functions take in ctx: QueryCtx & { user: User }
alixi
alixiOP11mo ago
Cool, so it sounds like I should be a bit more proactive about organizing my code. my backend codebase isn't too big yet so it shouldn't be too bad to rearrange some things
ian
ian11mo ago
btw there's a type utility in customFunctions called CustomCtx that you can use like CustomCtx<typeof publicLoggedInQuery> for the ctx argument. You can define that once after you define the custom query, so you can just use something like ctx: LoggedInCtx in your helper functions.

Did you find this page helpful?