Prismic.io Mapping

I've built a NuGet package to map prismic.io documents to models using attributes.

I recently wrote about switching to using prismic.io to manage content on the site. This time round, I'm going to cover the first step I took to streamline the presentation of my content.

Prismic.io uses custom types (formerly document masks) to define the structure of a document (a piece of content). Custom types are JSON documents. The JSON defines the document structure in the API and presentation in the Writing-Room. The following is a simple example.

{
  "Content": {
    "title" : {
      "type" : "StructuredText",
      "fieldset" : "Title",
      "config" : {
        "single" : "heading1"
      }
    }
  }
}

“Content” is the tab name in the writing-room, we can use tabs to group related fields. In my example, we have a single field called “title”. We must define the field type, in this case, StructuredText. Each field type has its own configuration options. Check out the documentation for the supported field types.

After a few implementations, I found common patterns emerging. I tend to map a document to a model. It makes my views cleaner. Allows me to take advantage of MVC's display templates. And where possible, separate my presentation from the implementation. There are exceptions to this most notably, StructuredText. Rich-formatted content requires a complex data structure, which is difficult to abstract. Your choice is, to pre-render HTML, losing flexibility or, duplicating kit features. I still found I had a lot of repetitive code, see below.

@Model.getStructuredText("title").AsHtml(new DocumentLinkResolver())

The above code snippet assume your document is your model. It attempts to grab the “title” field and using the kit's AsHtml method renders output the HTML. When you take into account that all fields except UID are optional, your views can get messy.

I spent a little time experimenting and produced an alpha solution to road-test on a few sites. It helped me discover what features I was missing. It's by no means feature complete but, it's extensible enough that you can customise it to fit your needs. Here's it works.

To Map a document you first need to do the following. Create a class or classes in your solution that represent your custom type. Decorate your class with a PrismicDocumentAttribute. The attribute takes the id of the custom type as it’s first argument.

[PrismicDocument("your_prismic_document_id")]
public class ExampleMappingClass {}

For every property that you want to map must have a PrismicFieldAttribute that corresponds to the field type. As with the PrismicDocumentAttribute you can supply the field name as the first argument. If you don’t supply a field name, the mapper will lowercase the property name and attempt to resolve a field with that name.

[PrismicDocument("your_prismic_document_id")]
private class ExampleMappingClass
{
    [PrismicUid]
    public string Id { get; set; }

    [PrismicTextField]
    public string Title { get; set; }

    [PrismicTextField("title")]
    public string NamedTitel { get; set; }
}

Once you have this in place you can map a document as follows.

var model = PrismicMapper.Map<ExampleMappingClass>(document);

Your view code is now much cleaner. We can do even better than this but, that's a post for another day.

@Model.Title.AsHtml(new DocumentLinkResolver())

Caveats

As I mentioned before this is by no means feature complete. There are some notable omissions. Groups and LinkedDocumentFields are still on the to-do list.

The first map initialises a cache for that document type. Subsequent maps use the cache. I'm considering adding a method to pre-cache. But, I've not run into a situation where first-map performance necessitates it.

If you want a feature implemented, need a bug fixed, or need help integrating prismic.io, get in touch, I'm @benembery. If you want to contribute create a pull request or log an issue on GitHub.

View the project on GitHub

Install the NuGet Package