# Model customization

Source: https://developers.swell.is/guides/model-customization

Each Swell store has an editable schema based on models. These are the building blocks that shape each store and house both content and business data. With models, you can customize and capture information within various namespaces of your choosing—allowing you to utilize or access that information in various locations.

Models can be customized by [Swell Apps](https://developers.swell.is/apps/models), and from within the Swell dashboard under **Developer → Models**.

### Standard models

Swell comes with a suite of standard data models and ecommerce business logic out of the box which serves as a foundation for further customization. You can add new fields to built-in models like `products` and `orders`, or create entirely new models for your store’s specific needs. Fields can be used to store all the kinds of data you’d expect from a CMS or database, can be rendered in the dashboard for admins to edit, and can utilize formulas for default values.

### Content models vs Data models

Swell utilizes two different types of models, each with its own intended functionality:

- **Content models** work similarly to a CMS and can be used to model editable structured content any way you like.
- **Data models** are for Swell's built-in commerce functionality and can be customized to suit your business needs.

#### Key differences

**Content models**

- Automatically generate an associated data model if they need to be accessible via their own API endpoint.
- Define field types with input UI components and validation options.
- Content collections and fields have dedicated space in the dashboard for managing items.
- Content models can have their own API endpoint, attach fields to standard data models (e.g. `products`), or be abstract sets of fields used within other models.

**Data models**

- Define database field types directly mapping to API structure.
- Editing UI only for standard models.
- All models have a top level API endpoint.

Since data models are low-level configurations with primitive field types, they're best used to store data that will be accessed programmatically or through a custom UI. If you want to provide the ability for admins to edit field values in the dashboard or storefront editor similarly to a CMS, content models are the solution.

### Content models

Content models are a layer above data models and have a simpler configuration syntax and allow for field values to be editable in the dashboard. They provide most of the functionality you'd expect from a dedicated CMS—with the additional benefit of making content available in the same API as standard models like `products`. While data models are limited to primitive field types, content models can define input UIs for fields like `phone` or `url` to provide a better editing experience.

**Content models can be used to:**

- Add new fields to existing models that can be edited in the dashboard, like extra details about orders or customers.
- Add new collections of custom content that are available via API, like pages or blogs.
- Create repeatable and modular components that can be used to build custom page layouts with structured content blocks.

**Example of a content model**

**swell.js**

```javascript
{
  id: 'product_detail_page', // Required
  name: 'Product detail page', // Required
  description: "Page displaying a single product", // Optional
  collection: "products", // Optional
  fields: [
		{ ... },
		{ ... },
		{ ... }
	]
}
```

**Content model attributes**:

- `id` is what the model is referred to in code
- `name` and description are used in the dashboard to help admins understand what the model is and what it is used for
- `collection` is used to determine where the content model will exist
- `fields` are the set child fields the model contains

#### Working with content models

Content models work in a similar way to data models, but they have a simpler definition syntax. Their use is focused on building flexible content structures and an intuitive editing UI within the dashboard.

**Manage content models in the following ways:**

- From the dashboard, under **Developer → Models**.
- By configuration in a [Swell App](https://developers.swell.is/apps/content).

#### Defining where content lives

The `collection` attribute determines where the model's data is stored, and whether it has an API endpoint.

**1. In a new model**

A new collection and an underlying data model is created if the collection doesn't already exist. All objects of the content model will be available at that collection endpoint.

Field IDs can be arbitrary object paths, which allows for logical grouping of things, and reliable paths even when moving fields between the root and field groups.

**Show an example**

Let's say we're an upscale beverage maker and want to have a list of ingredients for one of our fine tipples. Defining a content type with an `ingredients field` and `model: 'products'` stores the data on a product object at `product.content.ingredients`.

We want each ingredient to have a name and description, so we'll use a `collection` field to allow any number of ingredients with those two fields to be added. Collection fields can accommodate other content types using the `item_types` attribute and passing an array of content type IDs, or define a set of fields that each item in the collection will have. Some CMS call this a 'repeated field'.

`Creating the content type`

```javascript
// Create the content type
await swell.put('/:content', {
	name: 'Product details', // The name shown in the dashboard
	description: 'Additional info about the product', // An optional description to help admins understand what this content type is for
	collection: 'products', // We're attaching these fields to every product
	fields: [
		{
			id: 'ingredients', // The field's object key
			label: 'Ingredient list', // The label shown in the dashboard
			type: 'collection',
			fields: [
				{
					id: 'name',
					label: 'Ingredient name',
					type: 'short_text'
				},
				{
					id: 'description',
					label: 'Description',
					type: 'long_text'
				}
			]
		}
	]
})

// Add some ingredient data to an existing product with the slug 'elderflower-tonic'
await swell.put('/:content', {
	id: 'elderberry-tonic',
	'content.ingredients': [
		{
			name: 'Organic Elderflower',
			description: 'Picked by hand in the Swiss Alps.'
		},
		{
			name: 'Grapefruit peel',
			description: 'Aromatic but not too tart.',
		},
		{
			name: 'Cane sugar',
			description: 'Just enough to balance out the grapefruit.'
		},
		{ 
			name: 'Quinine',
			description: 'The real stuff, direct from farmers in Congo'
		}
	]
})

// Fetch the newly-updated product with our ingredient list
const product = await swell.get('/products/elderflower-tonic')
```

`Result`

```javascript
{
	id: '1079d3b465c4452688b3bf57',
	slug: 'elderflower-tonic',
	...
	content: {
		ingredients: [
			{
				name: 'Organic Elderflower',
				description: 'Picked by hand in the Swiss Alps.'
			},
			{
				name: 'Grapefruit peel',
				description: 'Aromatic but not too tart.',
			},
			{
				name: 'Cane sugar',
				description: 'Just enough to balance out the grapefruit.'
			},
			{ 
				name: 'Quinine',
				description: 'The real stuff, direct from farmers in Congo'
			}
		]
	},
	...
	name: 'Elderflower Tonic',
	price: 24.00
}
```

**2. Within an existing data model**

Using the ID of a data model will attach the content model to it. The fields of the content model become available on all entries in that collection.

**Show an example**

Let's say we're an upscale beverage maker and want to have a list of ingredients for one of our fine tipples. Defining a content type with an `ingredients` field and `collection: 'products'` stores the data on a product object at `product.content.ingredients`.

We want each ingredient to have a name and description, so we'll use a `collection field` to allow any number of ingredients with those two fields to be added. Collection fields can accommodate other content types using the `item_types` attribute and passing an array of content type IDs, or define a set of fields that each item in the collection will have. Some CMS call this a 'repeated field'.

**Code example title**

`Creating the content type`

```javascript
// Create the content type
await swell.put('/:content', {
	name: 'Product details', // The name shown in the dashboard
	description: 'Additional info about the product', // An optional description to help admins understand what this content type is for
	collection: 'products', // We're attaching these fields to every product
	fields: [
		{
			id: 'ingredients', // The field's object key
			label: 'Ingredient list', // The label shown in the dashboard
			type: 'collection',
			fields: [
				{
					id: 'name',
					label: 'Ingredient name',
					type: 'short_text'
				},
				{
					id: 'description',
					label: 'Description',
					type: 'long_text'
				}
			]
		}
	]
})

// Add some ingredient data to an existing product with the slug 'elderflower-tonic'
await swell.put('/:content', {
	id: 'elderberry-tonic',
	'content.ingredients': [
		{
			name: 'Organic Elderflower',
			description: 'Picked by hand in the Swiss Alps.'
		},
		{
			name: 'Grapefruit peel',
			description: 'Aromatic but not too tart.',
		},
		{
			name: 'Cane sugar',
			description: 'Just enough to balance out the grapefruit.'
		},
		{ 
			name: 'Quinine',
			description: 'The real stuff, direct from farmers in Congo'
		}
	]
})

// Fetch the newly-updated product with our ingredient list
const product = await swell.get('/products/elderflower-tonic')
```

`Result`

```javascript
{
	id: '1079d3b465c4452688b3bf57',
	slug: 'elderflower-tonic',
	...
	content: {
		ingredients: [
			{
				name: 'Organic Elderflower',
				description: 'Picked by hand in the Swiss Alps.'
			},
			{
				name: 'Grapefruit peel',
				description: 'Aromatic but not too tart.',
			},
			{
				name: 'Cane sugar',
				description: 'Just enough to balance out the grapefruit.'
			},
			{ 
				name: 'Quinine',
				description: 'The real stuff, direct from farmers in Congo'
			}
		]
	},
	...
	name: 'Elderflower Tonic',
	price: 24.00
}
```

**3. As abstract**

Omitting the `collection` attribute makes the model abstract, meaning there's no collection or API endpoint where entries can be fetched directly. This is ideal for defining smaller groups of fields that are used within other content models, without polluting the global schema*—*making sets of fields reusable in multiple places makes the job of content editors and developers much simpler*—*resulting in more consistent structures.

#### Field types and input UI

Fields are a powerful way to shape structured content and define appropriate input components for admins. A field's `type` and `ui` property can be specified to determine the most appropriate formatting and editing experience from within the dashboard. If omitted or unspecified, the field type's relative default UI will be used.

Take the `boolean` field type for example:

**swell.js**

```javascript
// Boolean type defaults to a checkbox UI
{
  id: ...,
  label: ...,
  type: 'boolean',
}

// Specify a boolean field with a toggle UI 
{
  id: ...,
  label: ...,
  type: 'boolean',
  ui: 'toggle', // 
}
```

### Data models

Being able to create native-level data models and add to existing ones provides the opportunity to make your store work exactly how you need it to. Swell's recommended approach to customize data models directly is by configurations in [Swell Apps](https://developers.swell.is/apps/overview).

#### Schema introspection

You can view your store’s schema in the Swell dashboard, and through API endpoints such as the following.

**GET method**

```txt
GET /:models
```

To retrieve a single model, append the model’s ID:

**Retrieve a single model**

```txt
GET /:models/products
```

That will return a result like this:

**The product model**

```json
{
  "version": "1.0.147",
  "name": "products",
  "api": "com",
  "label": "Products",
  "fields": {
    "id": {
      "type": "objectid"
    },
    "date_created": {
      "type": "date",
      "auto": true
    },
    "date_updated": {
      "type": "date",
      "auto": "update"
    },
    "name": {
      "type": "string",
      "required": true,
      "localized": true
    },
    "slug": {
      "type": "string",
      "unique": true,
      "required": true,
      "format": "slug",
      "default": {
        "$formula": "slug(name)"
      }
    },
    "sku": {
      "type": "string",
      "unique": true,
      "label": "SKU"
    },
    "active": {
      "type": "bool",
      "default": false
    },
    "discontinued": {
      "type": "bool"
    },
    "tags": {
      "type": "array",
      "value_type": "string"
    },
    "popularity": {
      "type": "int"
    },
    "price": {
      "type": "currency",
      "localized": true,
      "default": 0
    },
    "sale": {
      "type": "bool"
    },
    "sale_price": {
      "type": "currency",
      "localized": true
    },
    ...
   }
  }
```

#### Extending models

When defining a new model, you can specify the name of a parent model to extend properties from.

All properties of the extended model will be inherited and merged under the new schema. Any property can be overridden or modified in the definition of the extending model, including field attributes.

For example, if a parent model has an optional field `sku` and you want to make it required in the extending model:

**models/custom-products.json**

```json
{
  "extends": "products",
  "fields": {
    "sku": {
      "required": true
    }
  }
}
```

Consider the similarity to class inheritance in object-oriented programming. This approach allows you to compose models and manage complexity with less configuration.

### Conclusion

Swell's data and content models provide unrestricted creative freedom. They are also scalable and can grow with your business needs.
