CodeWithAntonio
CodeWithAntonio
CCConvex Community
Created by CodeWithAntonio on 1/13/2024 in #support-community
Clerk Auth in Route Handlers
Hi everyone 👋 I need help for a pretty specific edge case. A third party library which I use alongside Convex needs to generate an authentication token by using NextJS route handlers endpoint. Lets call this /api/third-party-auth In this route handler, which is a POST request, I need to have access to currently logged in user. I know I can access convex instance using the following: const convex = new ConvexHttpClient(process.env.NEXT_PUBLIC_CONVEX_URL!); But I am not sure if I can use that to access current auth. This is usualy accessible with @clerk/nextjs package, but as far as I understand, for Convex + Clerk we use @clerk/react package instead, and then we access "backend" auth using ctx.identity How would I solve this specific issue? Here are a couple of things that come to mind: - Add @clerk/nextjs & middleware.ts (I have a feeling this will break things) - convex/http (I tried this, but did not really understand if I can test this out locally?) - getToken I see this popping up in discord searches, but do not really understand how I should approach it. My main goal is to get access to user ID inside route handler (I also need user organization ID, but I will debug that later) Thanks!
21 replies
CCConvex Community
Created by CodeWithAntonio on 1/9/2024 in #support-community
Reuseable query hook
Hi everyone 👋 Looking into some best practices for reusing mutations and queries. Primarily so I don't have to import from _generated/api every time I need a query/mutation, but also to reuse some states like loading or reuse some toast notifications on mutations. Saw this message as an example of what folks do: https://discord.com/channels/1019350475847499849/1151937233616646286/1151960378486566962 So I am sharing my simple example here, is this OK, is there any new practice you would recommend for creating reuseable queries? 🙂
import { useQuery } from "convex/react";

import { api } from "@/convex/_generated/api";

interface UseQueryBoardsProps {
orgId: string;
};

export const useQueryBoards = ({
orgId,
}: UseQueryBoardsProps) => {
const data = useQuery(api.boards.getBoards, { orgId });

const loading = data === undefined;

return {
data,
loading,
};
};
import { useQuery } from "convex/react";

import { api } from "@/convex/_generated/api";

interface UseQueryBoardsProps {
orgId: string;
};

export const useQueryBoards = ({
orgId,
}: UseQueryBoardsProps) => {
const data = useQuery(api.boards.getBoards, { orgId });

const loading = data === undefined;

return {
data,
loading,
};
};
5 replies
CCConvex Community
Created by CodeWithAntonio on 9/30/2023 in #support-community
Authorized queries & mutations (patch, delete, get)
No description
6 replies
CCConvex Community
Created by CodeWithAntonio on 9/30/2023 in #support-community
Recursive query performance
Hi again 👋 I am working on a Notion clone, currently focusing on the sidebar element. Which looks like this: https://imgur.com/itFF5qX My schema for this entity is as follows:
export default defineSchema({
documents: defineTable({
title: v.string(),
userId: v.string(),
isArchived: v.boolean(),
parentDocument: v.optional(v.id("documents")),
content: v.optional(v.string()),
})
.index("by_user_id", ["userId"])
});
export default defineSchema({
documents: defineTable({
title: v.string(),
userId: v.string(),
isArchived: v.boolean(),
parentDocument: v.optional(v.id("documents")),
content: v.optional(v.string()),
})
.index("by_user_id", ["userId"])
});
As you can see, documents which are created at the top level have undefined as their parentDocument field, where children have a proper relation with their parent. This is my API to fetch both parent documents, or child documents if I provide a parentDocument argument:
export const get = query({
args: {
parentDocument: v.optional(v.id("documents")),
isArchived: v.optional(v.boolean()),
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();

if (!identity) {
throw new Error("Not authenticated");
}

const userId = identity.subject;

const documents = await ctx.db
.query("documents")
.withIndex("by_user_id", (q) => q.eq("userId", userId))
.filter((q) =>
q.and(
q.eq(q.field("isArchived"), !!args.isArchived),
q.eq(q.field("parentDocument"), args.parentDocument),
)
)
.order("desc")
.collect();

return documents;
},
});
export const get = query({
args: {
parentDocument: v.optional(v.id("documents")),
isArchived: v.optional(v.boolean()),
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();

if (!identity) {
throw new Error("Not authenticated");
}

const userId = identity.subject;

const documents = await ctx.db
.query("documents")
.withIndex("by_user_id", (q) => q.eq("userId", userId))
.filter((q) =>
q.and(
q.eq(q.field("isArchived"), !!args.isArchived),
q.eq(q.field("parentDocument"), args.parentDocument),
)
)
.order("desc")
.collect();

return documents;
},
});
I will continue in the additional comments because the message is too long 😅
23 replies