An example server implemented by a schema-first approach exposes a GraphQL API for search indices. Starting from a schema that defines the structure of the documents in search indices, the server generates:
-
Elasticsearch index mappings, and
-
GraphQL schema with additional types needed to execute mutations and queries on search indices.
An API version implements a different generation of a GraphQL API within a single server. A GraphQL schema defines the types and operations implemented by an API version. The server exposes an HTTP endpoint for each API version at the URL paths:
{server.servlet.context-path}/graphql/{api-version}
A proto schema is a schema from which other schema are generated.
It is written in the GraphQL schema definition language.
The src/main/resources/search/ directory contains a subdirectory for each API version.
The schema files under a API version subdirectory define the proto schema for that API version.
Directives provide information about how to generate the other schema.
The @document directive indicates the annotated object type is the root object of the document to
be put in a search index.
type Transaction @document {The @id directive indicates the annotated field uniquely identifies the document in a search
index.
This is the document ID used to put a document into a search index.
transaction_urn: ID! @idThe @searchable directive indicates the annotated field can be queried in a search.
city: String! @searchableBy default, the server translates the ID scalar type to the "keyword" mapping type, and the
String scalar type to the "text" mapping type.
The type argument can change the mapping type.
product_code: String! @searchable(type: "keyword")
By default, the server translates an object type definition to a mapping with type "object".
The type argument can change the mapping type to "nested".
type Listing @searchable(type: "nested") {The search schema is generated from the proto schema. This is the schema exposed by the GraphQL API.
mutation {
createIndexWithAlias(
type: "Transaction"
index: "transaction-1"
alias: "transaction-write"
)
}mutation put {
putTransaction(
index: "transaction-write"
documents: {
transaction_urn: "transaction:1"
listing: {
listing_urn: "listing:2"
description: "description"
reserve_price: 2
valuation_price: 1
}
property: {
property_urn: "property:3"
location: {
address: {
line: "9641 Sunset Blvd"
city: "Beverly Hills"
state: "CA"
postal_code: "90210"
country: "US"
}
position: {
lat: 34.08492556624647
lon: -118.4135163566971
}
}
bathrooms: 2
bedrooms: 3
}
}
)
}query search {
transactionSearch(
index: "transaction"
filter: {
property: {
location: {
address: {
state: {
eq: "CA"
}
}
}
}
}
sort: {
field: "property.bedrooms"
direction: ASC
}
) {
edges {
node {
transaction_urn
}
}
pageInfo {
endCursor
hasNextPage
}
}
}query aggregate {
transactionSearch(
index: "transaction"
filter: {
property: {
location: {
address: {
state: {
eq: "CA"
}
}
}
}
}
groupBy: {
property: {
bedrooms: {
terms: {
first: 10
}
}
}
}
) {
groupBy {
property {
bedrooms {
key
count
}
}
}
}
}The following filter operators are supported:
| Operator | Description |
|---|---|
|
All of the conditions must be true |
|
At least one of the conditions must be true |
|
All of the conditions must be false |
|
A term analyzed from the field value is a term in the list |
|
Equal to |
|
The field value is a value in the list |
|
Greater than |
|
Greater than or equal to |
|
Less than |
|
Less than or equal to |
|
Whether the field has a value |
|
The GeoPoint field value is within the given radius from the given center |