Skip to main content
Version: v4

REST Querying

Harper's REST interface supports a rich URL-based query language for filtering, sorting, selecting, and limiting records. Queries are expressed as URL query parameters on collection paths.

Basic Attribute Filtering

Search by attribute name and value using query parameters. The queried attribute must be indexed.

GET /Product/?category=software

Multiple attributes can be combined — only one needs to be indexed for the query to execute:

GET /Product/?category=software&inStock=true

Null Queries

Added in: v4.3.0

Query for null values or non-null values:

GET /Product/?discount=null

Note: Only indexes created in v4.3.0 or later support null indexing. Existing indexes must be rebuilt (removed and re-added) to support null queries.

Comparison Operators (FIQL)

Harper uses FIQL syntax for comparison operators:

OperatorMeaning
==Equal
=lt=Less than
=le=Less than or equal
=gt=Greater than
=ge=Greater than or equal
=ne=, !=Not equal
=ct=Contains (strings)
=sw=, ==<value>*Starts with (strings)
=ew=Ends with (strings)
=, ===Strict equality (no type conversion)
!==Strict inequality (no type conversion)

Examples:

GET /Product/?price=gt=100
GET /Product/?price=le=20
GET /Product/?name==Keyboard*
GET /Product/?category=software&price=gt=100&price=lt=200

For date fields, colons must be URL-encoded as %3A:

GET /Product/?listDate=gt=2017-03-08T09%3A30%3A00.000Z

Chained Conditions (Range)

Omit the attribute name on the second condition to chain it against the same attribute:

GET /Product/?price=gt=100&lt=200

Chaining supports gt/ge combined with lt/le for range queries. No other chaining combinations are currently supported.

Type Conversion

For FIQL comparators (==, !=, =gt=, etc.), Harper applies automatic type conversion:

SyntaxBehavior
name==nullConverts to null
name==123Converts to number if attribute is untyped
name==trueConverts to boolean if attribute is untyped
name==number:123Explicit number conversion
name==boolean:trueExplicit boolean conversion
name==string:some%20textKeep as string with URL decode
name==date:2024-01-05T20%3A07%3A27.955ZExplicit Date conversion

If the attribute specifies a type in the schema (e.g., Float), values are always converted to that type before searching.

For strict operators (=, ===, !==), no automatic type conversion is applied — the value is decoded as a URL-encoded string, and the attribute type (if declared in the schema) dictates type conversion.

Unions (OR Logic)

Use | instead of & to combine conditions with OR logic:

GET /Product/?rating=5|featured=true

Grouping

Use parentheses or square brackets to control order of operations:

GET /Product/?rating=5|(price=gt=100&price=lt=200)

Square brackets are recommended when constructing queries from user input because standard URI encoding safely encodes [ and ] (but not ():

GET /Product/?rating=5&[tag=fast|tag=scalable|tag=efficient]

Constructing from JavaScript:

let url = `/Product/?rating=5&[${tags.map(encodeURIComponent).join('|')}]`;

Groups can be nested for complex conditions:

GET /Product/?price=lt=100|[rating=5&[tag=fast|tag=scalable|tag=efficient]&inStock=true]

Query Functions

Harper supports special query functions using call syntax, included in the query string separated by &.

select(properties)

Specify which properties to include in the response.

SyntaxReturns
?select(property)Values of a single property directly
?select(property1,property2)Objects with only the specified properties
?select([property1,property2])Arrays of property values
?select(property1,)Objects with a single specified property
?select(property{subProp1,subProp2})Nested objects with specific sub-properties

Examples:

GET /Product/?category=software&select(name)
GET /Product/?brand.name=Microsoft&select(name,brand{name})

limit(end) or limit(start,end)

Limit the number of results returned, with an optional starting offset.

GET /Product/?rating=gt=3&inStock=true&select(rating,name)&limit(20)
GET /Product/?rating=gt=3&limit(10,30)

sort(property) or sort(+property,-property,...)

Sort results by one or more properties. Prefix + or no prefix = ascending; - = descending. Multiple properties break ties in order.

GET /Product/?rating=gt=3&sort(+name)
GET /Product/?sort(+rating,-price)

Added in: v4.3.0

Relationships and Joins

Added in: v4.3.0

Harper supports querying across related tables through dot-syntax chained attributes. Relationships must be defined in the schema using @relation.

Schema example:

type Product @table @export {
id: ID @primaryKey
name: String
brandId: ID @indexed
brand: Brand @relation(from: "brandId")
}
type Brand @table @export {
id: ID @primaryKey
name: String
products: [Product] @relation(to: "brandId")
}

Query by related attribute (INNER JOIN behavior):

GET /Product/?brand.name=Microsoft
GET /Brand/?products.name=Keyboard

Nested Select with Joins

Relationship attributes are not included by default. Use select() to include them:

GET /Product/?brand.name=Microsoft&select(name,brand)
GET /Product/?brand.name=Microsoft&select(name,brand{name})
GET /Product/?name=Keyboard&select(name,brand{name,id})

When selecting without a filter on the related table, this acts as a LEFT JOIN — the relationship property is omitted if the foreign key is null or references a non-existent record.

Many-to-Many Relationships

Many-to-many relationships can be modeled with an array of foreign key values, without a junction table:

type Product @table @export {
id: ID @primaryKey
name: String
resellerIds: [ID] @indexed
resellers: [Reseller] @relation(from: "resellerId")
}
GET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})

The array order of resellerIds is preserved when resolving the relationship.

Property Access via URL

Changed in: v4.5.0

Access a specific property of a record by appending it with dot syntax to the record id:

GET /MyTable/123.propertyName

This only works for properties declared in the schema. As of v4.5.0, dots in URL paths are no longer interpreted as property access for undeclared properties, allowing URLs to generally include dots without being misinterpreted.

directURLMapping Option

Added in: v4.5.0

Resources can be configured with directURLMapping: true for more direct URL path handling. When enabled, the URL path is mapped more directly to the resource without the default query parameter parsing semantics. See Database / Schema for configuration details.

See Also