Skip to main content

Data Modeling

Data modeling in TakeShape can be accomplished without writing any code using TakeShape's shape editor. The shape editor provides a simple, easy-to-use interface where you'll define your shape's metadata and storage, then define its properties.

First, go to the "API" section of your project. Then:

  • to create a new shape, use the "Add Shape" button.
  • to edit an exiting shape, find it in the schema index and use the "Edit" action, which looks like a pencil

From there, you'll be taken to the shape editor.

Metadata​

By convention shape names should be singular. For example, a shape representing articles should be title "Article". Entering the title "Article" will also fill in the name "article". What's the difference?

  • Name - API identifier for your shape. It can't contain spaces, can't use special characters, and can't start with a number.
  • Title - User-facing identifier for your shape. A title will be generated based on your shape name, but you can further customize it. Titles can include spaces and richer characters.
  • Description - A user-facing explanation of a shapes's purpose. The description appears in several places in the UI.

ShapeDB Storage​

In TakeShape, data modeling is as open-ended as possible. That said, you create your shapes to fulfill a specific use-case. Your Built-in Data Storage choice describes how you plan to use your shape.

Creating a shape without persistent storage in ShapeDB is useful to represent data returned from connected services, like SearchResults. It's also useful for data structures shared between other shapes, like SEO metadata.

When ShapeDB is enabled, you can choose the type of storage to use:

Single​

Denotes a single item or singleton in programming terminology. Persist a single instance of this shape. Useful for creating shapes like Navigation or Settings.

Multiple​

Denotes multiple items. This is the default setting. Useful for creating shapes like Products or Posts.

Taxonomy​

Denotes a shape which is used to organize others. A taxonomy can be used to filter data entries it has relationships with, like Categories or Tags.

Annotating a shape as a "Taxonomy" allows the relationships between data entries to be surfaced to users when filtering in the asset views and entry list views.

Taxonomies appear in the sidebar in their own section under "Multiple' shapes.

A good taxonomy is something you'll use to classify other thing. Tags, Categories, Topics, Subjects, Genres, and even Authors. Right now the way a taxonomy is used in the UI is to help filter lists.

A taxonomy is effectively a multiple shape that we treat slightly differently on the backend. You can switch a multiple shape to a taxonomy and vice-versa at will.

Taxonomies treat their first text property as their β€œterm” property. This is what will be used for auto suggest.

Properties​

You easily can add, configure, and delete Shape properties using our shape editor. Pick the data type, give the property a name, and use the "plus" button it add it to your shape.

Best practices
  • Put your identifying properties first. Property order is important because it informs how TakeShape generates previews of your data for list views, relationships and taxonomies. Examples of identifying properties are "Title", "Name", "Headline", etc.
  • Make at least one property required.

Shape properties can hold a single value, or an array of values. In addition to primitive types like String, Number, and Boolean, we also suppport:

  • an Asset type, for properties that contain images or other files
  • an Object type, for properties that use the data structure of other shapes in your schema, or that use ShapeDB relationships to other saved entries in your schema

Properties are also configurable with widgets for creating and editing their values in ShapeDB.

String properties​

String properties resolve to basic string values, like "hello world".

When configuring your String property on a shape with ShapeDB enabled, you can choose between many different form widgets for creating and editing string data in ShapeDB:

Single Line Canvas​

A single line rich text widget.

Markdown​

Markdown widget with preview that uses the CommonMark flavor of markdown.

Single Line​

A single line plain text widget.

Paragraph​

A multi-line plain text widget.

Slug​

Similar to a single line text widget but with some special features specific to content slugs.

When you create a slug property, you can select a Single Line Text widget as a source property. When new content is created, the slug widget is automatically filled out based on a slugified version of the text in the source property using the slugg npm package. The slug widget content can be unlocked, allowing you to use a custom slug value instead.

note

A slug cannot set its source to a property in a repeater unless the slug is in the same repeater. This avoids ambiguity about what the slug content should be.

Block Canvas MDX​

TakeShape's "rich text" widget.

By default, querying for a shape with a Block Canvas MDX widget will return the property value in MDX format. Block Canvas MDX fields accept the following parameters to customize the output:

The format argument accepts the following parameters to customize the output:

format​
  • mdx
  • html
headerIdPrefix​

A prefix to be added to all id properties on header elements when outputting as HTML.

classPrefix​

A prefix to be added to all CSS classes in the generated HTML.

imageConfig​

An imgix configuration json object for the default image size.

query {
home {
fooHtml(imageConfig: {w: 100, h: 100})
}
}
images​

Allows you to specify imgix configurations for the default, small, medium, and large images sizes.

query {
home {
fooHtml(images: {default: {w: 100, h: 100}})
}
}

Returned image urls will have width and height parameters added to the query string: [...]example.jpg?h=100&w=100.

Datetime​

A Date and Time picker widget.

Date​

A Date picker widget where the time defaults to midnight in your project's selected timezone. See "How TakeShape handles dates" for more detail.

A single selection dropdown menu widget with a predefined list of options.

Radio Buttons​

Single selection radio buttons with a predefined list of options.

Number properties​

Number properties hold basic number values. When ShapeDB is enabled, they can be configured to store either an integer value or a fractional number value.

Boolean properties​

Boolean properties hold basic boolean (true/false) values. When ShapeDB is enabled, they can be configured to use either a "Checkbox" or a "Switch" widget.

When the property type is a Boolean Array, you'll be able to use the "Multiple Choice Checkboxes" widget when ShapeDB is enabled.

Checkbox​

A single checkbox widget. Checkboxes work best for granular boolean values, when the resulting value will have a minor impact on the shape.

Switch​

A switch widget. Switches work best for high-level boolean values, when the resulting value will have a major impact on the shape.

Multiple Choice Checkboxes​

A group of checkbox items with a predefined list of options.

The resulting value will be stored as a list of booleans:

[true, false]

Asset fields​

Asset fields hold images, files, or other binary data. When ShapeDB is enabled, asset fields provide an asset selection widget that works with the ShapeDB Asset Library.

Sample GraphQL query for an field named "photo"
query {
photo {
caption
credit
description
filename
mimeType
path
title
}
}

Object fields​

Object fields contain references to other Shapes in your schema. Regardless of whether ShapeDB is enabled, there are a few choices for how to references other Shapes in an object field:

  • Inline will let you create nested object structures within the shape,
  • Relationship will let you create linked references between ShapeDB entries
Block Canvas Options

You will see two other options in this list: "Block Canvas (deprecated)" and "Single Line Block Canvas (deprecated)". These fields provide legacy support for shapes that use the last generation Block Canvas and we discourage choosing them when creating a new shape.

If you'd like to add a new Block Canvas field, create a String field and select the "Block Canvas MDX" widget.

Inline​

Inline object fields allow you to create nested objects inside your shape, so you can store several values under single property. A common use for an object is modeling an address:

When configuring an Inline Object field, you may select as many shapes as you'd like as valid values.

When the field is singluar, its value will be a single object with properties defined by one of N shapes you've selected (ex, 1 dog or 1 cat).

Sample GraphQL query of Shape Object field named "shapeObject"
query {
getDogOrCat {
shapeObject {
... on Cat {
name
lives
}
... on Dog {
name
isBestFriend
}
}
}
}

When the field is an array of Inline Objects, its value will be a list of any N shapes (ex, 2 cats and 3 dogs [{cat}, {dog}, {cat}, {dog}, {dog}])

Sample GraphQL query of Shape Array field named "shapeArray"
query {
getPetStore {
shapeArray {
... on Cat {
name
lives
}
... on Dog {
name
isBestFriend
}
}
}
}
Color​

When a Shape chosen for the object is the built-in "Color", the widget for it will automatically be a color picker which stores the selected color in RGB, HEX, HSV.

Sample GraphQL query for a color field named "color"
query {
color {
hex
hsl {
a
h
l
s
}
hsv {
a
h
s
v
}
rgb {
a
b
g
r
}
}
}

Relationship​

Relationships are a fundamental part of modeling data in TakeShape they allow data items to reference one another. You can think of them as foreign keys in RDBMS or Associations from Rails, but as you'll see TakeShape's relationships are much more useful.

note

The Shapes allowed by a Relationship must have built-in data storage enabled. If you want nested data instead of separate data entries, consider using a Shape Array or Shape Object instead.

When creating a relationship the first step is to choose which shapes you want to allow in the relationship:

Multiple Relationships​

When the field type is an array of Objects, relationships can be thought of as an array of single relationships. In addition, relationships can be ordered. Ordering makes multiple relationships a useful tool when building data entries that need to be manually curated.

Reverse Relationships​

When a relationship is created a reverse relationship is automatically added to the related shape. For example if you add a relationship to a Book type that points to the Author type, a reverse relationship property called bookSet will automatically appear on Author.

There are cases where the name of this reverse relationship property becomes ambiguous. For example, a Post type with two relationships authors and editors which both point to the Person type. The automatically generated field postSet is now ambiguous because it will contain both authors and editors. The solution is to specify the "Reverse Name" on each relationship.

To disambiguate these relationships set the "Reverse Name" for authors to "authored" and the "Reverse Name" Β for editors to Β "edited"

relatedName not set, so "postSet" used automatically
{
getAuthor(_id: "author_id") {
postSet {
total
results {
title
}
}
}
}
Disambiguated by setting relatedName to "edited"
{
getAuthor(_id: "author_id") {
authored {
total
results {
title
}
}
edited {
total
results {
title
}
}
}
}

Block Canvas (deprecated) and Single Line Block Canvas (deprecated)​

TakeShape's deprecated "rich text" field.

Block canvas fields automatically add a corresponding [blockCanvasFieldName]Html field to the API. For example a field named foo will have a corresponding fooHtml field.

  • foo returns raw DraftJS JSON
  • fooHtml - return rendered to HTML

The html field accepts the following parameters to customize the output:

classPrefix​

A string that will prefix HTML class names in the output.

headerIdPrefix​

A string that will prefix the id attributes of header elements in the output.

imageConfig​

An imgix configuration object for the default image size.

query {
home {
fooHtml(imageConfig: {w: 100, h: 100})
}
}
images​

Allows you to specify imgix configurations for the default, small, medium, and large image sizes.

query {
home {
fooHtml(images: {default: {w: 100, h: 100}})
}
}

Returned image urls will have width and height parameters added to the query string: [...]example.jpg?h=100&w=100.