[ js ⬡⊶⬡ prismic.io ] 99% pure (or a touch beyond) approach to managing content in JavaScript

Written by Guillaume Bort in Engineering on October 23,2013

You can't get much more native to the web than JavaScript. Indeed, the programming language and its tools have evolved around and with the web - and today it's central to any serious web programming. Not only is it the standard way of working client-side on the Web browsers, but it's now becoming as important on the server side with the rise of node.js.

We can all agree that "manageable content" is an important topic in most web projects - though managing content has often been the show stopper for your workflows and coding habits: pushing you to use a Content Management System (CMS). At best, a CMS will force you to write JavaScript code from within its tedious framework - and in the extreme it can push you towards abandoning one or the other: JavaScript or Manageable Content.

This is one of the key problems we wanted to solve when we started working on the prismic.io platform. We also knew that consuming the content repository data from JavaScript (whether from a simple script running client-side, or from a full-featured application running server-side), would be one of the most common usage patterns.

prismic.io provides a content repository with a writing wroom, and an API allowing you to query that content in different ways and pull it into your website or app. It is a fundamental point in the prismic.io design that you can use whatever technology you want to build websites or applications that connect to your content repository. Not only can you choose the technology you prefer (or that is the best match for a particular project), but you will be able to use it in a very idiomatic way: we don't build "technological bridges" to prismic.io, but we really create development kits and starter projects that embrace the community standards and best practices.

Hence, as soon as we have got our beta out - the JavaScript technology page shows you many ways to work with prismic.io. Let's take a quick tour of what is available and why working with both prismic.io and JavaScript will make your next project easier.

Meet the JavaScript development kit

What we call "development kit" is a minimal library with no dependencies, providing bindings for JavaScript to the prismic.io REST API. It can be embedded into any JavaScript-compatible project to consume the content coming from any prismic.io content repository.

The JavaScript development kit consists of a single file library that you can embed into a Web page to access a prismic.io repository from a web browser, or that you can use as a npm module to embed into a node.js application.

Let's try to use it from the node.js interactive shell. First, install the prismic.io library from npm:

$ npm install prismic.io

Run the node interactive shell and load the dependency:

$ node
> Prismic = require('prismic.io').Prismic

For experimenting with the API we need to connect to a content repository. We can use the open API from our public example "Les Bonnes Choses" pastry shop.

You can now create a "prismic.io session" by fetching the API end-point.

> Prismic.Api('https://lesbonneschoses.prismic.io/api', function(err, o) { 
if (err) console.error(err);
// Store the Api object in a global variable so we can experiment further.
else api = o;
})

You can inspect the resulting api object to see that it contains several forms. A form represents a very useful API interface, by filling and submitting a form you will access your content repository data. Why do we have several forms? Simply because our api already created pre-filled forms that represent interesting queries you can run on your repository, based on the document collections that are setup in the writing-room.

For example there is a macarons form, that will retrieve all product documents tagged "Macaron" in this content repository. You can inspect this form data, to discover how it was pre-filled:

> api.form('macarons').data

You will see that it already contains a value for the q field that represents the query:

[:d = at(document.tags, ["Macaron"])] [:d = any(document.type, ["product"])]

Those are two predicates that will constraint the results of this query. You can read more about the available predicates in our documentation, but just know that these two ones will only select "product" documents tagged "Macaron". What is intetersting here too, is that you can chose a prefilled form, and add predicates on top of it.

In addition of the q field, you also see that this form requires a ref field. You can read more about refs and releases in this previous blog post, but for now all you have to understand is that this ref represents the moment of the repository timeline on which you want to run your query. Most of the time you will run queries on the live version of your repository, a special ref that we call master ref, and whose identifier you can access from the api object:

> api.master()

So let's fill the missing field in this macarons form to submit the query and inspect the resulting documents:

> api.form('macarons').ref(api.master()).submit(function(err, d) {
if (err) console.error(err);
// Store the result into a global variable so we can experiment further.
else docs = d
});

The result of any query is an array of documents matching the given predicates and available at the provided ref. For the previous query you should get 7 results, that are all live Macarons availables on the "Les Bonnes Choses" example. You can run the same query from the "Les Bonnes Choses" API browser. API browser is a visual tool allowing you to experiment with your content and interactively compose your queries.

If you take a look at the query result on the graphical API browser, you will see that the resulting documents are composed of several fields (that we call document fragments). You can switch between the HTML and JSON views. The JSON view of the documents is of course the one you will get via the JavaScript development kit. Obviously, JSON is really easy to manipulate and to display using any JavaScript framework and templating engine.

On top of the raw JSON structure, we added a few useful helpers you can directly use in your application. For example, for the StructuredText fields, while we give you access to the very low-level JSON structure that describe every bit of text, but we also give you some handy helpers like the asHtml() function which does the HTML rendering for you:

docs.results[0].getStructuredText('product.description').asHtml()

It is a good idea to experiment more and get more familiar with the API, but we will now see that we provide more than this development kit to help you get started with prismic.io and your own project.

Embed prismic.io content into a simple Web page

We have created several starter projects to help you getting started in different situation. One common use case is to just embed a bit of manageable content into an existing Web page. This simple pattern doesn't require a full-featured client side or server side JavaScript framework, but still that is something JavaScript perfectly does!

Here is a starter project published on our Github, it demonstrates this pattern using JQuery along with a minimal templating engine, to render a prismic.io document as HTML and to inject it into the existing DOM:

As you can see, it uses the same JavaScript library we just played with before, but embedded into a web page. It is then very simple to compose with the DOM manipulation features provided by JQuery to quickly add content management capabilities to any Web application.

That's a good starting point if you want to display some bits of manageable content into an application that is not itself fully managed using JavaScript, but we all know that it becomes quickly limited for a bigger application.

Full featured single page app using BackboneJS

For a more sophisticated website or web application built with JavaScript you need a more powerful MVC framework. It is exciting that there are plenty of options in the today's JavaScript eco-system, and the choice of your JavaScript MVC framework doesn't bring any limitation to the way you will work with prismic.io.

As an example, we have created this example using RequireJS to organize our code base, and BackboneJS as a MVC framework:

Of course it still uses the same JavaScript library as before. You can use this as a base project for your next JavaScript application or just as an inspiration to integrate efficiently prismic.io with your preferred JavaScript framework.

Server-side manageable content with node.js

There are several problems related to fully client-side applications. One of them, that is of course very relevant to content-focused web projects, is Search Engine Optimization. If the content you are displaying is the central component of your application then you have to take care of SEO and you can't just dynamically consume and render it (only) client-side.

That doesn't mean that using prismic.io from the client side is not a good thing to do. It is sometimes the way to go, for example if you are displaying the content very dynamically or if the content you are displaying is just an add-on to your application, such as an help system.

But if you must render SEO-optimized web pages containing some manageable content, you should go server-side and generate them using node.js. You can of course mix both ways of interacting with your content repository: server-side generated web pages as a base for your application and dynamically updated client-side to quickly react to the user interactions.

The good thing is that no matter which way you choose, you will be able to use the same library and the same queries and patterns, whether your code is running in node.js or in the browser.

To help you getting started with any node.js project we have created this starter project using express.js:

The prismic.io kit being totally async, it plays well in the node.js environment. Our starter project provides a few helpers, like this prismic.route function that automatically provide a "prismic context" to any express.js route:

prismic.route(function(req, res, ctx) {
ctx.api.form('everything').ref(ctx.ref).submit(function(err, docs) {
if (err) console.error(err);
else res.render('index', {
docs: docs
});
});
});

A more complete example

Starter projects just demonstrate the basic interaction patterns. If you are new to prismic.io, you probably wonder what a more realistic project looks like? That's why we have created a first complete example content repository called "Les Bonnes Choses" pastry shop, that we used above to experiment with the API.

On top of this example repository, we took the time to develop a complete website that queries and displays the repository data. Here are two flavors of this website written using JavaScript, one client-side, and one server-side:

Feel free to dig into these two complete examples to discover how easy and powerful it is to handle manageable content using prismic.io. You can of course fork your own version of the "Les Bonnes Choses" repository, so you can really experiment with it by modifying documents, preparing, previewing and publishing releases.

Both examples can also be easily deployed to the cloud. For example you can push the client side version to Github pages or deploy the node.js version to Heroku.

We hope that you will find all these starter projects and examples inspiring, and that you will either create your own, or start your next personal project using prismic.io! Remember that if you want to use prismic.io for an open-source project, or if you lead a project that provides open content that brings value to the community, we can offer you a free licence.

Happy hacking with prismic.io & JavaScript!

Guillaume Bort

Guillaume Bort is the co-founder of prismic.io and created the Play Framework and Zengularity.