Building a Cardstack app - Part 1

24 November 2017

What is Cardstack?

Cardstack is an open-source application framework, built on top of Ember.js and
Node, that aims to make common application features (CMS, notifications,
authentication) a snap to add to your application and empowering the end-user
to do so.

It is also special in that it also provides a server-side component as part of
the framework, so the front- and back-end can really work in tandem.

The Cardstack team has a grand and worthy vision for the future of software and
I strongly encourage you to read the whitepaper (and I dare you not to get
enthusiastic about the project once you’ve done so).

In this series of blog posts, I’m going to show you how to get started with
Cardstack by leading you through the building of a simple app.

The tutorial app

We’re going to integrate Cardstack in the “Super Rentals” app developed in the
official Ember.js tutorial. It’s a really small app but it’s big enough to
highlight some of the features Cardstack gives you.

Unsurprisingly, it’s built around rentals, and its main page shows a list of
rentals that can be filtered by city.

Each rental can then be examined on its own page. There is also a simple About
us and Contact page.

First part: Welcome to Cardstack

In this first installment of the tutorial, we’ll see how to integrate Cardstack
into this app until the point where it displays the main page with a welcome
message.

We’re going to do a lot of groundwork, things that don’t have an immediate,
user-facing result, but which will allow us to build really fast and high later.

Let’s jump in.

Setting up the app

If you’d like to follow along, which I encourage you to do, you first have to
check out the super-rentals repo:

1

$ git clone https://github.com/ember-learn/super-rentals.git

We’ll use yarn as our package manager, so you’ll have to install it if you
haven’t already done so. To be able to run the app, you’ll want to have a recent
version of node, 8 is best.

Change to the folder you have cloned the repo to and install the project’s
dependencies:

1

$ yarn

When you have this, start the app by launching ember serve. When you go to
http://localhost:4200, you should see the list of rentals:

Setting up CardStack dependencies

Cardstack is a search-first web application and is powered by
Elasticsearch. To make it easy for developers to set up Elasticsearch (and to
prevent a slew of incompatibility and configuration issues), Cardstack also
published a Docker repository you can download.

(If you don’t yet have Docker on your machine, you’ll first have to install it).

Now that we have the hub, the main server-side piece of the hub architecture, we
need to define the models there. Cardstack will then create models, routes and
server endpoints(!), the full monty, based on the schema defined in the host
application.

Don’t worry about the module.exports part too much, the only thing we care
about now is that it calls the initialModels function for the data source
which should return the model definition.

Since we want to build a little CMS and work with pages, the first model we
define therein should be page. Cardstack uses the JSON API format for defining
data schema and the jsonapi-factory provides methods, like withAttributes and
withRelated, to help create the documents that describe that data.

The page content type (the plural form is used in JSON API) has a
routing-field with a value of permalink, which is the property used by the
routing package to create and traverse URLs.

It also has fields, which is defined as a relation to the built-in fields
content-type. Then come the fields themselves, each having an id (like title,
body, etc.) and a field-type.

Good, so we’ve now defined the page schema (the Page class, if you will), we
can now create page instances.

For now it suffices to have a main page, so let’s create one in the same file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// cardstack/seeds/development/models.jsconstFactory=require('@cardstack/test-support/jsonapi-factory');module.exports=[(...)];functioninitialModels(){(...)factory.addResource('pages').withAttributes({permalink:" ",// a string with a single spacetitle:"Welcome to Cardstack!",});returnfactory.getModels();}

Before we go on, let’s add the @cardstack/test-support package to our
dependencies as we’re importing the jsonapi-factory module from there:

1

$ yarn add @cardstack/test-support

The next error we receive is:

1

> cardstack.index @cardstack/routing tried to use model page but it does not exist

We defined our data schema but for Cardstack to generate client-side models for
it, we also need the @cardstack/models package, so let’s install it:

1

$ yarn add @cardstack/models

After a restart, we now get another error, but not to despair, keep in mind that
receiving a different error each time is progress:

Oh, ok. The Super Rentals app uses Mirage for mocking server responses, but
Cardstack has a built-in server side that implements the CRUD actions based on
our model schema, so we don’t need Mirage.

We have to replace Mirage with the @cardstack/jsonapi plugin:

1
2

$ yarn remove ember-cli-mirage
$ yarn add @cardstack/jsonapi

With that change, we again got closer to have a working, Cardstack-enabled
landing page. The page header is rendered but when it gets to the header link,
it bows out:

1

You attempted to define a `{{link-to "index"}}` but (...). There is no route named index"

Since we took over routing by way of the @cardstack/routing package, we have to use routes
generated by it and the helpers it provides. In the header, we want to link to
the main page that we created in the models seed file and we achieve it by using
the cardstack-url helper (provided by @cardstack/routing) which takes a type
and an id.

Let’s open the application template and replace the first link-to, while
temporarily removing the links to the about and contact page:

The header is now rendered and the body contains the error message: “No such
component cardstack/page-page”.

Great, we now we got to the core customization feature of Cardstack, components.

Cardstack components

Cardstack components is the main way of making your app look and behave the way
you want it to while still having all the features the framework provides for you.

The naming rule for which component is rendered for a certain type of resources
is

1

`cardstack/${resource-type}-${format}`

In our case, we have a resource of type page as the main page of the app.
Since this object represents the whole page, Cardstack, by convention, tries to
render a “page” object in “page” format, and that’s why it complains about not
finding a cardstack/page-page component.

This might be confusing, so let me give you another example. If you have a
resource of type rental, and a ‘card’ format, Cardstack will render the
cardstack/rental-card component.

Rendering the main page

Ok, so we established we’d have to define a cardstack/page-page component to
put some content on the main page. We already have a title property for pages so
let’s see if we can make it appear.

We’ll create a template file for the component manually as we don’t need the
javascript file, and put the following content into it: