JSON Programming Guide
Welcome to the Hub Framework JSON programming guide! This guide aims to act as a reference to the default JSON schema provided by the framework, and also contain information on how to enable a custom JSON schema to be used with the framework.
Before reading this guide, it’s recommended to read the Content programming guide, which goes into more detail on how content is built with the Hub Framework.
Table of contents
Introduction
The Hub Framework enables content for views to be defined through JSON. This can make it a lot faster to ship content changes, since content can be defined completely in a server-side system, without requiring a client release.
Any JSON schema can be used with the Hub Framework, and each feature using the framework has the ability to define its own. This enables you to start using the Hub Framework without modifying any server-side system that produces the JSON that you’re consuming, and also enables multiple teams working on the same application to potentially use different JSON schemas.
For convenience, the Hub Framework ships with a default JSON schema that is guaranteed to be synced across both iOS & Android.
JSON schema hierarchy
To match the content models that JSON data feeds into, each JSON schema that is used with the Hub Framework contains 3 sub-schemas.
HUBViewModelJSONSchema
- forHUBViewModel
.HUBComponentModelJSONSchema
- forHUBComponentModel
.HUBComponentImageDataJSONSchema
- forHUBComponentImageData
.
JSON data can either be supplied with a root dictionary (in the form of a serialized view model), or with a root array (where each element contains a serialized component model).
Default JSON schema
To use the default JSON schema, no additional action is required. Every feature that doesn’t declare a custom JSON schema automatically uses the default one.
Here is a reference for the default JSON schema:
View model schema
Key | Type | Description | Maps to |
---|---|---|---|
id |
String |
The identifier of the view model. Can be used for logging, or to identify the view in various delegate methods & handlers. | identifier |
title |
String |
The title to use for the view’s navigation bar. | navigationBarTitle |
header |
Dictionary -> ComponentModel |
Dictionary for a component model that should be used as the view’s header component. Will be parsed using the schema for component models. | headerComponentModel |
body |
[Dictionary] -> [ComponentModel] |
An array of dictionaries for the component models that should be used for the view’s body components. Will be parsed using the schema for component models. | bodyComponentModels |
overlays |
[Dictionary] -> [ComponentModel] |
An array of dictionaries for the component models that should be used for the view’s overlay components. Will be parsed using the schema for component models. | overlayComponentModels |
custom |
Dictionary |
Any custom (free-form) data to associate with the view model. | customData |
Component model schema
When a dot (.
) is being used in the key, it means that the key is nested within another dictionary. For example text.title
means that the structure looks like this:
{
"text": {
"title": "The title"
}
}
Key | Type | Description | Maps to |
---|---|---|---|
id |
String |
The identifier of the component model. Can be used for logging, or to identify the model in other content operations, various delegate methods, handlers, etc. | identifier |
group |
String |
The identifier of any logical group to put the component model in within its parent. Can be used to associate certain child components with each other. | groupIdentifier |
component.id |
String |
The identifier (namespace:name ) of the component to use to render the model. |
componentNamespace and componentName |
component.category |
String |
The category of the component. Used to perform sensible fallbacks for older versions of the application that might not support the requested component. See component categories for possible values. | componentCategory |
text.title |
String |
The title that the component should display. | title |
text.subtitle |
String |
The subtitle that the component should display. | subtitle |
text.accessory |
String |
Any accessory title for the component. Usually used to render some form of metadata or accessory information with less prominence. | accessoryTitle |
text.description |
String |
Any longer body of text that should be displayed in the component. | descriptionText |
images.icon |
String |
Any icon that should be displayed in the component. Will be resolved using the application’s HUBIconImageResolver . |
icon |
images.main |
Dictionary -> ComponentImageData |
The data for the component’s main image, that will be displayed in the foreground of the component. Will be parsed using the schema for component image data. | mainImageData |
images.background |
Dictionary -> ComponentImageData |
The data for the component’s background image. Will be parsed using the schema for component image data. | backgroundImageData |
images.custom |
{String : Dictionary -> ComponentImageData} |
A dictionary containing dictionaries for custom image data that the component may use. Each nested dictionary will be parsed using the schema for component image data. | customImageData . |
target |
Dictionary -> ComponentTarget |
A dictionary containing target information for the component, used to handle selections. Will be parsed using the schema for component targets. | target |
metadata |
Dictionary |
Any application-specific metadata to associate with the component. Typically this data is not consumed by the component itself, but by application-wide systems such as playback for a media app, or photo metadata for a photo app, etc. | metadata |
logging |
Dictionary |
Logging information that can be used to log events that occur for the component. Each application should define what keys that are used in this dictionary. | loggingData |
custom |
Dictionary |
Dictionary used to provide an extension point for component authors. Each component can define which keys that it wants to use from this dictionary, enabling customization of properties that are not included as first-class properties in the component model schema. | customData |
children |
[Dictionary] -> [ComponentModel] |
An array of dictionaries for the component models that should be used for the component’s children. Will be parsed using the schema for component models. | childComponentModels |
Component image data schema
Key | Type | Description | Maps to |
---|---|---|---|
uri |
String |
The URI of the image. Used to download a remote image using the application’s HUBImageLoader(Factory) . |
URL |
placeholder |
String |
Any icon to use as a placeholder until a remote image has been downloaded. Will be resolved using the application’s HUBIconImageResolver . |
placeholderIcon |
local |
String |
The name of any local (bundled) image to use. | localImage |
custom |
Dictionary |
Any custom (free-form) data to associate with the image data. | customData |
Component target schema
Key | Type | Description | Maps to |
---|---|---|---|
uri |
String -> URI |
Any URI that should be opened when the user selects the component. | URI |
actions |
[String] |
The identifiers (namespace:name ) of any actions (HUBAction ) that should be performed when the user selects the component. |
actionIdentifiers |
view |
Dictionary -> ViewModel |
Any pre-loaded view model that should be used for a Hub Framework-powered view that is the destination of uri . Will be parsed using the schema for view models. |
initialViewModel |
custom |
Dictionary |
Any custom (free-form) data to associate with the target. | customData |
Example JSON
Below is an example JSON file that shows how to use the default schema. It adds a header component, a carousel, a section header and 3 rows to a view model.
{
"header": {
"id": "header",
"component": {
"id": "default:header",
"category": "header"
},
"text": {
"title": "Delicious Food",
"subtitle": "Discover the tastes of the world"
},
"images": {
"background": {
"uri": "https://spotify.com/image/of/food.jpg",
"placeholder": "food"
}
}
},
"body": [
{
"id": "featured",
"component": {
"id": "default:carousel",
"category": "carousel"
},
"text": {
"title": "Great quick meals"
},
"children": [
{
"id": "featured-0",
"component": {
"id": "default:card",
"category": "card"
},
"text": {
"title": "Hamburger",
"description": "Very popular around the world - and quick both to make and eat!"
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/hamburger.jpg",
"placeholder": "quickfood"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Hamburger"
}
},
{
"id": "featured-1",
"component": {
"id": "default:card",
"category": "card"
},
"text": {
"title": "Noodles",
"description": "Quick to boil - and can be served with many different accessories."
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/noodles.jpg",
"placeholder": "quickfood"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Noodle"
}
},
{
"id": "featured-2",
"component": {
"id": "default:card",
"category": "card"
},
"text": {
"title": "Hot Dogs",
"description": "Whether you're having a barbeque or just a quick bite - it's awesome."
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/hotdog.jpg",
"placeholder": "quickfood"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Hot_dog"
}
}
]
},
{
"id": "sectionHeader",
"component": {
"id": "default:sectionHeader",
"category": "header"
},
"text": {
"title": "Delicious Swedish Food"
}
},
{
"id": "row-0",
"component": {
"id": "default:row",
"category": "row"
},
"text": {
"title": "Meatballs & mashed potatoes",
"subtitle": "A swedish classic"
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/meatballs.jpg",
"placeholder": "sweden"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Meatball"
}
},
{
"id": "row-1",
"component": {
"id": "default:row",
"category": "row"
},
"text": {
"title": "Fried herring",
"subtitle": "Just be careful of the fermented version!"
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/herring.jpg",
"placeholder": "sweden"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Herring"
}
},
{
"id": "row-2",
"component": {
"id": "default:row",
"category": "row"
},
"text": {
"title": "Cinnamon bun",
"subtitle": "If you're having a stressful day, just take a break for a \"fika!\""
},
"images": {
"main": {
"uri": "https://spotify.com/image/of/cinnamon-bun.jpg",
"placeholder": "sweden"
}
},
"target": {
"uri": "https://en.wikipedia.org/wiki/Cinnamon_roll"
}
}
]
}
Using custom JSON schemas
Custom JSON schemas can be used to easily use existing server side data with the Hub Framework. All you need to do is let the framework know how to parse your expected JSON format, and it takes care of the rest.
Defining JSON paths
In order to support the level of flexibility required to be able to parse virtually any JSON schema, the Hub Framework uses a path-based approach to JSON parsing. Each piece of data that should be retrieved is associated with a path, that is then followed into a JSON structure to retrieve that data.
For example, let’s say we want to retrieve the title
string that is nested within the text
dictionary, as below:
{
"text": {
"title": "The title"
}
}
To do that, we use the following path:
[[[path goTo:@"text"] goTo:@"title"] stringPath];
This tells the Hub Framework’s JSON parsing system that it should navigate through the text
and title
keys, and then retrieve the string value for that key.
Paths are defined using HUBMutableJSONPath
, which can be created from a HUBJSONSchema
, which in turn can be created from HUBJSONSchemaRegistry
. Each path is then attached to a schema, which is then registered using HUBJSONSchemaRegistry
.
Paths can also perform a lot more complex operations, such as running a block. For more information, see the code documentation for HUBMutableJSONPath
.
Extending an existing schema
Sometimes you just want to slightly tweak the default schema (or any existing custom schema), instead of building one from scratch.
All schemas that are created by the Hub Framework come setup according to the default schema, so all you need to do is tweak the properties that you want to tweak.
In order to extend an existing custom schema, use the copySchemaWithIdentifier:
method on HUBJSONSchemaRegistry
.