Dane Hillard
Posted on February 5, 2019
This post originally appeared on dane.engineering.
Although sites like Medium provide audience reach and a consistent experience, the list of reasons I'm no longer happy with it keeps growing. I've done most of my recent writing here on dev.to, which has been a refreshing change!
I decided to take my maiden voyage into headless CMS, and I've chosen ButterCMS for the moment. Its small but focused API was plenty for me to get my blog up and running! Best of all, it's free for non-commercial use.
Right after you sign up with Butter, you'll get an API key and links to an impressive array of framework-specific instructions for how to get set up. I found the instructions for Vue very easy to follow, and was able to go from signing up to retrieving the test blog post within 15 minutes or so! I'm using single-file components (SFCs) in my app, so I started by grabbing a list of blog posts and creating the template together. Butter returns a data
property that contains the list of posts, each of which has a title, slug, body, and so on. We can fetch these when the BlogPostList
component is created, so that the data becomes available around the time it mounts. I also put in a loading state for the rare occasion where the API response takes a noticeable amount of time:
<template>
<main>
<h1>Posts</h1>
<span v-if="loading">Loading...</span>
<ul v-else-if="posts.data.length">
<li v-for="post in posts.data" :key="post.slug">
<router-link :to="{ name: 'post', params: { slug: post.slug } }">
{{ post.title }}
</router-link>
</li>
</ul>
</main>
</template>
<script>
import Butter from 'buttercms'
const butter = Butter('YOUR API KEY')
export default {
name: 'BlogPostList',
data () {
return {
loading: true,
posts: {},
}
},
methods: {
fetchPosts () {
butter.post.list({ page: 1, pageSize: 10 })
.then((response) => {
this.loading = false
this.posts = response.data
}).catch((response) => {
console.log(response)
})
},
},
created () {
this.fetchPosts()
},
}
</script>
The code for displaying a single post is much the same—a data
property contains information about the post and we can fetch the post as the component is created:
<template>
<main>
<article v-if="post.data">
<h1>{{ post.data.title }}</h1>
<span class="metadata">{{ publishedDate }}</span>
<div v-html="post.data.body" />
</article>
</main>
</template>
<script>
import Butter from 'buttercms'
const butter = Butter('YOUR API KEY')
export default {
name: 'BlogPost',
data () {
return {
loading: true,
post: {},
}
},
methods: {
fetchPost () {
butter.post.retrieve(this.$route.params.slug)
.then((response) => {
this.loading = false
this.post = response.data
}).catch((response) => {
console.log(response)
})
},
},
created () {
this.fetchPost()
},
}
</script>
This is about all you need in order to start fetching a list of posts and rendering each post! The rest of the work is in dropping all the SEO into place (I use vue-meta
for this) and styling the content as you wish. One additional thing I did to make using Butter easier throughout my Vue app was adding it to the Vue prototype:
import Butter from 'buttercms'
const butter = Butter('YOUR API KEY')
Vue.prototype.$butter = butter
Then I can just type this.$butter
in a component's methods instead of initializing the API client each time.
The features I like about butter so far are:
- The easy-to-use API and corresponding JavaScript client
- The small amount of time it took to get started
- The image API they provide (through Filestack)
The features that could use some work are:
- Adding code blocks to your posts: it's way nicer than Medium, but not as good an experience in the WYSIWYG as other more basic things
- Terminology: this isn't unique to Butter; a CMS can be complex so it's difficult to distinguish all the concepts you can configure, create, and customize
Posted on February 5, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.