X
X

Login

Login if you already have an account

LOGIN

Register

Create a new account. join us!

REGISTER

Support

Need some help? Check out our forum.

FORUM
Welcome to our Blog

The Post

FYI – FatFractal now provides textual term search for NoServer apps!


As a developer, I want to be able to retrieve information from my backend using search technology so that I can create even more powerful queries and get super fast responses.

You can see working code for everything below (here).
You can access the source code for the sample application (here).

We are really excited to announce that we our latest release includes full textual term search for all your data that is stored on FatFractal NoServer applications. This opens up an entirely new set of options for your queries and they are super fast to boot!

How it works:

We have recently started to use elasticsearch – a superb product by the way, and a future post will outline why we switched to it – as one of the data stores for your app’s data. Basically, as before, everything that is stored is fully indexed for you automatically without any configuration of your application or schema required. In addition, our implementation does not impose any additional overhead on any interaction with your data (Create, Read Update or Delete), but it has vastly improved the response times for all queries and we have added full textual term search as well.

How to use it:

We have added two new operators that you can use in your queries, “contains_all” and “contains_any”. These provide textual term search capability for queries that looks for, you guessed it, ANY submitted term matches or ALL submitted terms match.
For more information, you can find the documentation for the FatFractal Query Language (here).

Examples:

As usual, we have created a sample application to illustrate this, you can try the application (here), and the source code for the application is (here) and also play with the databrowser for the application’ backend (here).

The sample application uses a Movies collection that holds Movie objects. The movie objects have a member called “description” which we will be searching.

The model for Movie is as follows:

function Movie() {
this.title = null;
this.description = null;
this.year = null;
return this;
}
We have populated the collection with two Movies as shown below:

{
"title": "The Conjuring",
"description": "Paranormal investigators Ed and Lorraine Warren work to help a family terrorized by a dark presence in their farmhouse. Forced to confront a powerful entity, the Warrens find themselves caught in the most terrifying case of their lives.",
"year": 2013
},
{
"title": "Grown Ups 2",
"description": "After moving his family back to his hometown to be with his friends and their kids, Lenny finds out that between old bullies, new bullies, schizo bus drivers, drunk cops on skis, and 400 costumed party crashers sometimes crazy follows you.",
"year": 2013
}
So, now let’s create a couple of queries that use free text search.

Search using contains_any

First, we will search the Movies collection for any Movie objects whose description member contain any one of two terms (for example, “family” and “terrorized”). The query looks like this:

/Movies/(description contains_any 'family terrorized')
The code looks like this:
function searchAny() {
var eli = document.getElementById('movies-search-any-input');
ff.getArrayFromUri("/ff/resources/Movies/(description contains_any '" + eli.value + "')", function(movies) {
// handle success
}, function(code, msg) {
// handle error
});
}
Since “family” is contained in both “The Conjuring” as well as “Grown Ups 2” descriptions, this query will return both objects.

Search using contains_all

Next, let’s use the same search terms, but use the contains_all operator, which will search for any Movie objects whose description member contain both search terms.

/Movies/(description contains_all 'family terrorized')
The code looks like this:
function searchAll() {
var eli = document.getElementById('movies-search-all-input');
ff.getArrayFromUri("/ff/resources/Movies/(description contains_all '" + eli.value + "')", function(movies) {
// handle success
}, function(code, msg) {
// handle error
});
}
In this case, the query will return only “The Conjuring” as it’s descrption contains both terms and “Grown Ups 2” does not.

As mentioned above, these operations are extremely fast and efficient as any data that is stored on your backend is fully indexed automatically as soon as it is created or modified.

Have fun!

Kevin

FatFractal Console 2.0

As you may have noticed, the FatFractal Console recently underwent a major upgrade, and we’d like to talk a little bit about what’s new.

The most obvious change is the look and feel. Following in the footsteps of the Data Browser and the rest of the internet, the new Console now uses Bootstrap for a nice, consistent and functional interface. As you probably know, Bootstrap makes web development a lot simpler, giving you a lot of good-looking styles for basic interface elements and layout for free.

A less obvious but more important change is the frontend framework. We are now using AngularJS, and were really impressed with the ease of development. Angular also encourages a very maintainable code organization and separation of concerns, which will make future updates a lot easier (and thus more frequent). Overall, we were really impressed with Angular and very glad to have made the leap for this Console upgrade. The new interface is clean and fast, and we think you’ll like it a lot.

Major new functionality has been added as well. Now that we have left public beta, the new Console lets you manage your accounts and subscriptions. Subscriptions are the way you choose the service level for your applications; everyone gets free Sandbox subscriptions when they sign up. When you’re ready for production, subscriptions are the way to choose your limits for things such as API calls, how many domains and applications you need, backup settings, etc. The Console is also your destination for app analytics. Wonder how many API calls you’ve used this month, or what your app’s average response time is? The Console is the place to find out.

Finally, it’s worth mentioning something that hasn’t changed: The FatFractal Console is a NoServer application: all of the Console business logic, including accounts and billing, is implemented as event handlers, server extensions, and scheduled code. In other words, the Console is running atop the same FatFractal backend available to you. Can Parse or StackMob say the same? I sincerely doubt it.

We’re very excited about the new Console, and there’s more yet to come! We will be continuously rolling out new features and improvements to make your development work even easier.

Emerging from Beta – Thank you to everyone!

I would like to express my sincere thanks to the FatFractal team and to all of our beta testers over the last months for all of their efforts and collaboration. As a result of lots of hard work, we emerged from Beta today.

What does this mean?

New Console

If you look at the new console application (see it here), you will see some new options. Some relate to setting up accounts and payment methods. But don’t worry, your apps are all safe and you will have lots of options for development and production, including free ones. We have also added a number of features and a new look and feel to the console application, including:

  • App and domain search
  • App metrics
  • Improved navigation

New Pricing

We have updated our pricing model and are pleased to offer the most competitive pricing in the industry, made possible by our unique architecture — optimized top to bottom to provide the most efficient application frameworks to developers for your applications. You can see our new pricing at the following:

  • NoServer application pricing is here.
  • Ruby and Java/Servlet application is here

New Features and Improvements

We have also released a new version of the platform and SDKs with a lot of new features there as well. One of the most exciting new features is that NoServer now supports full textual term search on your data (eg description contains_any ‘BaaS PaaS’) – check out the Release Notes!

Questions? Feedback?

We would love to hear your questions and feedback on the console application as well as our pricing. Please share your thoughts with us (click here).

FAQ:
Q: I am still in development with my app, do I need to do anything?
A: No, we believe that asking developers to pay during development would inhibit development of cool new stuff, and we never, ever want to inhibit developers from developing cool new stuff.

Q: My app is being used by real customers, do I need to do anything?
A: We now have a development “sandbox” separate from “production”. If your app is in use, you should migrate to “production” to ensure that your data is best protected and your application is always available.

Q: When will the new pricing take effect?
A: The new pricing takes effect immediately when you create a subscription for your application and move it out of the sandbox. Ruby and Servlet apps have a 30-day trial period, after which time they will be required to have a paid subscription.

Q: I have more than three applications or domains already. Do I need to remove them?
A: No, your existing apps will all continue to work. However, in the next few weeks we will ask that such legacy apps be moved into either your sandbox subscription or a production subscription where possible.

Q: What is the difference between Sandbox and the other tiers for NoServer apps?
A: The most important distinction between Sandbox and non-Sandbox apps is that in Sandbox the data is not guaranteed or backed up in anyway. So, if you have data that can’t be lost, you should be in production. Sandbox apps also are subject to usage limits for bandwidth, API calls, and storage.

Q: I see that Ruby and Servlet apps have a 30 day free trial period. Why is this different from the SandBox for NoServer apps?
A: Ruby and Servlet apps have to be provisioned differently than NoServer apps. They are allocated reserved instances from the beginning and as a result, we have elected to provide 30 day free trial period as the best means of helping developers get started.

FYI – FatFractal improves authentication support with full OAuth 1.0 and OAuth 2.0 support


User authentication is an ages old problem for developers that has greatly improved recently thanks to the emergence of trusted providers such as Twitter and Facebook.

FatFractal has provided integrated authentication with Facebook and Twitter on the client-side for some time. We have just released a major upgrade to our backend support for full OAuth 2.0 as well as OAuth 1.0 using the Scribe library.

Implementing single-sign-on using a trusted provider like Facebook or Twitter makes a lot of sense. Now, implementing this has gotten a lot easier. The basic steps to using either as an authentication provider with FatFractal are:

  1. Register your application with the provider
  2. Add the keys from one or both to the Auth.js file that is created during application scaffolding
  3. Implement the auth life-cycle in your application

Full documentation for the FatFractal ScriptAuth process is found here

You can see working code for everything below (here).

First, you need to add the application keys for Twitter and/ or Facebook into the Auth.js file that is automatically created for you when you scaffold your application with FatFractal. The Auth.js code looks like this:

auth.setScribeApiClassName(TWITTER, "org.scribe.builder.api.TwitterApi");
auth.setScribeApiKey(TWITTER, "twitter_api_key");
auth.setScribeApiSecret(TWITTER, "twitter_api_secret");

auth.setScribeApiClassName(FACEBOOK, "org.scribe.builder.api.FacebookApi");
auth.setScribeApiKey(FACEBOOK, "facebook_app_id");
auth.setScribeApiSecret(FACEBOOK, "facebook_app_secret");

You need to replace the ApiKey and ApiSecret values with the corresponding values for Facebook and/ or Twitter. Then, the basic components needed for the sample app above are (in HTML/Javascript) are quite straightforward:

  1. Create a login for Facebook function
  2. Create a login for Twitter function
  3. Create a page that will handle process the callback from the provider and redirect back the application page with the user logged in

Next, we set up the callback URI that both will use (you could also create separate pages fors handling Facebook or Twitter if you prefer).

var callbackUri = ff.getBaseUrl() + "authorize.html";
sessionStorage.setItem("ff-callback-uri", callbackUri);
ff.setCallbackUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK, callbackUri);
ff.setCallbackUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_TWITTER, callbackUri);
Note that we are saving the callback in sessionStorage as we will want to use that later from the authentication page.

Here is the code for launching the Facebook login process:

// Facebook login
function facebookLogin() {
ff.authUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK,
function(authUri) {
sessionStorage.setItem("ff-auth-provider", "FACEBOOK");
window.location = authUri;
}, function(code, msg) {
console.error("facebookLogin() Error: " + code + " " + msg);
});
}

And, here is the code for launching the Twitter login process:

// Twitter login
function facebookLogin() {
ff.authUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK, function(authUri) {
sessionStorage.setItem("ff-auth-provider", "FACEBOOK");
window.location = authUri;
}, function(code, msg) {
console.error("facebookLogin() Error: " + code + " " + msg);
});
}
Note that we are also saving the authentication provider in sessionStorage as well in order to have a single page to handle the response.

var callbackUri = sessionStorage.getItem("ff-callback-uri");
var provider = sessionStorage.getItem("ff-auth-provider");
var ff = new FatFractal();
if(provider == "FACEBOOK") {
ff.setCallbackUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK, callbackUri);
ff.retrieveAccessTokenForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK, location.href, function() {
ff.loginWithScriptAuthService(ff.SCRIPT_AUTH_SERVICE_FACEBOOK, function(user) {
var msg = "Success! Logged in as " + user.guid;
var el = document.getElementById('status');
el.innerHTML = "<br><div class = 'well'>Logged in with Facebook - message: " + msg + "</div>";
window.location = "index.html";
});
});
} else if(provider == "TWITTER") {
var requestToken = JSON.parse(sessionStorage.getItem("ff-tw-request-token"));
sessionStorage.removeItem("ff-tw-request-token");
ff.setCallbackUriForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_TWITTER, callbackUri);
ff.setRequestTokenForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_TWITTER, requestToken);
ff.retrieveAccessTokenForScriptAuthService(ff.SCRIPT_AUTH_SERVICE_TWITTER,
location.href, function() {
ff.loginWithScriptAuthService(ff.SCRIPT_AUTH_SERVICE_TWITTER, function(user) {
var msg = "Success! Logged in as " + user.guid;
var el = document.getElementById('status');
el.innerHTML = "<br><div class = 'well'>Logged in with Twitter - message: " + msg + "</div>";
window.location = "index.html";
});
});
} else console.error("Could not determine the OAuth provider");
When the callback is received, this page will complete the authentication process, create the logged in user and session and redirect back the original page logged in.

That’s it,

Kevin

FYI – Datagraph with Objects and Collections


As a developer, I want to have complete control of my objects and collections on the backend.

There are so many terms being thrown around these days that it is often difficult to separate the truth from the marketing hype. So – at FatFractal, when we talk about our Datagraph capabilities, we mean a real graph, not marketing hype. To illustrate, let me show you a couple of simple examples.

You can see working code for everything below (here).
You can access the source code for the sample application (here).

Most of the time, you will define an object and map it to a identical collection.

Let’s start with couple of simple object definitions:

function Movie() {
this.title = null;
this.description = null;
this.year = null;
}
function Actor() {
this.firstName = null;
this.lastName = null;
}

Then, we add the following to our FFDL (what’s this?), to define these object types and collections on the backend as follows:

CREATE OBJECTTYPE Movie (title STRING, description STRING, year NUMERIC)
CREATE OBJECTTYPE Actor (firstName STRING, lastName STRING)
CREATE COLLECTION /Movies OBJECTTYPE Movie
CREATE COLLECTION /Actors OBJECTTYPE Actor

Note – that the two collections are typed to an object type (Movie and Actor), which means that attempting to store a Movie in the Actors collection or vice-a-versa will generate a validation error.

But, let’s say that you want to create a collection of favorites and allow it to hold different object types, while also still being able to distinguish them from each other. No problem, to do that, let’s add a new collection called Favs that is not typed:

CREATE COLLECTION /Favs OBJECTTYPE *

Examples:

First, let’s store an object in a collection typed to a Movie object type:

var m = new Movie();
m.title = "Argo";
m.description = "Argo is a 2012 historical drama thriller film directed by Ben Affleck.";
m.year = 2012;
ff.createObjAtUri(m, "/Movies");

Now – let’s try saving a Movie to the Favs collection…

ff.createObjAtUri(m, "/Favs");

Similarly, you can store an Actor in the Actors collection or in the Favs collection…

var a = new Actor();
a.firstName = "Ben";
a.lastName = "Affleck"
FatFractal.createObjAtUri(a, "/Actors");
FatFractal.createObjAtUri(a, "/Favs");

But, if you try to store a Movie in the Actors (or vice-a-versa) collection, you will get an error…

FatFractal.createObjAtUri(m, "/Actors");

Now – let’s see how you can retrieve objects of a particular class from a collection that holds more than one object type.

Get all the Movie objects from the Favs collection…

ff.getArrayFromUri("/ff/resources/Favs/(clazz eq 'Movie')", function(r) {
// handle success
}, function(code,message){
// handle error
});

Get all the Actor objects from the Favs collection…

ff.getArrayFromUri("/ff/resources/Favs/(clazz eq 'Actor')", function(r) {
// handle success
}, function(code, message){
// handle error
});

Get all the objects from the Favs collection…

ff.getArrayFromUri("/ff/resources/Favs/", function(r) {
// handle success
}, function(code, message){
// handle error
});

That’s it – we hope that you will agree that this is another example of FatFractal being the most flexible, robust and capable backend for your app – enjoy!

Kevin

FYI – Retrieve an object graph in a single query with FatFractal


As a developer, I want an easy to navigate data model (a datagraph) so that I can get the data I want with fewer API calls which increases my applications performance and saves me money.

We have added a new capability that allows you to retrieve an object graph (the object as well as all of its REFERENCES and GRABBAGS) in a single API call. This can improve the the performance of your application and reduce the “chattiness” of using your API.

Previously, you could retrieve an object from a URI such as:

http://telluride.fatfractal.com/tff39/ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4

For which you would get a response like this…[toggle title="Click to see response"]

{
"result":
[
{
"ffUserCanEdit": false,
"ffUrl": "/ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4",
"qa": false,
"ffRL": "/Showings",
"updatedBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"version": 1,
"updatedAt": 1346642155713,
"guid": "e-06R5_d_FfHXKHSCx-ky4",
"ffRefs":
[
{
"name": "theater",
"type": "FFO",
"url": "/ff/resources/Theaters/h3uX2Gt1j74w4yYbcifNq6"
},
{
"name": "film",
"type": "FFO",
"url": "/ff/resources/Films/KG09l8GvwRc9pUzXGMTEJ4"
}
],
"createdBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"createdAt": 1346642155713,
"datetime": 1315094400000,
"clazz": "Showing"
}
],
"statusMessage":"Retrieved 1 resources from /ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4"
}
[/toggle] The response includes the object itself (in ‘result’), and includes the URIs for any references (in this case, there are two). The FatFractal SDKs would then retrieve the referenced objects (requires a minimum of two additional queries, plus even more if these objects contain references or grabbag items themselves). That makes for a lot of round trips for the queries which can be expensive and adversely impact your application performance.

Get More for Less

Now you can access the entire datagraph from the object instance at a specified depth by adding the depthRef (depth for references) and depthGb (depth for grabbags) parameters:

http://telluride.fatfractal.com/tff39/ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4?depthRef=1&depthGb=1

This will return the object AND all of the object’s REFERENCES and GRABBAGS that the user has permission to read in a single response.

The response will now look like this…[toggle title="Click to see response"]

    "result":
[
{
"ffUserCanEdit": false,
"ffUrl": "/ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4",
"qa": false,
"ffRL": "/Showings",
"updatedBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"version": 1,
"updatedAt": 1346642155713,
"guid": "e-06R5_d_FfHXKHSCx-ky4",
"ffRefs":
[
{
"name": "theater",
"type": "FFO",
"url": "/ff/resources/Theaters/h3uX2Gt1j74w4yYbcifNq6"
},
{
"name": "film",
"type": "FFO",
"url": "/ff/resources/Films/KG09l8GvwRc9pUzXGMTEJ4"
}
],
"createdBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"createdAt": 1346642155713,
"datetime": 1315094400000,
"clazz": "Showing"
}
],
"references":
[
{
"ffUserCanEdit": false,
"filmType": 0,
"ffUrl": "/ff/resources/Films/KG09l8GvwRc9pUzXGMTEJ4",
"director": "Ben Affleck",
"ffRL": "/Films",
"country": "U.S.",
"version": 1,
"updatedBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"guid": "KG09l8GvwRc9pUzXGMTEJ4",
"updatedAt": 1346472626252,
"filmDescription": "While 50 Americans are held hostage by the Ayatollah Khomeini’s Revolutionary Guard, six U.S. Embassy employees hiding at the Canadian ambassador’s residence in Teheran stage a daring escape. “Extraction” expert Tony Mendez (Ben Affleck) enlists a veteran Hollywood make-up expert and producer (John Goodman and Alan Arkin, each giving disciplined comic performances) to create a sham sci-fi movie epic in the hopes of finding a way out of the country. Affleck directs with formidable precision and documentary-style immediacy, intercutting between turf battles between the CIA and Washington diplomats, the chaotic street violence during Iran’s revolution and the black comedy of spies pretending to be Hollywood types. This is thrilling, nail-biting entertainment.nIn person: Ben Affleck",
"duration": 120,
"title": " SNEAK: Argo",
"ffRefs": [],
"createdBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"createdAt": 1346472626252,
"madePossibleBy": "",
"year": 2012,
"actors": "",
"clazz": "Film"
},
{
"ffUserCanEdit": false,
"ffUrl": "/ff/resources/Theaters/h3uX2Gt1j74w4yYbcifNq6",
"ffRL": "/Theaters",
"version": 1,
"updatedBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"guid": "h3uX2Gt1j74w4yYbcifNq6",
"updatedAt": 1346359016787,
"createdBy": "Os0t9Mjm7FhPemzN0uQ8U7",
"address": "",
"createdAt": 1346359016787,
"name": "Chuck Jones Cinema",
"capacity": 500,
"longitude": -107.8478,
"latitude": 37.9361,
"sponsorString": "",
"shortName": "Chuck Jones",
"clazz": "Theater"
}
],
"statusMessage":"Retrieved 1 resources from /ff/resources/Showings/e-06R5_d_FfHXKHSCx-ky4"
}
[/toggle]

As you can see, the response includes the object itself (in ‘result’), but additionally, all objects referenced or contained in grabbags have been retrieved as well.

In your client code, using the methods provided in the various SDKs, the REFERENCE and GRABBAG items are automatically incorporated into your client object model, but now these are populated with a single request.

For more info on references, see the docs here.

Have fun!

Kevin

FYI – get all your data in one click from FatFractal


As a developer, I want to be able to export all my data (and I mean ALL my data) with one click so that I can do whatever I want to with my data, including moving to another provider – it is MY data after all.

I was asked by @objclxt a couple of days ago if he could export his data stored in FatFractal with one click. At the time, we had always generated an export of the data for customers upon request, which is fine, but not what developers want. When someone asks for functionality that I know ought to be there, I get a bit antsy, so I decided that I had put that important piece of functionality off for too long, promised Nick a 1-day turnaround, and set about it.

Twelve hours of coding and testing, eight hours of sleep, and then another 3 hours running our release candidate smoke tests later, the good news was that it worked – and so it was deployed to production.

How it works:

From the console list of your applications, you will now see a link that says “export my data”. When you click on it, you will see an alert that tells you that your data is being exported and you will receive an email with a link to a zip file with your data.

Note: the request requires authentication/ authorization for the application as does the export link in the email, which is both ephemeral and is of course an SSL link for security purposes.

So – we export a zip that contains a number of .json files (one for each of your collections with all of the object data that they contain). The object data also contains all the references to other objects, a collection for your GrabBag references, including BackReferences, and of course we also export all of your blob data in the export.

Give it a whirl and let us know what you think!

Gary

FYI – Queries that will make you smile! FatFractal’s natural language queries are very cool.


As a developer, I really want to be able to get the data back from my API in a single request so that my application performs better and I don’t get socked with excessive API requests that result from “chatty” APIs.

One of the things that developers love about FatFractal is the way that you can construct queries that can get you to what you want in a single round-trip.

First, the basics – FatFractal queries…

  1. …are written in an easy to create, easy to read, natural language style.
  2. …can be chained together to filter the results to only the results you want in a single request.
  3. …are able to “walk” your object graph in both directions.
  4. …provide the best of relational capabilities without the complexity.
  5. …are constructed as strings, not proprietary query objects.
  6. …includes a very useful random operator that for some reason, nobody else seems to offer.

Let’s say that you have movie Star, Movie and Theater objects and their respective collections (Stars, Movies and Theaters) and you want to get all the theaters that are showing movies that have a particular star acting in them within a defined distance from the user. The following explains how you can create a query string that can return that in a single request/ response to illustrate the power of nesting queries in a single construct:

/Stars/(firstName matches ‘(%3Fi)milla’ and lastName matches ‘(%3Fi)jovovich’)/BackReferences.Movies.stars/()/BackReferences.Theaters.movies/(distance (location, [57.5833, 3.8667]) lte 5000)?sort=rating desc, name asc&count=5&first=0

Creating or reading FatFractal queries goes left to right, with query constituents enclosed in parentheses with “traversals” and queries separated by forward slashes. So, breaking down the query above into pieces:

    /Stars/(firstName matches ‘(%3Fi)milla’ and lastName matches ‘(%3Fi)jovovich’)
    The first part (a query) will get the movie star(s) (Star object) from the Stars Collection with the firstName member ‘Milla’ and the lastName member ‘Jovovich’, using regular expressions that compare while ignoring case (requires proper encoding of the Java regex mode modifier ?i for ignore case to be added as %3Fi) and a boolean operator (and) to ensure a complete match. Note: we now have a set of Star objects, probably with a single object.
    /BackReferences.Movies.stars
    The second part (a traversal) will then get all the Movie objects that she starred in based on the BackReferences from the Movie objects in the Movies Collection to the star in the Stars Collection. Note: we now have a set of Movie objects.
    /()
    The third part (a query) is an empty query operator that says that will use the entire set returned by the traversal.
    /BackReferences.Theaters.movies
    The fourth part (a traversal) will then get the Theater objects from the Theaters Collection that are showing movies that Milla Jovovich starred in from the BackReferences from the Theater objects in Theaters Collection to the above set of Movie objects in the Movies Collection. Note: we now have a set of Theater objects, which is what we want.
    /(distance (location, [57.5833, 3.8667]) lte 5000)
    The fifth part (a query) will then filter that set of Theater objects by geolocation that are within 5 kilometers of the user.
    ?sort=rating desc, name asc
    The sixth part (a sort) will then sort them first by the rating member of the Theater objects in descending order, second by name member of the Theater objects in ascending order.
    &count=5&first=0
    Lastly, we then limit the result set of Theater objects to the first 5 items or less.

Summary:

So, basically we start from a Star object in the Stars Collection, walk the datagraph to Movies using a BackReference, then walk the datagraph again to Theaters using another BackReference, and then filter the set of Theater objects further based on location, order the results by both the rating and name member values and limit the number of responses to a specified maximum count. Voila – you get what you want, ordered as you want, all in one go with a single, easy to understand query – this simply cannot be done with any other BaaS provider.

Also, let me point out the random operator in the FatFractal query language as it is an example of a very common use case.

Let’s say you want to retrieve a random movie Star from the Stars collection. The query looks like this:

“/Stars/(guid eq random(guid))”

This is incredibly useful as otherwise, you would have to retrieve the entire set of Star objects from the Stars collection over the wire and then pick a random one from that set in your client code. Easy enough to program, but grossly inefficient in terms of client resources and network performance. Otherwise, you could *probably* retrieve a random item with two queries – first, by querying the collection to get a count, and if the API has an ordered ID (as many do), then you could generate a random ID in your client code and fetch that one (hoping that it has not been deleted). At any rate, getting a random object from a collection is a very common use case and I do find it bizarre that nobody else support this as easily as FatFractal does and forces you to use very inelegant client solutions.

One more point to make is that queries can be used in the context of GETS as well as within Server Extensions and Event Handlers.

All for now – have fun with your queries!

Kevin

For more information on FatFractal Query language, the docs are here.

For more information on how to write queries with FatFractal, the docs are here.

FYI – You can run batch routines (CRON) jobs on FatFractal


As a developer, I want to be able to schedule code to run periodically on my backend so that I can clean up my data, generate reports or any other function that is not generated by an event or API call.

In addition to Event Handlers which execute based on data events and Server Extensions that execute on an API call, FatFractal also supports running backend code on a periodic basis using our Schedule Code capability. Any number of functions can be defined that execute on defined schedules. This has many applications from data administration to reporting, there really is no limit to what you can do with this.

Scheduled Code is defined in the same manner as Event Handlers and Server Extensions in your FFDL (what’s this?). You can define as many scheduled code events to be executed as you wish very easily as follows:

SCHEDULE <task name> <schedule> AS <script type>:<script text>

Where schedule is given in CRON format:

<minute (0-59)> <hour (0-23)> <day of month (1-31)> <month (1-12)> <day of week (0-6)>

For example, if I want to send out a daily report that lists the number of users for my cool new app, I would create a function like this in a file (here called EventHandlers.js):

ff = require('ffef/FatFractal');
exports.userReport = function() {
var n = ff.getArrayFromUri("/FFUser").length;
var msgSubject = "Application user total daily report";
var msgString = "You now have " + n + " users loving your application";
ff.sendEmail({
host: "<mailserver>", port: "<port>",
auth: "<true|false>", authPort: "<port>",
username: "<username>", password: "<password>",
from: "<fromAddress>", to: "<toAddress>",
cc: null, bcc: null, // included for completeness
subject: msgSubject,
text: msgString,
html: null // included for completeness. When supplied, the HTML message is
// sent, the text is also included as fallback if HTML viewing
// is not enabled in the receiver's email client
});
}

And, then to schedule this be sent out daily at midnight, the FFDL would be:

SCHEDULE UserReport 0 0 * * * AS javascript:require(‘scripts/EventHandlers).userReport();

That’s it – an approach that is very consistent with everything else which allows you to easily schedule any code that you like to execute on a defined schedule.

For more details on FFDL, the docs are here.

For more details on Scheduled Code, the docs are here.

Have fun!

Kevin

FYI – FatFractal Server Extensions lets you extend your API with any function that you want


As a developer, I want to be able to add any function without limitation to my API so that I can… do just about anything!

As Gary mentioned in his post about the origins and future of FatFractal’s NoServer -

The cloud should… Not prevent me from doing anything else that I want to do”

Server Extensions are, essentially, a means to extend your API with any kind of function that you desire. Server Extensions accept data as needed, execute any code that you want and return a broad set of return types (JSON, HTML) allowing virtually unlimited capabilities for your backend. They are easy to create, and you can add as many as you wish.

What can I do with a Server Extension?

The uses for Server Extensions are very broad, but a few examples are:

  • Aggregate data on the fly without corrupting your data model.
  • Access other backend services (e.g. salesforce, sap, etc.), then transform/ return the results.
  • Data management/administrative functions.
  • Manipulate and return HTML, images, videos, documents or any other MIME type.

Extending your API

Accessing a server extension is as simple as naming it in your FFDL (what’s this?), which will provide URI access to this particular function.

CREATE EXTENSION /extension_name AS javascript:require (‘scripts/MyExtensions.js’).function_to_be_executed();

This will add a new URI endpoint to your application that looks like:

https://mydomain.fatfractal.com/ff/ext/extension_name

When that URI is called, the function function_to_be_executed that is in the file MyExtensions.js in the ff-scripts directory will be called. Any provided parameters or data are made available to the function as well. You also have the option to declare the function to be secured (default) or add UNSECURED which allows a non-authenticated user to call the function as desired.

Passing in Data

There is a wealth of data from a request that is made available to a Server Extension, including:

httpMethod: the HTTP method (eg. GET, POST, PUT, DELETE, HEAD)
httpRequestUri: the request URI, relative to your application’s base URL
httpParameters: A map of the request parameters
httpHeaders: A map of the request headers
httpCookies: For convenience, a map of the cookies from the Cookie request header
httpContent: A map corresponding to the JSON content supplied in the request body, if any
ffUser: the guid of the logged-in user

This means that you can process according to the httpMethod used, pass in data as httpContent or as URL parameters and authenticate based on the user making the request – in short, you have a lot of flexibility on getting what you want into a Server Extension.

Return Types

You also have control over what gets returned by the extension, including the following:

result: the data or content that you wish to return
responseCode: the appropriate http response code
statusMessage: an informational status message useful for debugging
mimeType: the MIME type of the response content

One of the most useful abilities that Server Extensions provide is the additional return MIME types that are supported. For example, you could create an image resizing service and set the MIME type of the return (e.g. “image/jpeg” or “image/png”). Or, you could read an html template file, replace elements to personalize it and return a web page (“text/html”). And, of course, you can always return data as well (“application/json”), which is the default.

You can also implement as much error handling as you want based on what data is received as well as the result of the operation itself. For example, checking for required information and returning an appropriate error code with a message that you want.

The following example of an extension that validates a user registration from a link shows a number of these features in use:

exports.verifyRegistration = function() {
var data = ff.getExtensionRequestData();
var hc = require('ringo/httpclient');
var r = ff.response();
// check if user guid provided
var guid = data.httpParameters['guid'];
if (! guid) {r.result = null;
r.responseCode = "400";
r.statusMessage = "ActivationRequest guid not supplied";
r.mimeType = "text/html";
return;
}
// check if activationRequest exists
var activationRequest = ff.getObjFromUri("/ff/resources/ActivationRequest/" + guid);
if (! activationRequest) {
var htmlContent = hc.get(ff.getHttpAppAddress() + '/validateuser.html').content;
htmlContent = htmlContent.replace("___SUBJECT___", "ERROR");
htmlContent = htmlContent.replace("___MESSAGE___", "The validation request for this account no longer exists. ";
htmlContent = '' + htmlContent;
r.result = htmlContent;
r.responseCode = "404";
r.statusMessage = "ActivationRequest could not be found";
r.mimeType = "text/html";
return;
}
// check if user exists
var user = ff.getUser(activationRequest.userGuid);
if (! user) {
r.result = null;
r.responseCode = "404";
r.statusMessage = "User could not be found";
r.mimeType = "text/html";
return;
}
// checks passed - now create the welcome html from a template and return
user.active = true;
ff.updateObj(user);
ff.deleteObj(activationRequest);
r.responseCode = "200";
var htmlContent = hc.get(ff.getHttpAppAddress() + '/validateuser.html').content;
    htmlContent = htmlContent.replace("___SUBJECT___", "Thank You!");
htmlContent = htmlContent.replace("___MESSAGE___", "Your account has been activated.";
htmlContent = '' + htmlContent;
r.result = htmlContent;
r.statusMessage = "User now activated";
r.mimeType = "text/html";
}

Hope you find this useful…

Kevin

For more information about Server Extensions, see the docs here.

For more information about FFDL, see here.

Contact