Next.js Discord

Discord Forum

Security with DB

Unanswered
Masai Lion posted this in #help-forum
Open in Discord
Masai LionOP
Let´s say we need to handle database sorting through an API endpoint, like localhost:3000/api/products?sortBy=price&order=ASC&category=, and we need to always ensure it's done safely while I have to prioritize security. What would be your opinions on handling like this?

49 Replies

Masai LionOP
@DirtyCajunRice | AppDir
Basically I first create a db client from /db/config.ts, then, I made and API that fetches and queries the data based on params src/app/api/products/route.ts, and from that I make a request from a page to get the products and display them
Basically DB > API > PAGE
On the API I handle the query with
const { searchParams } = new URL(request.url);
const sortBy = (searchParams.get('sortBy') as ValidColumn) || 'price';
const order = searchParams.get('order') || 'ASC';
const category = searchParams.get('category') || '';
const keyword = searchParams.get('keyword') || '';
My question is, how "safe" is it to handle the query like this?
and make requests like this:
useEffect(() => {
        async function fetchProducts() {
            const res = await fetch(`/api/products?sortBy=${sortBy}&order=${order}&category=${category}`);
            const sortedProducts = await res.json();
            setFilteredProducts(sortedProducts);
        }
        fetchProducts();
    }, [sortBy, order, category]);
@Masai Lion <@184479429404262410>
got hyper focused. looking now
1. request.nextUrl.searchParams
2. i would personally convert those search params into an object and have zod parse it
3. i NEVER suggest fetching in a useEffect. use a tanstack query
@DirtyCajunRice | AppDir 1. request.nextUrl.searchParams
Masai LionOP
i dont understand...
you mean from the searchParams object?
the new URL(request.url)?
@Masai Lion i dont understand...
const { searchParams } = new URL(request.url);

to
const { searchParams } = request.nextUrl
no need to reinvent the wheel. its already done for you
@DirtyCajunRice | AppDir js const { searchParams } = new URL(request.url); to js const { searchParams } = request.nextUrl
Masai LionOP
but i defined request as Request from 'next/server';
@DirtyCajunRice | AppDir Need to change it to NextRequest. Thats what it really is.
Masai LionOP
alr so i made my zod thingy like this:

const querySchema = z.object({
    sortBy: z.enum(['price', 'name', 'createdAt']).default('price'),
    order: z.enum(['ASC', 'DESC']).default('ASC'),
    category: z.string().optional(),
    keyword: z.string().optional()
});

export async function GET(request: Request) {
    const { searchParams } = new URL(request.url);
    const result = querySchema.safeParse(Object.fromEntries(searchParams.entries()));
}
i need to see
how to change searchParams definition
meanwhile it can stay like it is for a while
Masai LionOP
yay i did it
@DirtyCajunRice | AppDir i literally linked it
Masai LionOP
ye i saw
@DirtyCajunRice | AppDir 3. i NEVER suggest fetching in a useEffect. use a tanstack query
Masai LionOP
now for this... mmm havent used it much, but let me do something from what i remember
@Masai Lion ye i saw
also its generally not smart to do what you did with entries
as params can be entered multiple times and it may come back as a comma list
you should .get each value
@DirtyCajunRice | AppDir you should .get each value
Masai LionOP
with zod entries?
const params = ParamsSchema.parse({  
  tags: searchParams.get('tags'),  
  period: searchParams.get('period'),  
  posts: searchParams.get('posts'),  
});  
if the user can break it, the user WILL break it
leave nothing to chance
@DirtyCajunRice | AppDir ts const params = ParamsSchema.parse({ tags: searchParams.get('tags'), period: searchParams.get('period'), posts: searchParams.get('posts'), });
Masai LionOP
const querySchema = z.object({
    sortBy: z.enum(['price', 'name', 'createdAt']).default('price'),
    order: z.enum(['ASC', 'DESC']).default('ASC'),
    category: z.string().optional(),
    keyword: z.string().optional()
});

export async function GET(request: NextRequest) {
    const url = request.nextUrl.searchParams
    const searchParams = url.searchParams;

    const params = querySchema.parse({
        sortBy: searchParams.get('sortBy') || undefined,
        order: searchParams.get('order') || undefined,
        category: searchParams.get('category') || undefined,
        keyword: searchParams.get('keyword') || undefined,
    });

    const { sortBy, order, category, keyword } = params;
}
this is what i did
you dont need undefined
you can deal with that in the schema
@DirtyCajunRice | AppDir you dont need undefined
Masai LionOP
so queryschema should be deleted
and we stay with params?
wait
… what
Masai LionOP
mmm
i understood now
hold up
ye got it
Masai LionOP
@DirtyCajunRice | AppDir

basically what i did now is uhhh on the client

const [sortBy, setSortBy] = useState<keyof IProduct>('price');
    const [order, setOrder] = useState<'ASC' | 'DESC'>('ASC');
    const router = useRouter();

    const fetchProducts = async () => {
        const res = await fetch(`/api/products?sortBy=${sortBy}&order=${order}&category=${category}`);
        return res.json();
    };

    const { data: filteredProducts = [] } = useQuery({
        queryKey: ['products', sortBy, order, category],
        queryFn: fetchProducts,
    });


im still fetching but using tanstack query, never used it before btw so not sure if its correctly implemented
import { z } from 'zod';

const querySchema = z.object({
    sortBy: z.enum(['price', 'name', 'createdAt']).default('price'),
    order: z.enum(['ASC', 'DESC']).default('ASC'),
    category: z.string().optional(),
    keyword: z.string().optional()
});

export async function GET(request: NextRequest) {
    const searchParams = request.nextUrl.searchParams
    
    const sortBy = searchParams.get('sortBy') || 'price';
    const order = searchParams.get('order') || 'ASC';
    const category = searchParams.get('category') || '';
    const keyword = searchParams.get('keyword') || '';

    const result = querySchema.safeParse({ sortBy, order, category, keyword });


for zod parse I cant make the zod interface inside my db schema cuz it isnt part of it at all, this are just params that have nothing to do with the object. then I get the search params and then I do safeParse to pase the four params.
not sure what else is missing or what might be wrong...