Powering a React + Next.js Blog With Cosmic JS

Written by tonyspiro | Published 2018/05/24
Tech Story Tags: javascript | reactjs | react | nodejs | cms | cosmicjs | programming | nestjs

TLDR Cosmic JS is a fully-featured content management system (CMS) with an intuitive user interface that a non-technical client can use to manage their site content. In this how-to article, we’ll connect a React + Nextjs app to Cosmic JS and go over some of the features. We’ve just created an entire backend for your project for your entire project. No configuring databases or servers required! No configuration required! Follow the links below for code and demo:via the TL;DR App

TLDR;
Cosmic JS provides an excellent backend for blogs. It is a fully-featured content management system (CMS) with an intuitive user interface that a non-technical client can use to manage their site content.
Follow the links below for code and demo:

TL;DR:

Intro
Every blog needs a solid CMS. This allows content owners to control their content without having to hire a developer to make every single change to their site. Many developers immediately think WordPress when considering a CMS. I’d like to suggest Cosmic JS as an alternative, though. It’s extremely simple to integrate from the developer’s viewpoint and to manage from the client’s. In this how-to article, we’ll connect a React + Next.js app to Cosmic JS and go over some of the features.
Getting Started
Fist you’ll need to create a free account with Cosmic JS. Navigate to https://cosmicjs.com. Click the ‘Create Free Account’ button in the header.
Then fill in your information or simply click ‘Sign up using GitHub’.
The first step in creating a backend with Cosmic JS is to create a Bucket. A Bucket can be thought of as a container of Objects. Objects are any piece of data that you want to store. An Object could be a blog post, an image, any kind of metadata, or really any kind of anything. We’ll discuss Objects more in the next section. For now, just know that you need a Bucket to hold all of your project data. You should now be at https://cosmicjs.com/buckets. Click ‘Add New Bucket’. Type in a name for your project and click ‘Save Bucket’.
The Dashboard and Setup
You should now be at https://cosmicjs.com/****/dashboard, **** being a unique string of characters that identifies your bucket (also called a slug). All of your site’s data can be managed in the Dashboard. The first thing we’re going to do is define an Object Type. An Object Type defines a data structure. For this tutorial, we’re going to define 4 different Object Types: Globals, Posts, Authors, and Social Links. Let’s start with Posts. Post Objects will hold all of the information needed to display a blog post on our site. Click the ‘Add Object Type’ button.
Type ‘Post’ in the ‘Singular Name’ field. The ‘Plural Name’ and ‘API Endpoint’ fields should auto-populate.
Then click the ‘Metafields Template’ tab. Click ‘Add Metafield’.
Choose ‘Image / File’.
Type ‘Hero’ in the ‘Title’ field. The ‘Key’ field should auto-populate with ‘hero’.
Let’s add one more metafield. Click ‘Add Metafield’ again. This time select ‘HTML Text Area’.
Give it the title ‘Teaser’. Then click ‘Save Object Type’.
Awesome! you’ve created your first Object Type. Let’s do it three more times!
  1. Create an Object Type, Author. This represents a blog post author. Add an ‘Image / File’ metafield and call it ‘Image’.
  2. Create an Object Type, Global. This is how we’ll store meta data about our blog, like it’s title, tag, and logo. Don’t add any metafields.
  3. Create an Object Type, Social Link. We’ll use this to store data about external social links. Add a ‘Plain Text Input’ metafield and call it ‘Url’. Add an ‘Image / File’ metafield and call it ‘Icon’.
We’re almost done with the setup. Let’s go back to our Post Object Type and add one more metafield. We just defined another Object Type, Author. Wouldn’t it be great if we could connect each Post to it’s Author? Click ‘Add Metafield’ again. This time choose ‘Single Object Relationship’. In the dialog that appears, type ‘Author’ for the ‘Title’. Then select ‘Limit Search By Object Type’ and choose ‘Authors’. Then click ‘Save’.
Setup complete! You’ve just created an entire backend for your project. No configuring databases or servers required! 😀 🎉

Add some content

Before we move on to connecting Cosmic JS to our app, let’s add some data first. Click ‘Globals’ in the Dashboard menu. Then click ‘Add Global’.
In the ‘Title’ field, type ‘Header’. We’ll then add 3 metafields.
  1. Add a ‘Plain Text Input’ metafield. Type ‘Site Title’ for the ‘Title’ and ‘My Cosmic Blog’ for the ‘Value’. Check the ‘Required’ checkbox.
  2. Add another ‘Plain Text Input’ metafield. Type ‘Site Tag’ for the ‘Title’ and ‘A clean, minimalist, content-first blog powered by Cosmic JS’ for the ‘Value’.
  3. Add an ‘Image / File’ metafield. Type ‘Site Logo’ for the ‘Title’ and then select an image from your computer.
Click ‘Publish’.
Now, lets add an Author. Click ‘Authors’, then ‘Add Author’. Enter your name for the ‘Title’. Add a brief bio for yourself in the ‘Content’ section. Select an image. Then click ‘Publish’.
Then, we’ll add a Post. Click ‘Posts’, then ‘Add Post’. Enter a Title, some Content, a Teaser, add a Hero image, then select your name from the Author dropdown menu.
Hopefully, you’re getting the hang of using the Dashboard now. It’s pretty intuitive.
The last thing we’ll do is add some Social Links. Repeat the same process as with the other Object Types. Add at least two Social Links.

Content ✔️, Let’s write some code

Now we can get to the code! Clone, download, or just check out the source code at https://github.com/chrisoverstreet/cosmic-blog.
This isn’t a React or Next.js tutorial, so I’m just going to focus on the
/server.js
file. Next.js allows you to implement your own server by creating a server.js file in the root directory of your project. We’re going to create an express server.
The simplest way to connect to your Cosmic JS backend is with the offical Cosmic JS JavaScript client. To install the client, in your terminal, type:
npm i -S cosmicjs
Back in server.js, import and initialize cosmicjs:
const Cosmic = require('cosmicjs');<br>const api = Cosmic();
Now we’re going to implement our own API to connect to Cosmic JS. We’re doing this to create a layer between our App and our data. We could use the cosmicjs client whenever we wanted to fetch data in our app, but then our sensitive bucket data would be exposed to the client (like an API Write Access Key). Find your bucket slug by going back to the Cosmic JS Dashboard. Under the Settings menu, choose ‘Basic Settings’. Your ‘Bucket slug’ should be visible. Copy it.
Back in server.js, we’ll create a bucket object that our API can use.
const bucket = api.bucket({ slug: 5b7536d0-59f8-11e8-8958-e7a8aba9942d });
With that bucket object, we can fetch and return our data in the following way:
// API endpoint for site metadata (i.e. title, tag, logo)

server.get('/api/meta', (req, res) => bucket.getObject({ slug: 'header' })
  .then(object => res.send(object))
  .catch(err => res.status(404).json({
    message: 'Error fetching header data',
    error: err,
  })));
The slug in
bucket.getObject()
is the slug used to define your Object. You can also fetch a list of Objects.
// API endpoint for social links

server.get('/api/social-links', (req, res) => {
  const params = {
    type: 'social-links',
  };
  
  return bucket.getObjects(params)
    .then(objects => res.send(objects))
    .catch(err => res.status(404).json({
      message: 'Error fetching social links',
      error: err,
    }));
});
Here’s the complete server.js code:
/* eslint-disable no-console */
require('dotenv').config({ path: './.env.production' });
const express = require('express');
const next = require('next');
const routes = require('./routes');
const Cosmic = require('cosmicjs');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handler = routes.getRequestHandler(app);
const api = Cosmic();
const bucket = api.bucket({ slug: process.env.BUCKET_SLUG });

app.prepare()
  .then(() => {
    const server = express();

    // API endpoint for site metadata (i.e. title, tag, logo)
    server.get('/api/meta', (req, res) => bucket.getObject({ slug: 'header' })
      .then(object => res.send(object))
      .catch(err => res.status(404).json({
        message: 'Error fetching header data',
        error: err,
      })));

    // API endpoint for social links
    server.get('/api/social-links', (req, res) => {
      const params = {
        type: 'social-links',
      };

      return bucket.getObjects(params)
        .then(objects => res.send(objects))
        .catch(err => res.status(404).json({
          message: 'Error fetching social links',
          error: err,
        }));
    });

    // API endpoint for a list of posts (by page)
    server.get('/api/posts/page/:page', (req, res) => {
      const validatedPage = !Number.isNaN(req.params.page) && parseInt(req.params.page, 10) >= 0
        ? parseInt(req.params.page, 10)
        : 1;
      const postsPerPage = 10;
      const params = {
        limit: postsPerPage,
        skip: (validatedPage - 1) * postsPerPage,
        sort: '+created_at',
        status: 'published',
        type: 'posts',
      };

      return bucket.getObjects(params)
        .then(objects => res.send(objects))
        .catch(err => res.status(404).json({
          message: `Error fetching posts for page ${validatedPage}`,
          error: err,
        }));
    });

    // API endpoint for an individual post
    server.get('/api/post/:slug', (req, res) => bucket.getObject({ slug: req.params.slug })
      .then(object => res.send(object))
      .catch(err => res.status(404).json({
        message: `Error fetching post with slug, ${req.params.slug}`,
        error: err,
      })));

    // Our regular NextJS pages
    server.get('*', (req, res) => handler(req, res));

    server
      .listen(port, (err) => {
        if (err) throw err;
        console.log(`> Ready on http://localhost:${port}`);
      });
});
Now we can hit our API endpoint inside our App to retrieve our data. For example, to retrieve a single post, we can use the following code:
const fetchPost = slug => fetch(`${API_URL}/post/${slug}`)
  .then(res => res.json())
  .then(json => console.log(json));
It’s that simple!

Outro

This was just a high level overview of using Cosmic JS with React + Next.js. If you’re like me, the best way to learn something is to jump right in and experiment with things. I invite you to download the source code for this project and tinker with it. Cosmic JS has much more to offer than what was mentioned in this post. Check out the articles and other information available on their site under the ‘Developers’ tab.
Thanks for reading! Happy coding!
This article originally appeared as a Cosmic JS Article.

Written by tonyspiro | CEO & Co-Founder of Cosmic JS
Published by HackerNoon on 2018/05/24