Custom GraphQL schema
Headless development through GRAPHQL dedicated APIs
The Jaha GraphQL API allows you to define your own types and queries with the GraphQL Schema Definition Language (SDL). You can easily deploy it along with your module. To learn how to create a Jahia module, refer to Using the Jahia Studio to create a new project.
After you deploy your SDL schema, you can check the deployment status on the “tools” page of Jahia. In addition, Jahia has an integrated GraphiQL console to let you view and test your custom schema definitions.
Creating an SDL file
First, create and place your SDL file in your module under the following directory.
Since Jahia GraphQL API uses a fixed SDL file name to look up custom schema, you must use the graphql-extension.sdl file name to maintain all GraphQL types.
SDL example
This example SDL defines two custom object types and queries that you could place into your module. If you are not familiar with the syntax of SDL don’t worry, more details are provided later.
The SDL file is plain text and you can use any text editor to create it.
extend type Query { type hotel @mapping(node: "jnt:hotel"){ type booking @mapping(node: "jnt:booking"){ |
Deploy the module using Jahia
Once you create your SDL file and place it into your module, you are ready to deploy your own schema along with your module.
Once module is deployed:
- Now your own SDL schema is deployed. You can use Jahia’s SDL report tool to check the deployment status. Open Jahia Support Tools in your web browser using a URL similar to http://localhost:8080/tools.
- Under Modules, click Jahia GraphQL Core Provider : sdlreporttool.
- Then you should see the my-module-with-SDL deployment status and your custom types in the SDL report tool. The SDL report tool has two sections:
- SDL Definitions
Displays individual type definitions in all schemas which are deployed. If there is an error for an individual type, an error message displays. - SDL Schema
Displays deployment status of each schema from each module in general. This helps you to address problems with modules quickly.
If the indicators are all green, your schema is ready to use. Otherwise, go back to your SDL schema definition to fix it. You don’t have to redeploy your module as all graphql-extension.sdl files are monitored for changes.
Testing custom types and queries
Jahia provides a tool for viewing all GraphQL types and running queries.
To test custom types and queries:
- Click Jahia GraphQL Core Provider : graphiql.
The GraphiQL integrated tool opens. - To view your custom types, click the Docs button at the top-right corner. Enter a type name to lookup the type and query
You should find the type and query definition documents in the current schema. You can also use this simple GraphiQL console to run a query statement to test your types and queries.
SDL syntax
SDL syntax is similar to JSON syntax. Jahia GraphQL API supports the standard syntax and provides some special directives for Jahia content type. The example that follows the data type descriptions shows how to create your own schema using Jahia GraphQL directives.
Basic data types
To start learning SDL syntax, first get to know the most basic data type. Then the most complex data types supported in Jahia GraphQL API. The following two tables provide a summary of these data types.
Type | Format | Example |
---|---|---|
ID |
^([a-zA-Z0-9]+[-])+ |
126e20ba-2599-49af-a6cd-b575b5417482 |
String |
A brown fox jumps over the lazy dog |
|
Int |
-2³¹ ~ 2³¹-1 |
1, 2, 342, -3, ... |
Float |
3.4E +/- 38 |
123.45 |
Double |
1.7E +/- 308 |
123.087223423554 |
Short |
An integer in between -32,768 ~ 32,767 |
123 |
Long |
-2⁶³ ~ 2⁶³-1 |
8746655929836 |
*BigInteger |
Any integer larger than Long type |
1234567890987654321 |
*BigDecimal |
0.33333333333 |
|
Boolean |
true | false |
|
Date | yyyy-MM-dd'T'hh:mm:ss.SSSXXX | 2016-01-06T18:49:45.308+01:00 |
*Note: For BigInteger and BigDecimal types in Jahia JCR, when the data is stored as a larger number than Long or a longer decimal than Double, the actual value will be Long or Double.
Jahia GraphQL API provides a set of composite types which contains multiple basic data types.
Although you could define your own composite type, it is easier to reuse built-in composite types to make your definitions simpler. In addition, you could also define your type by extending one of these.
Jahia data types
Type |
Format |
Metadata |
{ created: Date, createdBy: String, lastModified: Date, lastModifiedBy: String, lastPublished: Date, lastPublishedBy:String } |
Asset |
{ type: String, size: Long, metadata: Metadata } |
ImageAsset |
{ type: String, size: Long, height: Long, width: Long, metadata: Metadata } |
Category |
{ title: String metadata: Metadata description: String } |
Defining a Jahia content model
To define your own type, you must define the content model in a CND file first. Usually you can create the definition in the definitions.cnd file under the same directory as the SDL file, for example:
You can deploy the CND file along with the module.
Here is a sample CND for a content model. For example, you want to publish hotel information on your website. In the CND, you define different fields for the content, such as address, city and country.
<jmix = 'http://www.jahia.org/jahia/mix/1.0'> <jnt = 'http://www.jahia.org/jahia/nt/1.0'> [jnt:hotel] > jnt:content, jmix:basicContent, mix:title - city (string) internationalized - country (string) internationalized - address (string) internationalized |
You can learn how to manage your content model in more detail here Content Structures.
GraphQL type without directive example
This is an example of a GraphQL SDL without any directives. It just defines one type, hotel, with its own properties. However, if you upload this SDL along with your module, it won’t work because the Jahia GraphQL API doesn’t know how to map the type to its content node and node properties.
type hotel { name: String! city: String address: String country: String } |
Therefore, after creating a new type, you need to define the mapping directives.
Use mapping definitions with directives
Add the mapping directive to your types in graphql-extension.sdl file.
Note that @mapping directive supports: node and property arguments for a type and its fields.
type hotel @mapping(node: "jnt:hotel"){ name: String! @mapping(property: "jcr:title") city: String @mapping(property: "city") address: String @mapping(property: "address") country: String @mapping(property: "country") metadata: Metadata rooms: [Room] } type Room @mapping(node: "jnt:room"){ number: Int! @mapping(property: "roomNo") specification: String @mapping(property: "description") available: Boolean @mapping(property: "available") } |
Node mapping is used on a type to specify which JCR node type will be mapped.
type hotel @mapping(node: "jnt:hotel"){ ... } |
Here jnt:hotel is a specific JCR node type. By specifying the node type you enable Jahia to access the right content node.
Property mapping is used in the fields of a type.
type hotel @mapping(node: "jnt:hotel"){ name: String! @mapping(property: "jcr:title") city: String @mapping(property: "city") address: String @mapping(property: "address") country: String @mapping(property: "country") metadata: Metadata rooms: [Room] } |
In this type definition, you could define its fields, such as name, city, address and country. Use the property argument to map the field to the property of a content node. This allows Jahia's GraphQL API to resolve the field correctly
For the custom type Metadata, it maps to the fields in the type which are predefined in the system schema, you don’t need to specify the properties to be mapped here.
For the children of custom type, like Room, it maps to multiple references of the other type. You should get the references along with the main type, when you do the query.
Defining a custom query by extending Query type
Once you define your own types, you may want to query data for the new types. Jahia GraphQL API provides the Query extension for you to define your own query.
Note: All query types in your SDL must extend the Query type.
Defining an all query
If you want to fetch all data set in a list, you could define an all query.
extend type Query { allHotel: [hotel] } |
Defining a single property query
Jahia GraphQL API provides queries for a single property.
extend type Query { hotelByCity: [hotel] hotelByCityConnection: hotelConnection hotelByCountry: [hotel] hotelByCountryConnection: hotelConnection } |
The Jahia GraphQL API will generate the default ByID and ByPath queries for your type, which returns a single unique record. You do not need to define the queries explicitly in your SDL.
You can define any By query for any single property in a type, which returns a list of records. Also make sure you use the exact type name as the query prefix, and the exact property name as suffix, for example, hotelByAddress, hotelByName, or hotelByCity.
Inline descriptions
Descriptions can be added to describe types and their associated fields. Descriptions are useful for communicating information with other developers i.e. consumers of the API.
In your SDL, you can use quotation marks to add descriptions as shown in the following example:
""" hotel content with contact """ type hotel { """unique name of hotel""" name: String! address: String city: String country: String } |
Troubleshooting SDL Issues
Whenever SDL markup is changed it is validated to make sure that it is syntactically correct, that JCR and GraphQL types are available etc. The SDL report tool displays a red indicator to indicate errors discovered during validation.
SDL syntax error
An SDL syntax error displays under SDL schema to help you find the line containing the error.
#missing end brace type hotel { uuid: ID! name: String! address: String city: String country: String |
If you encounter typo error in your SDL, you will see error message similar to this.
#typo error typo hotel { uuid: ID! name: String! address: String city: String country: String } |
Type and extension error
If your SDL has an extension with a nonexisting type, you will see an error message similar to this.
#type ParagraphSDL does not exist extend type ParagraphSDL { content: @mapping(property: "jnt:content") } |
If a type contains an invalid field type in your SDL, you will see an error message similar to this.
#invalid field type type hotel @mapping(node: "jnt:hotel"){ uuid: ID! name: String @mapping(property: "jcr:title") address: String city: String country: String #field type Metadata does not exist metadata: Metadata } |
Mapping directive errors
If a type maps to an invalid node type, you will see an error message similar to this.
#invalid node type mapping type hotel @mapping(node: "jnt:someInvalidNodeType"){ uuid: ID! name: String @mapping(property: "jcr:title") address: String city: String country: String } |
If a type contains a field which maps to invalid property, you will see an error message similar to this.
type hotel @mapping(node: "jnt:hotel"){ uuid: ID! name: String @mapping(property: "jcr:title") address: String city: String country: String #invalid node property mapping startDate: String @mapping(property: "jnt:checkinDate") } |
Connection error
If you try to add a connection to an entry point which does not return a list you will see an error in the status tool.
extends type Query { #invalid connection hotelsByPropertyConnection: Hotel } |