07 Apr 2017
What if you could take the web, turn it into a native app component, and plug it into native layout/scrollview along with other native components? Like magic!

Meet JSON Web Container. Here's how it works:
Step 1. Write HTML:
Write HTML just like you would make a website, using HTML, Javascript, CSS, or whatever. As long as it works in a browser, it will work as a web container.
Step 2. Write JSON:
Write JSON to describe how it blends into native app layout. You can even style it just like any other component!
Step 3. Enjoy!
Here's an example:

Check out this video and you’ll realize how much more you can do with this:
This is a simple update but simultaneously a huge deal for Jasonette, because it opens door to all kinds of new possibilities.
How this came to be
It all started with Brad.
Just like any developer, I believed web would never work in a native app. We did kind of have a half-assed 'html' component with the first version of Jasonette, but it was very limited and was just a hack to display a small subset of HTML elements.
Most importantly, it didn't have Android support (I never implemented an Android counterpart because I really didn't see much utility from the iOS version so didn't want to invest time).
Then one day I see a new pull request on the Android repository:

Obviously I was super skeptical at first ("Everyone knows web views suck!").
But then I actually tried it out..... I was shocked to find how smooth it was. Whole bunch of web views were scrolling within a list view just fine!
So eventually I got around to converting the iOS HTML component to use the same approach.
Also on top of that I made some improvements and design decisions to make sure that these "web containers" will feel completely native inside our apps. I also added support for Javascript.
Adding Javascript opened doors to all kinds of crazy things:

Performance
Once I had a prototype running I posted it on the forum and I got lots of great feedback. One was something I hadn't thought of before:

This comment made me realize that all remote assets (like javascript libraries or css) were being loaded separately for each web container, which resulted in tons of duplicate downloads AND slowdown.
So I went back and added caching mechanism to improve this. So now, all the static assets are cached so they don't get redownloaded multiple times.
After all this was done, the web container was performing flawlessly on both iOS and Android.
In fact, sometimes you can't even tell if it's a native component or a web container!
To sum up: Peformance is great! Of course it won't be 100% the performance of native, but the whole point is to mix and match this into your native app, not to power the entire app using HTML (we're building a native app here!). You have never been able to do something like this before (Seamlessly integrate web views into native scroll views, native layouts, native background, and use them as native components) and that makes tons of difference.
Conclusion
The moral of this story is, "Always push the boundary". With Jasonette we're doing something that most people will say is crazy ("it will never work!") anyway, so why not go all out!
Also I think the way this feature came together is really awesome because this could only happen because the project was open for contribution. Thanks Brad!
I encourage you to feel free to send pull requests no matter how crazy it is.
And that's it! I'm sure this will take your native app to the next level. The initial release for web container is intentionally minimal, and we'll probably add more powerful features going forward.
Would appreciate feedback!
TODO:
02 Mar 2017
In the last post, I've talked about mix-ins for Jasonette, which lets you mix in remote JSON objects to generate a new JSON object. (If you haven't read that one yet, please read it first and come back, you'll need to understand the basics first)
Well, today I have a powerful piece of dark magic which takes this to a whole new level.
Meet Self-Mixin -- A mix-in that mixes a JSON object into itself.

Syntax
There's only one thing you need to know: $document
.
$document
refers to the the currently loaded JSON tree.
For example, let's imagine we've loaded the following JSON on Jasonette.
{
"items": [{
"type": "label",
"text": "Label 1"
}, {
"type": "label",
"text": "Label 2"
}, {
"type": "label",
"text": "Label 3"
}],
"$jason": {
"body": {
"sections": [{
"@": "$document.items"
}]
}
}
}
Notice the $document.items
part. This is a self mixin in action.
When resolving, Jasonette looks at the loaded JSON tree itself ($document
) and searches for an attribute called items
, then it replaces the mixin expression with the object, which results in:
{
"items": [{
"type": "label",
"text": "Label 1"
}, {
"type": "label",
"text": "Label 2"
}, {
"type": "label",
"text": "Label 3"
}],
"$jason": {
"body": {
"sections": [{
"items": [{
"type": "label",
"text": "Label 1"
}, {
"type": "label",
"text": "Label 2"
}, {
"type": "label",
"text": "Label 3"
}]
}]
}
}
}
$document is contextual
$document
is a contextual concept. The same $document
reference can point to a different object depending on how the JSON object was loaded (Was it loaded as the main JSON markup? vs. Was it loaded from the main markup as a mix-in?)
Let's take a look at some examples:
1. Loaded as the main JSON markup
Here's a basic case:
https://blah.blah/child.json
{
"$jason": {
"head": {
"title": "Test",
"templates": {
"body": {
"sections": [{
"items": [{
"@": "$document.model"
}]
}]
}
}
}
},
"model": {
"type": "label",
"text": "Bye World"
}
}
When Jasonette loads and resolves the "@": "$document.model"
, it takes the current JSON tree's model
attribute and replaces it into the mixin expression, and we end up with:
{
"$jason": {
"head": {
"title": "Test",
"templates": {
"body": {
"sections": [{
"items": [{
"type": "label",
"text": "Bye World"
}]
}]
}
}
}
},
"model": {
"type": "label",
"text": "Bye World"
}
}
But we already knew that. Nothing special here.
2. Loaded as a mix-in
This time, let's try taking the same child.json
and mix it into another JSON called parent.json
like this:
https://blah.blah/parent.json
{
"@": "https://blah.blah/child.json",
"model": {
"type": "label",
"text": "Hello World"
}
}
Here's what will happen:
Step 1. Jasonette loads parent.json
and discovers that there's a mixin to resolve.
Step 2. So it mixes in the contents of https://blah.blah/child.json
. To refresh your memory, child.json
looks like this:
{
"$jason": {
"head": {
"title": "Test",
"templates": {
"body": {
"sections": [{
"items": [{
"@": "$document.model"
}]
}]
}
}
}
},
"model": {
"type": "label",
"text": "Bye World"
}
}
Step 3. Notice how parent.json
and child.json
both have the model
attribute, but with different values. Whenever there's a conflict, the remotely mixed-in attribute (model
from child.json
) gets overridden by the main one (model
attribute from parent.json
) like this:
{
"$jason": {
"head": {
"title": "Test",
"templates": {
"body": {
"sections": [{
"items": [{
"@": "$document.model"
}]
}]
}
}
}
},
"model": {
"type": "label",
"text": "Hello World"
}
}
Step 4. Now Jasonette finds that there's still another mixin to resolve: $document.model
. So it mixes in the model
attribute.
The final result is:
{
"$jason": {
"head": {
"title": "Test",
"templates": {
"body": {
"sections": [{
"items": [{
"type": "label",
"text": "Hello World"
}]
}]
}
}
}
},
"model": {
"type": "label",
"text": "Hello World"
}
}
Important distinction: In the previous example the $document.model
inside child.json
was interpreted as child.json
itself, but this time the same $document.model
was interpreted as parent.json
, since its interpretation was carried out after it was mixed into parent.json
.
Impossible is Nothing
Let's step back and think about what all this means.
This means now you can practically manipulate ANY part of a JSON tree at your will.
1. Organize the JSON any way you want
Previously Jasonette had some conventions you needed to follow. For example, you place templates under $jason.head.templates
, data under $jason.head.data
, actions under $jason.head.actions
, and so forth.
{
"$jason": {
"head": {
"data": {
"dwarfs": [{
"username": "Doc"
}, {
"username": "Dopey"
}, {
"username": "Bashful"
}, {
"username": "Grumpy"
}, {
"username": "Sneezy"
}, {
"username": "Sleepy"
}, {
"username": "Happy"
}]
},
"templates": {
"body": {
"sections": [{
"items": {
"{{#each model.dwarfs}}": {
"type": "label",
"text": "{{username}}"
}
}
}]
}
}
}
}
}
This still applies, but you are no longer locked into writing your markup strictly this way since you now have access to ANY part of the entire JSON tree.
Here's an example that does the same thing as above:
{
"$jason": {
"head": {
"data": {
"@": "$document.model"
},
"templates": {
"@": "$document.view.body"
}
}
},
"view": {
"body": {
"sections": [{
"items": {
"{{#each model.dwarfs}}": {
"type": "label",
"text": "{{username}}"
}
}
}]
}
},
"model": {
"dwarfs": [{
"username": "Doc"
}, {
"username": "Dopey"
}, {
"username": "Bashful"
}, {
"username": "Grumpy"
}, {
"username": "Sneezy"
}, {
"username": "Sleepy"
}, {
"username": "Happy"
}]
}
}
Combine this with remote mix-ins and you have something like:
{
"$jason": {
"head": {
"data": {
"@": "$document.model"
},
"templates": {
"@": "$document.view.body"
}
}
},
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"@": "https://blah.blah/dwarfs.json"
}
}
You can even mix-in the $jason
object from remote:
{
"@": "https://blah.blah/jason_skeleton.json",
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"@": "https://blah.blah/dwarfs.json"
}
}
where jason_skeleton.json
looks like this:
https://blah.blah/jason_skeleton.json
{
"$jason": {
"head": {
"data": {
"@": "$document.model"
},
"templates": {
"@": "$document.view.body"
}
}
}
}
2. Modularize and reuse
Once you get the hang of it, you'll come up with all kinds of creative ways of utilizing this feature. Let me explain one.
Let's go back to the dwarfs app example. What if we wanted to take the same app and just switch out the data to build a new app? Here's the original view:
https://blah.blah/view.json
{
"body": {
"sections": [{
"items": {
"{{#each model.dwarfs}}": {
"type": "label",
"text": "{{username}}"
}
}
}]
}
}
As you can see, the template makes two assumptions:
$jason.head.data.model
has an array called dwarfs
- The
dwarfs
array contains objects with the attribute username
.
So we immediately run into a problem. This view is not really reusable outside of this dwarfs app context. For example we may have an API that returns the following:
{
"response": {
"movies": [{
"title": "American Psycho"
}, {
"title": "Fight Club"
}, {
"title": "Matrix"
}, {
"title": "The Shining"
}]
}
}
First, let's fix the model.dwarfs
part. Let's switch it out with something that's more generic: model.items
{
"body": {
"sections": [{
"items": {
"{{#each model.items}}": {
"type": "label",
"text": "{{username}}"
}
}
}]
}
}
Now let's go back to the main JSON. Currently it looks like this:
{
"@": "https://blah.blah/jason_skeleton.json",
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"@": "https://blah.blah/dwarfs.json"
}
}
Let's change this since it wouldn't work anymore now that the view is expecting model.items
. We need to create a mapping that transforms model.dwarfs
into model.items
, like this:
{
"@": "https://blah.blah/jason_skeleton.json",
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"items": {
"@": "[email protected]://blah.blah/dwarfs.json"
}
}
}
Here we have used partial mixin (introduced in the last article on mixins) to select dwarfs
and assign it to $document.model.items
.
This solves the first problem.
Now, we still have one more problem to solve. We want to make the "text": "{{username}}"
part generic as well so it can be reused for any other cases. How can we create a mapping for this?
Let's go back to view.json
:
{
"body": {
"sections": [{
"items": {
"{{#each model.items}}": {
"type": "label",
"text": "{{username}}"
}
}
}]
}
}
Instead of "text": "{{username}}"
we will use a self-mixin.
{
"body": {
"sections": [{
"items": {
"{{#each model.items}}": {
"type": "label",
"@": "$document.adapter.label"
}
}
}]
}
}
Of course, this assumes that we have an adapter.label
object at root level, so let's go back and create it in the main JSON:
{
"@": "https://blah.blah/jason_skeleton.json",
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"items": {
"@": "[email protected]://blah.blah/dwarfs.json"
}
},
"adapter": {
"label": {
"text": "{{username}}"
}
}
}
Finally we have everything we need!
Now we can easily turn this into a Movies app which consumes the following API:
{
"response": {
"movies": [{
"title": "American Psycho"
}, {
"title": "Fight Club"
}, {
"title": "Matrix"
}, {
"title": "The Shining"
}]
}
}
To do this we:
- Switch out
model.items
.
- Update the
adapter.label
to "text": "{{title}}"
.
Here's the result:
{
"@": "https://blah.blah/jason_skeleton.json",
"view": {
"@": "https://blah.blah/body.json"
},
"model": {
"items": {
"@": "[email protected]://blah.blah/movies.json"
}
},
"adapter": {
"label": {
"text": "{{title}}"
}
}
}
Finale
Lambda
This concludes the series on the lambda
branch rollout. To summarize, here's the list:
- $labmda: Full functional programming in JSON. Including arguments, call stacks, return values, etc.
- $require: Parallel JSON requests
- mixins: Powerful JSON manipulation
Apps as toys
During the span of time it took me writing this single article, I could have probably made 100 apps with Jasonette. Jasonette makes it THAT easy to make apps.
With lambda
, require
, and mix-in
we take a huge step forward.
But we're still not there yet. More to come!
Making an app should be like putting together toy parts

27 Feb 2017
Have you met Frank, the ice cream truck guy? He takes a cone, adds a scoop of ice cream, maybe one more, adds some syrup, adds some sprinkles, and there you go, you have an ice cream cone!

He probably didn't make the sprinkles himself, he probably didn't make the syrup, and he probably didn't make the cone, but he sure can magically put them all together and make a really good ice cream cone, all in just ten seconds, and that's why we love him!
Same with Jasonette: You should not have to waste time reinventing the ice cream cone.
Ideally, you shouldn't even have to write a single line of JSON logic, but simply put together what already exist, and still perform your magic!
What is a Mix-in?
Jasonette Mix-ins let you compose multiple JSON objects into one. Since everything on Jasonette is written in JSON, this means you can mix in anything from actions to styles to templates!
You can use it to:
- Separate your JSON markup into multiple manageable modules
- Write reusable JSON modules to use in different projects
- Make your JSON module reusable and share it with the world!
Usage
You can implement a mixin simply by adding a key named "@"
and setting a URL as its value. Every time a Jasonette view loads, it:
- Looks at all occurrences of
"@": URL
pairs.
- Fetches all the URL content, in parallel.
- Lastly, replaces each mixin expression with returned objects.
1. Basic
Here's a mix-in expression:
{
"item": {
"@": "https://jasonbase.com/things/h3f.json"
}
}
Let's say https://jasonbase.com/things/h3f.json
contains a JSON object that looks like this:
{
"type": "label",
"text": "Hello",
"style": {
"font": "HelveticaNeue",
"color": "#ff0000"
}
}
When the mix-in is resolved, it fetches and merges this object into the original, becoming:
{
"item": {
"type": "label",
"text": "Hello",
"style": {
"font": "HelveticaNeue",
"color": "#ff0000"
}
}
}
2. Array
You can also mix-in an array of URLs (example: "@": [URL, URL,.., URL]
).
Here's an example where we mix-in the same JSON object 3 times:
{
"items": {
"@": [
"https://jasonbase.com/things/h3f.json",
"https://jasonbase.com/things/h3f.json",
"https://jasonbase.com/things/h3f.json"
]
}
}
When resolved, this becomes:
{
"items": [
{
"type": "label",
"text": "Hello",
"style": {
"font": "HelveticaNeue",
"color": "#ff0000"
}
},
{
"type": "label",
"text": "Hello",
"style": {
"font": "HelveticaNeue",
"color": "#ff0000"
}
},
{
"type": "label",
"text": "Hello",
"style": {
"font": "HelveticaNeue",
"color": "#ff0000"
}
}
]
}
How is Mix-in different from $require?
We've talked about the $require action in the last post. Let me explain how mixins are different before you get confused.
1. Mix-ins modify the JSON markup itself.
$require is an action, which means all JSON objects you fetch using $require stay on memory only while you're executing the next action. If you don't save it or use it in the succeeding action, the required JSON objects immediately go away. This is because $require fetches JSON objects straight to memory, independent from the main JSON markup tree.
However, Mix-ins are designed for modifying the very JSON markup itself.
When I say JSON markup, I mean the main JSON that Jasonette loads for the current view, with a format that looks like this:
{
"$jason": {
"head": { },
"body": { }
}
}
In fact, with mix-ins, your initial markup doesn't even have to contain the $jason
key initially--You can use mix-ins to dynamically construct the final markup.
Which means something like the following is possible with mix-ins:
{
"$jason": {
"head": {
"@": "https://jasonbase.com/things/333.json"
},
"body": {
"@": "https://jasonbase.com/things/enf.json"
}
}
}
as well as
{
"@": "https://jasonbase.com/things/111.json"
}
2. Mix-ins get resolved before interpretation
You already know how Jasonette works:
- Fetches a JSON markup from a URL
- Interprets the fetched JSON to construct a view
- Bootstraps an
actions
controller which takes care of handling actions
$require starts its lifecycle after step 3, since it's an action.
On the other hand, mix-ins get resolved on step 1 even before any interpretation is made. Here's the complete sequence:
- Fetches a JSON markup from a URL
- The mix-in engine looks for any
"@"
references
- If any exist, the mix-in engine fetches all the referenced JSON objects and mixes them in to construct the final JSON markup.
- Interprets the fetched JSON to construct a view
- Bootstraps an
actions
controller which takes care of handling actions
Features
Due to the recursive/composable nature of JSON, Mix-ins are infinitely flexible.
Let's take a look at some basic things you can do:
Multiple Mix-ins
There is NO limit to the number of times you can mix-in a remote JSON object into your main JSON. They all get fetched and mixed into the main JSON object, in parallel.
{
"model": {
"@": "https://jasonbase.com/things/3nf.json"
},
"view": {
"@": "https://jasonbase.com/things/13f.json"
},
"controller": {
"@": "https://jasonbase.com/things/ina.json"
}
}
Mix-ins Everywhere
You can use mix-ins anywhere in the JSON tree, as many times as you want.
Just remember that the mix-in resolution happens before any interpretation. The bootstrapping/rendering of the view comes after all this has completed.
{
"$jason": {
"head": {
"styles": {
"@": "https://jasonbase.com/things/3nf.json"
},
"templates": {
"@": "https://jasonbase.com/things/a33.json"
},
"actions": {
"oauth": {
"@": "https://jasonbase.com/things/4nf.json"
},
"$load": {
"trigger": "oauth",
"success": {
"type": "$render"
}
}
}
}
}
}
Inheritance
Going extreme, you can even mix-in an entire JSON object to inherit from it.
{
"@": "https://jasonbase.com/things/3nf.json"
}
You may be asking "Why would I do that?". Which brings us to....
Overriding
In many cases you probably want to:
- Mix-in some generic JSON module
- Then override some of the JSON attributes with your own custom values.
Above example of mixing in an entire JSON is such a case. It becomes really powerful when you can mix in a JSON object AND override on top of that--it effectively becomes inheritance.
Let's say https://jasonbase.com/things/3nf.json
contained the following JSON:
{
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}
Here's a mix-in expression that references this:
[{
"firstname": "Bart",
"@": "https://jasonbase.com/things/3nf.json"
}, {
"firstname": "Homer",
"@": "https://jasonbase.com/things/3nf.json"
}, {
"firstname": "Lisa",
"@": "https://jasonbase.com/things/3nf.json"
}, {
"firstname": "Maggie",
"@": "https://jasonbase.com/things/3nf.json"
}, {
"firstname": "Marge",
"@": "https://jasonbase.com/things/3nf.json"
}]
When resolved, it merges in the remote JSON object for each, and also sets the local custom attribute "firstname"
on top of that, becoming:
[{
"firstname": "Bart",
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}, {
"firstname": "Homer",
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}, {
"firstname": "Lisa",
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}, {
"firstname": "Maggie",
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}, {
"firstname": "Marge",
"lastname": "Simpson",
"address": "742 Evergreen Terrace",
"city": "Springfield"
}]
Partial Mix-in
Sometimes you only want to import ONLY a part of a remote JSON object. Let's look at an example:
{
"posts": [{
"title": "Hello World",
"content": "Lorem Ipsum blah blah",
"comments": [{
"username": "Kat",
"message": "Great job!"
}, {
"username": "Sophie",
"message": "You suck!"
}]
}]
}
We can mix-in the entire object with:
{
"@": "https://jasonbase.com/things/n3f.json"
}
But what if we only wanted the comments
array from the first post? Simple! Just prepend the URL with the path:
Performance? No Problem!
As mentioned in the $require article, the performance for parallel loading is not much different from loading a single JSON object, you will fail to notice any difference!
The biggest concern I had when first working on this feature was performance. For some reason I had this idea that on mobile, only a single network request should be made at a time.
Turns out, this was absolutely a non-issue! Upon actually trying it out on my iPhone and Android, I found that there is no noticeable difference!
I thought about why this is so, and in retrospect it kind of makes sense. Here's the reasoning:
Think about a typical app where the view displays multiple items, each with an image and some text. When you load this view, it's going out there and concurrently fetching EVERY image and displaying it on the screen. Which means, this type of concurrent requests have existed on a low level, and have already been working fine without me realizing. And in most cases JSON files are significantly smaller than images. If concurrent image downloads work fine, concurrent JSON downloads should have no problem!
(from the $require.json article)
One more thing...
My original goal was to make this the final post of the series.
But there's one more type of Mix-in which takes all I've explained here to a whole new level.
This requires its own post, so I am going to write another article on this soon. Stay tuned!
17 Feb 2017
The $network.request action is used to dynamically fetch a single remote JSON file. But what if you want to fetch as many JSON files as you want, simultaneously?
Welcome to the world of $require.

Why would I want to do that?
Maybe you need to compose multiple sets of data to display to the view.
Maybe you need to fetch JSON objects from multiple different servers, each for a different purpose.
Or just maybe, you're building a completely decentralized networking app which needs to hit up every node individually!
Just remember that EVERYTHING on Jasonette (models, actions, views, templates, styles, or whatever) is expressed in JSON, which means you can dynamically require any part of your app.
In any case, this requires a powerful parallel networking feature.
Problem
Let's say we wanted to fetch a remote JSON object and assign it to a local variable:
{
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/posts"
},
"success": {
"type": "$set",
"options": {
"posts": "{{$jason}}"
}
}
}
- We use $network.request to fetch some posts as JSON.
- Then we assign the result to a local variable
posts
, using the $set action.
Now, what if we wanted to fetch from 6 different resources and do the same thing? Here's the code:
{
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/posts"
},
"success": {
"type": "$set",
"options": {
"posts": "{{$jason}}"
},
"success": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/comments"
},
"success": {
"type": "$set",
"options": {
"comments": "{{$jason}}"
},
"success": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/albums"
},
"success": {
"type": "$set",
"options": {
"albums": "{{$jason}}"
},
"success": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/photos"
},
"success": {
"type": "$set",
"options": {
"photos": "{{$jason}}"
},
"success": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/todos"
},
"success": {
"type": "$set",
"options": {
"todos": "{{$jason}}"
},
"success": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/users"
},
"success": {
"type": "$set",
"options": {
"users": "{{$jason}}"
}
}
}
}
}
}
}
}
}
}
}
}
}
There are two problems:
- The code is too long
- It will be 6 times slow because it runs these network requests one after one, serially.
Meet $require.
Now comes $require to the rescue:
{
"type": "$require",
"options": {
"posts": "https://jsonplaceholder.typicode.com/posts",
"comments": "https://jsonplaceholder.typicode.com/comments",
"albums": "https://jsonplaceholder.typicode.com/albums",
"photos": "https://jsonplaceholder.typicode.com/photos",
"todos": "https://jsonplaceholder.typicode.com/todos",
"users": "https://jsonplaceholder.typicode.com/users"
},
"success": {
"type": "$set",
"options": {
"posts": "{{$jason.posts}}",
"comments": "{{$jason.comments}}",
"albums": "{{$jason.albums}}",
"photos": "{{$jason.photos}}",
"todos": "{{$jason.todos}}",
"users": "{{$jason.users}}"
}
}
}
No kidding, this is it! This code does exactly the same thing as above!
Furthermore it's 6 times faster since the requests are made concurrently.
Basically, $require
waits until all of the requests have returned (either success or failure), and then calls its success
callback with the returned JSON objects.
To reiterate:
- The code is much shorter
- Will be 6 times faster since the network requests are run in parallel
Syntax
Let's get into the actual syntax.
Just like any other actions, the $require
action takes an options
object. There are two patterns:
- Key: URL String
- Key: URL Array
1. Key: URL String
The same syntax we saw above. Basically, the $require
action looks at all key: value
pairs in the options
object, fetches all the URL strings, and then assigns each result to its corresponding key of the return value.
{
"type": "$require",
"options": {
"posts": "https://jsonplaceholder.typicode.com/posts",
"comments": "https://jsonplaceholder.typicode.com/comments"
},
"success": {
"type": "$set",
"options": {
"jasonplaceholder_posts": "{{$jason.posts}}",
"jasonplaceholder_comments": "{{$jason.comments}}"
}
}
}
In this example, the keys are posts
and comments
, so you can access the results in the succeeding action ($set
) using {{$jason.posts}}
and {{$jason.comments}}
.
2. Key: URL Array
You can also have an array of URLs (instead of a single URL string) as the value.
{
"type": "$require",
"options": {
"result": ["https://jsonplaceholder.typicode.com/posts", "https://jsonplaceholder.typicode.com/comments"]
},
"success": {
"type": "$set",
"options": {
"jasonplaceholder_posts": "{{$jason.result[0]}}",
"jasonplaceholder_comments": "{{$jason.result[1]}}"
}
}
}
In this example, we only have a single key (result
) and the value is an array of URLs. So when we fetch these remote JSON content, we push them into the result
array. Once all JSON responses have returned, we go on to the next action $set
, where we can access them using {{$jason.result[0]}}
and {{$jason.result[1]}}
.
Performance
The biggest concern I had when first working on this feature was performance. For some reason I had this idea that on mobile, only a single network request should be made at a time.
Turns out, this was absolutely a non-issue! Upon actually trying it out on my iPhone and Android, I found that there is no noticeable difference!
I thought about why this is so, and in retrospect it kind of makes sense. Here's the reasoning:
Think about a typical app where the view displays multiple items, each with an image and some text. When you load this view, it's going out there and concurrently fetching EVERY image and displaying it on the screen. Which means, this type of concurrent requests have existed on a low level, and have already been working fine without me realizing. And in most cases JSON files are significantly smaller than images. If concurrent image downloads work fine, concurrent JSON downloads should have no problem!
Note
$require
has one job--fetch multiple JSON files in parallel--and it doesn't try to be more than that.
1. Only GET request
Since $require
is more about requiring multiple JSON files and not about actually making requests that will update things on the server, every $require
is actually a GET
request under the hood.
2. Only JSON type
$require is strictly for fetching JSON.
If you want to fetch HTML, RSS, or any raw content, these are not meant to be done in parallel and you need to use $network.request.
Conclusion
Parallel network requests can be extremely powerful, especially considering how literally EVERYTHING on Jasonette is expressed in JSON.
This includes all of model, view, controller logic.
All you need to do is:
- Require some JSON object
- Assign them to a local variable
- Use it anywhere!
What's possible is only bound by your imagination.
I've been personally experimenting with $require and can see there's all kinds of potentially interesting use cases. If you find a clever use case, please share!
15 Feb 2017
Today, let me show you something you have never seen--a programming language written in JSON.
And not just any programming, but functional programming.

Here's the summary of this article:
- Anatomy of a function
- How to write a function in JSON
- Expressing function call stacks and return values in JSON
Note: This post discusses the technology behind Jasonette, an open source framework that lets you make cross-platform mobile apps with just a JSON markup.
Expressing all of Model-View-Controller logic in pure JSON is not a simple task, and each deserves its own article. I have already written an article about the view-side logic.
But in this article, it's all about the controller logic. More specifically, functions.
1. Anatomy of a function
Programming languages are supposed to carry out useful tasks. Normally these exist in the form of functions. Let's take a look at Javascript for example.
1. A function has a name
and arguments
.
Names let you reference functions in a unique manner.
You pass Arguments to functions so they can be processed.

2. Callback
is when you pass a function as an argument to another function.
Callbacks are important in any application that involves asynchronous tasks such as network requests, processing user interactions, etc. because you have to delay the callback function's execution until it's time.

So the question is: How can we use a JSON object to describe things like this?
2. Writing a function in JSON
Jasonette has something called actions. Actions describe tasks. Each action consists of up to four attributes:
type
: name of a native function to run
options
: arguments to pass to the function
success
: success callback to run when the function returns success
error
: error callback to run when the function returns error
Using just these four attributes, you can build any kind of fully functional app.
Arguments
Functions are not so meaningful without arguments. We want a function to perform different actions based on the arguments we pass to it.
Here we pass title
and description
attributes to $util.alert action to create a custom alert dialog.
{
"type": "$util.alert",
"options": {
"title": "Basic Alert",
"description": "I'm a basic alert. I simply display an alert that needs to be dismissed before moving forward"
}
}
When you run this action on Jasonette, It displays an alert that looks like the following:
iOS
Android
Callbacks
Since most things that happen on mobile devices are asynchronous in nature, callbacks are first-class citizens and built into actions on Jasonette.
There are two types of callbacks: success
and error
. success
gets called when the action succeeds. error
when it fails.
Here's an example of a success
callback:
{
"fetch": {
"type": "$network.request",
"options": {
"url": "https://jsonplaceholder.typicode.com/posts"
},
"success": {
"type": "$render"
}
}
}
Here's what it does:
- Makes a network request ($network.request) to jsonplaceholder server
- Passes that result to its
success
callback action--which is another action called $render--which renders the result using whichever template you define (also in JSON).
- We name the action
fetch
by wrapping it with the key.
Evaluation
Since the native language of JSON is Javascript (JSON is short for JavaScript Object Notation), Jasonette implements evaluation using a built-in Javascript engine. If you want to evaluate something, simply wrap it inside a template expression ({{ }}
).
Inline Javascript means we can do some crazy stuff like this:
{
"fetch": {
"type": "$network.request",
"options": {
"url": "https://.....",
"method": "POST",
"data": {
"guid": "{{var str=$cache.guid; var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; for ( var block, charCode, idx = 0, map = chars, output = ''; str.charAt(idx | 0) || (map = '=', idx % 1); output += map.charAt(63 & block >> 8 - idx % 1 * 8)) { charCode = str.charCodeAt(idx += 3/4); if (charCode > 0xFF) { throw new InvalidCharacterError('btoa failed'); } block = block << 8 | charCode; } return output;}}"
}
},
"success": {
"type": "$render"
}
}
}
Here's what's going on:
- We try to make a network request using the data specified inside
options.data
.
- But the value of
guid
is a template expression, so the interpreter first executes the Javascript inside the template expression to determine the final value.
- If you look closely at the Javascript code, it takes the
$cache.guid
($cache is a global variable for persisting data on the device) and generates a hash from it. It's basically a manual implementation of javascript's native btoa function.
- After all that's done, it finally makes the network request with the final value.
- Then it calls
$render
via its success
callback.
Intermission
Everything below this point is completely NEW to Jasonette with the latest release.
Transition from Message dispatch to Function calls
So far I made it sound like actions on Jasonette are like functions. But it was only half true.
How it used to work
In the previous versions of Jasonette, every action would terminate immediately after calling its success
or error
callback. Here's what a typical action call chain looked like:
- Action 1 calls Action 2 and terminates.
- Action 2 does its job, and calls Action 3, then terminates.
- Action 3 does its job, and calls Action 4, then terminates. etc.
While not perfect, this model works fine because each action callback passes its result onto the next action (packaged as a variable called $jason
), and as long as each action keeps doing its job correctly and propagates the correct value, the last action in the call chain would end up with expected results.
Problem
The probelm is, you can't create subroutines with this architecture. It's impossible to do something as straight-forward as:
- Action 1 calls Action 2 and waits.
- Action 2 finishes running, and sends a return value back to Action 1.
- Action 1 picks up where it left off and carries on with the return value from Action 2.
It's impossible because every action immediately terminates after triggering another action--it can't wait for its subroutine to return.
In this sense, calling an action
was more like a message dispatch than a function.
Functions have call stacks, their own local states, and most importantly, return values. And there are no such things when you're simply dispatching messages.
Without a way to implement subroutines:
- It's impossible to write modular code
- Writing recursive algorithms is not trivial

This was not a serious problem initially, when most people just used Jasonette to write small apps and prototypes. But as people started to realize they can actually write production apps this way, this became problematic because they started writing thousands of lines. Imagine reading through thousands of lines of JSON code with absolutely no modularity.
Expressing function call stacks & return values in JSON
To address this we needed a way for an action to:
- Invoke another action
- Wait for the callee action to return, and continue on with the return value once it returns.
Also it would be best if we didn't invent a new concept just for this, but instead simply come up with just another new action to achieve this.
So $lambda and $return were born.
$lambda
$lambda is a special purpose action whose sole purpose is to trigger another action. Unlike other actions which carry out some task, it only functions as a mediator that
- Executes another action
- Waits for it to return
- Resumes and starts executing the next action with the return value
The $lambda
action takes two arguments as its options
:
name
: The name of the function to trigger
options
: An options object to pass to the triggering action.
Let's take a look at an example usage of $lambda
:
{
"fetch": {
"type": "$lambda",
"options": {
"name": "btoa",
"options": {
"guid": "{{$cache.guid}}"
}
},
"success": {
"type": "$network.request",
"options": {
"url": "https://.....",
"data": {
"guid": "{{$jason.hashed}}"
}
},
"success": {
"type": "$render"
}
}
}
}
In this example,
- We invoke an action called
btoa
(which we will come back to in the next section) using $lambda
.
- Then the
$lambda
action waits until the btoa
action completes its task and returns.
- Finally when that happens, the
$lambda
action's success
callback gets executed.
- Note that the success action is a $network.request action that uses the return value from
btoa
in the form of the variable $jason
.
$return
$return
is actually not a single action but a category of actions. There are two:
- $return.success : Used for returning values on success. This will backtrack to the current action's caller action and execute its
success
callback.
- $return.error : Used for returning an error. This will backtrack to the current action's caller action and execute its
error
callback.
There are two ways of returning--with return value and without return value
- Without return value: If the action doesn't need to return any value, simply doing
"type": "$return.success"
is enough to return the control back to the caller action.
- With return value: However if you wish to send a return value back to the caller action, you will need to set the
options
.
For example, when you $return.success
this way:
{
"myname": {
"type": "$return.success",
"options": {
"firstname": "Bart",
"lastname": "Simpson"
}
}
}
You will be able to access the options
object as $jason
in the caller action's success
callback. Here's an example:
{
"type": "$lambda",
"options": {
"name": "myname"
},
"success": {
"type": "$util.toast",
"options": {
"text": "My name is {{$jason.firstname}} {{$jason.lastname}}"
}
}
}
Notice how the $util.toast is accessing the $jason.firstname
and $jason.lastname
values after the myname
action returns.
Circling back to our btoa
action, here's what it looks like when we extract the btoa
action out as a standalone function. All it does is compute the hash and return. (It's basically a manual implementation of the native btoa function.
{
"btoa": {
"type": "$return.success",
"options": {
"hashed": "{{var str=$jason.guid; var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; for ( var block, charCode, idx = 0, map = chars, output = ''; str.charAt(idx | 0) || (map = '=', idx % 1); output += map.charAt(63 & block >> 8 - idx % 1 * 8)) { charCode = str.charCodeAt(idx += 3/4); if (charCode > 0xFF) { throw new InvalidCharacterError('btoa failed'); } block = block << 8 | charCode; } return output;}}"
}
}
}
Notice that the function uses var str=$jason.guid;
(previously it was var str=$cache.guid;
).
$jason
is the argument passed in from the caller action, which means it only exists within this local scope. The function doesn't use global variables like $cache
anymore.
Simplifying $lambda with 'trigger'
$lambda
actions can be a bit verbose, so there's a syntactic sugar for calling $lambda
actions.
Instead of using the $lambda
action directly, you can use the trigger
keyword to shorten it down.
Instead of the following $lambda
action:
<Action> ::= {
"type": "$lambda",
"options": {
"name": <Action Name>,
"options": <Arguments object>
},
"success": <Action>,
"error": <Action>
}
We can use the trigger
notation like this:
<Action> ::= {
"trigger": <Action Name>,
"options": <Arguments object>,
"success": <Action>,
"error": <Action>
}
For example, instead of this:
{
"type": "$lambda",
"options": {
"name": "some_action",
"options": {
"key1": "value1",
"key2": "value2"
}
},
"success": {
"type": "$render"
},
"error": {
"type": "$render"
}
}
You can use:
{
"trigger": "some_action",
"options": {
"key1": "value1",
"key2": "value2"
},
"success": {
"type": "$render"
},
"error": {
"type": "$render"
}
}
Stay Tuned for Part 2 and 3
If you read this far, you're either thinking:
- "This is the awesomest thing since Jasonette!" (probably like 5% of you)
- or, "Yeah cool story bro, now you can do some hipster functional stuff, so what?" (the rest 95%)
I think those of you who have already written long lines of JSON code may immediately get the benefit since it directly deals with your pain point. But even if you're in the group #2, don't feel bad!
Because this is the first piece of the puzzle towards introducing total modularity to Jasonette, and I have two more posts coming up where I will talk about how all this fits into the picture.
Stay tuned for the next one very soon.