Skip to content

Object Types

Object types are used in GraphQL to define the custom data structures of your application as well as the relationships between objects. This is the equivalent of modeling your database schema and models in traditional applications. With Slicknode, you only have to define the Schema for the API using the GraphQL SDL and Slicknode takes care of creating the database tables, running migrations, creating and enforcing foreign key constraints, unique constraints, creating indexes etc.

Based on the Schema that you define, the API with CRUD operations and the CMS is automatically generated.

There are two different object types available in Slicknode:

  • Persisted Objects: Objects that are stored in the Slicknode database. Think of them as the tables in your database. You can load and manipulate them via GraphQL queries.

  • Non-Persisted Objects: (Coming soon) Non-Persisted Objects are object types that just define a data structure without being persisted to the database by itself. They can be stored inline in a persisted object (For example as a JSONB field)

Persisted Objects

All persisted objects have to implement the Node interface. The Node interface has a field with the name id that has the type ID!. This creates the primary key in the database and makes it possible to load individual objects of that type.

For example, a simple article type in a module with the namespace NewsFeed and a text field could look as follows:

# A simple news article in the news feed
type NewsFeed_Article implements Node {
  # We always have to add all fields from the implemented interfaces
  # in this case the `id` field from the Node interface
  id: ID!

  # We can add more fields with other data types
  text: String
}

For the field types you can use the supported Scalar types or any of the object types in your application that implement the Node interface.

Also see Relations if you want to create list values or create relationships between objects.

Required fields

If you want to make a field required, you can append the field type with an exclamation mark. In the above example, the field id always has a value whereas the text field is optional (it can also contain the value NULL)

Note

The not-null constraint is enforced at the database level for maximum data consistency. You cannot add a required field to a type that already has records in the database. To add a required field you first have to add the field as non required and add values to the existing objects via the API. Afterwards you can change the field type to be required.

Descriptions

You can add descriptions to fields as well as to the type itself. Descriptions are enclosed in tripple quotes and can span across multiple lines.

For example:

"""
This is the description of the type and will be added to the GraphQL type

It can span across multiple lines an can contain `markdown`
"""
type MyModule_TypeName implements Node {
  """Single line description"""
  id: ID!

  """
  This description is added to the field 
  Descriptions can have multiple lines and support markdown
  """
  fieldWithDescription: String
}

It is recommended to add good documentation in the form of descriptions to your schema. This will be used as the description for the GraphQL types which will be available in the GraphiQL API explorer as well as in the forms of the CMS. The descriptions also appear in IDEs that support GraphQL.

You can use markdown to link to external resources if you need very long descriptions.

Unique fields

You can add unique constraints to your fields. This will ensure that each value is unique across all objects of that type. To create a unique constraints for a field, add the @unique directive after the field type.

For example, if we want to create a slug for the article for nice page links:

type NewsFeed_Article implements Node {
  id: ID!
  slug: String! @unique
  text: String
}

NULL values are ignored for the uniqueness, so there can be multiple objects that have the value NULL in a unique field.

Note

When you add a @unique constraint on a field that already has values stored in the data store, the migration will fail as the unique constraints are enforced at the database level. If you already have only unique or NULL values stored for that field, the @unique constaint can be added without problems.

Indexes

As the number of objects of a certain type grows, the Slicknode data store might take longer to return the objects when a complex filter criteria is applied. To improve the performance you can add an index on the filtered columns by adding the @index directive:

type NewsFeed_Article implements Node {
  id: ID!
  published: DateTime! @index
}

This will create an index on the published field which can significantly speed up queries when the types are filtered by the published status. Keep in mind though that the index has to be updated when new objects are added to the database. You should add an index to the field when an index would also make sense for a traditional RDBMS.

Note

Fields of a type that implements the Node interface are automatically indexed. Unique fields also have an index by default already and don't need the @index directive.