Request Query Parameters
Comprehensive Query Parameter Transformation
Arkos provides a sophisticated mechanism to transform URL query parameters into full-featured Prisma queries. Here's a detailed breakdown of how query parameters are translated:
1. Basic Filtering Transformation
GET /api/users?age=25&status=active
Translates to Prisma query:
const users = await prisma.user.findMay({
where: {
OR: [{ age: 25 }, { status: "active" }];
}
})
2. Comparison Operators Mapping
GET /api/products?price[gte]=50&price[lt]=100
Prisma equivalent:
const products = await prisma.product.findMany({
where: {
price: {
gte: 50,
lt: 100,
},
},
});
3. Advanced Search Mechanism
The search functionality dynamically builds searchable fields:
GET /api/users?search=john
Generates a Prisma query that searches across all string fields but the ones that ends in id, ids, ID, IDs because they are not searchable as simple strings:
const users = await prisma.user.findMany({
where: {
OR: [
{ name: { contains: "john", mode: "insensitive" } },
{ email: { contains: "john", mode: "insensitive" } },
// other string fields
];
}
})
4. Pagination
This allows you to seamlessly query you endpoints with pagination
GET /api/products?page=4
Translates to:
const products = await prisma.products.findMany({
take: 30,
skip: 90, // limit (default 30) * page - 1
});
If you want to take more records or even less recors do:
GET /api/products?page=4&limit=100
Translates to:
const products = await prisma.products.findMany({
take: 100,
skip: 300,
});
5. Limiting
The limiting feature controls how many records are returned in the response. It works in conjunction with pagination.
By default, queries return 30 records. You can change this using the limit
parameter:
GET /api/products?limit=10
Translates to:
const products = await prisma.product.findMany({
take: 10,
});
Limit with Pagination
When combining limit with pagination, the limit determines how many records are returned per page:
GET /api/products?page=2&limit=50
Translates to:
const products = await prisma.product.findMany({
take: 50,
skip: 50, // (page - 1) * limit = (2 - 1) * 50
});
Limit Range
You can use any positive integer for the limit. Common examples:
GET /api/products?limit=5 // Returns 5 records
GET /api/products?limit=100 // Returns 100 records
GET /api/products?limit=1 // Returns 1 record
Combining Sorting and Limiting
These features work seamlessly together:
GET /api/products?sort=-price&limit=10
This returns the 10 most expensive products:
const products = await prisma.product.findMany({
orderBy: [{ price: "desc" }],
take: 10,
});
Full Example with All Features
GET /api/products?search=laptop&price[gte]=500&sort=-rating,-price&page=1&limit=20&fields=id,name,price,rating
This complex query will:
- Search for 'laptop' in string fields
- Filter products with price >= 500
- Sort by rating (descending), then price (descending)
- Get the first page with 20 items
- Return only id, name, price, and rating fields
Translates to:
const products = await prisma.product.findMany({
where: {
OR: [
{ name: { contains: "laptop", mode: "insensitive" } },
{ description: { contains: "laptop", mode: "insensitive" } },
// other string fields
{ price: { gte: 500 } },
],
},
orderBy: [{ rating: "desc" }, { price: "desc" }],
skip: 0,
take: 20,
select: {
id: true,
name: true,
price: true,
rating: true,
},
});
6. Sorting
The sorting feature allows you to order results by one or more fields in ascending or descending order.
Basic Sorting (Ascending)
GET /api/products?sort=price
Translates to:
const products = await prisma.product.findMany({
orderBy: [{ price: "asc" }],
});
Descending Sort
To sort in descending order, prefix the field name with a minus sign -
:
GET /api/products?sort=-price
Translates to:
const products = await prisma.product.findMany({
orderBy: [{ price: "desc" }],
});
Multiple Field Sorting
You can sort by multiple fields using comma separation. The order matters - the first field is the primary sort, the second is the secondary sort, and so on:
GET /api/products?sort=-price,name
This will first sort by price in descending order, then by name in ascending order:
const products = await prisma.product.findMany({
orderBy: [{ price: "desc" }, { name: "asc" }],
});
Complex Sorting Example
GET /api/users?sort=-createdAt,lastName,firstName
Translates to:
const users = await prisma.user.findMany({
orderBy: [{ createdAt: "desc" }, { lastName: "asc" }, { firstName: "asc" }],
});
This will:
- Sort by creation date (newest first)
- Then by last name alphabetically
- Finally by first name alphabetically
5. Selecting, Adding And Removing Fields
5.1. Selecting
This allows you to whether take just some fields of the desired record, let's say a product model with id
, name
, description
, price
, color
, weight
, and instead of taking all the fields when querying, you can only take for example name
and price
depending of your needs
GET /api/products?fields=name,price
Translates to:
const products = await prisma.products.findMany({
select: {
name: true,
price: true,
},
});
5.2. Adding
To add fields that are not default selected to the end result, we must simple prefix the desired field with plus symbol +
:
GET /api/products?fields=+reviews
Will select all default fields + reviews
. Translates to:
const products = await prisma.products.findMany({
include: {
reviews: true,
},
});
5.3. Removing
To remove some fields from the end result, let's instead of naming all the fields you want you can just takeout the one you don't want:
GET /api/products?fields=-name,-price
Will select all the other fields but name
and price
. Translates to:
const products = await prisma.products.findMany({
include: {
name: false,
price: false,
},
});
Complex Querying Capabilities
6. Nested and Relational Filtering
GET /api/posts?author[age]=30&comments[some][content][contains]=interesting
Translates to:
const posts = await prisma.post.findMany({
where: {
OR: [
{
author: {
age: "30",
},
},
{
comments: {
some: {
content: {
contains: "interesting",
},
},
},
},
],
},
});
7. Logical Operator Control
The filterMode
parameter allows switching between OR
and AND
logic:
GET /api/users?filterMode=AND&age=25&status=active
Produces:
const users = await prisma.user.findMany({
where: {
AND: [{ age: 25 }, { status: "active" }];
}
})
Advanced Query Composition
8. Combining Multiple Query Features
GET /api/products?search=wireless&price[gte]=50&price[lt]=200&sort=-price&page=2&limit=10&fields=id,name,price,+reviews
This complex query would:
- Search for 'wireless' across string fields
- Filter products between 50 and 200
- Sort by price in descending order
- Paginate to the second page
- Limit to 10 results
- Return only specific fields: id, name and price. Noticed
+reviews
is because it is not default selected so we're adding it.
And it produces:
const products = await prisma.product.findMany({
where: {
OR: [
{
name: {
contains: "wireless",
mode: "insensitive",
},
},
{
description: {
// Let's say our Product model have description
// field which is String search=wireless will
// search the text in all string fields but
// id fields.
contains: "wireless",
mode: "insensitive",
},
},
{
price: {
gte: 50,
lt: 200,
},
},
],
orderBy: {
price: "desc",
},
skip: 10,
take: 10,
select: {
id: true,
name: true,
price: true,
reviews: true,
},
},
});
9. Custom Prisma Query Extension
You can extend queries with raw Prisma options:
GET /api/users?prismaQueryOptions={"include":{"posts":true}}&age=25
Generates:
const users = await prisma.user.findMany({
where: {
where: { age: 25 },
include: { posts: true },
},
});
This is disabled
by default for securites reasons because it allows end users not make raw prisma query which can be dangeours to your application, you is it if you really now what you are doing. We Recommend Not To Enabled This Option
.
A better way to use this is trough prisma-query-options
files that will only use this parameter on your code level for you to customize the default behavior of your prisma queries that are handled automatically by Arkos, you can read more about.
By the way, if you would like to activate the request query paramenter allowDangerousPrismaQueryOptions
do the following under your src/app.ts
:
import arkos from "arkos";
// your other codes
arkos.init({
request: {
parameters: {
allowDangerousPrismaQueryOptions: true, // (default is false)
},
},
// other configurations
});
10. Querying Like Django
As Arkos to easy developers lifes, there is a easier way to write the all this query parameters we've seen so far, this was inspired from the Django Framework
:
So instead of writing the query params as we did before in all previous examples we can write it differently, example translating the 8. Combining Multiple Query Features to this other style:
Instead of this:
GET /api/products?search=wireless&price[gte]=50&price[lt]=200&sort=-price&page=2&limit=10&fields=id,name,price,+reviews
You can write like this:
GET api/products?search=wireless&price__gte=50&price__lt=200&sort=-price&page=2&limit=10&fields=id,name,price,+reviews
And it will produce the same query as in 8. Combining Multiple Query Features.
How this actually works? see here.
You can use both approaches at the same time, it will work seamlessly.
Security and Performance Considerations
- All query parameters are securely parsed
- Unexpected parameters are safely filtered
- The system prevents potential injection attacks
- Supports complex querying with minimal to no performance overhead
Supported Query Parameters
search
: Full-text search across string fields- everything goes in
where prisma query
sort
: Multi-field sortingpage
,limit
: Paginationfields
: Fields selecting, adding and removingfilterMode
: Logical operator controlprismaQueryOptions
: Raw Prisma query extension
Best Practices
- Always use filtering for precise data retrieval
- Leverage search for flexible content finding
- Use pagination to manage large datasets
- Select only required fields to optimize performance