DEV Community

Alfredo Baldoceda
Alfredo Baldoceda

Posted on • Edited on

Managing a blog with AWS Amplify Studio

Summary

This article explains how to use AWS Amplify to manage a blog by creating, updating, and deleting new posts. In contrast to the previous blog post that used MDX files, this article uses a table on AWS DynamoDB and a graphical interface to update content. The article covers how to launch Amplify Studio, create a post data model using Data Modeling, and how to pull resources. Additionally, it demonstrates how to integrate Amplify libraries with Next.js for server-side rendering (SSR)and provides code examples for fetching and rendering blog posts from the DataStore.


Following the series of articles about AWS Amplify, in this post, we will cover a way to manage our blog by adding a way to create, update, and delete new posts.

In our past blog, we used MDX files to get the markdown content and use Tailwind/Topography prose plugins to show our markdown with tons of beautiful styles.

For this blog, instead of using MDX files to get our markdown content, we will use a table on AWS DynamoDB and a graphic interface to update our content.


Prerequisites

Before proceeding with this article, make sure you have an existing project hosted using AWS Amplify. If you don't have a project yet, you can follow this blog to learn how to host a project using Amplify.


Launching Amplify Studio

To get started, we need to launch Amplify Studio, which is a visual interface that manages the backend resources created by Amplify.

1. Go to the AWS Console and navigate to Amplify services.
2. Select your app, and under backend environments, click on the yellow button labeled Launch Studio.

Once Amplify Studio is launched, you will see the homepage where you can create or manage different resources. This interface provides a more convenient way to manage data models compared to using the Amplify CLI.

Amplify Studio Homepage


Data Modeling

Now let's create the data model for our blog posts using Amplify Studio.

1. Click on the Data link in the left menu.
2. Click on Add model to create a new model.
3. Enter the model title as Posts.
4. Add the following columns: title, content, and summary.

Data Modeling in Amplify Studio

After defining the model, click on Save and Deploy to deploy the infrastructure.

Wait for a few minutes until Amplify has finished creating all the necessary resources. Once completed, you will see the configuration and instructions for pulling that configuration. Here, you can select the model, operation, and language to generate code for accessing and managing your data.

Amplify Client Configuration


Create Initial Content

Now, on the Amplify Studio home page go to*Content* on the left menu. Here you will be able to create new post and see the list of post that has been created.

Amplify Studio Create Post

Note: There is currently a report that the new data manager doesn't support markdown editor anymore, but there is a work around provided by amplify team until this is resolved:
https://github.com/aws-amplify/amplify-studio/issues/815

And add some markdown content:

Amplify Studio Content


Pull resources

Once we have successfully deployed our infrastructure, you can download the configuration locally using AWS Amplify CLI:

$ amplify pull --appId ddxxxxxxxir --envName dev                                                               

Pre-pull status:

    Current Environment: dev

┌──────────┬────────────────┬───────────┬───────────────────┐
│ Category │ Resource name  │ Operation │ Provider plugin   │
├──────────┼────────────────┼───────────┼───────────────────┤
│ Hosting  │ amplifyhosting │ Create    │                   │
├──────────┼────────────────┼───────────┼───────────────────┤
│ Api      │ albacdev       │ No Change │ awscloudformation │
└──────────┴────────────────┴───────────┴───────────────────┘

⚠️ Local changes detected.
⚠️ Pulling changes from the cloud will override your local changes.
Enter fullscreen mode Exit fullscreen mode

Now you are ready to start coding and use your data model storage.


The Code

In our previous implementation, we used MDX files stored in a GitHub repository to display our markdown content as a web blog page. However, this approach made it challenging to manage and maintain the MDX files through a website. It required downloading, editing, and re-uploading the MDX files.

To improve the management of our blog posts, we can leverage the Amplify libraries for a more efficient workflow.

  • aws-amplify: This is the core library of AWS Amplify, providing a JavaScript interface for interacting with AWS services, including authentication, storage, and database.
  • @aws-amplify/ui-react: This library offers UI components and utilities for building user interfaces in React applications. It includes components for authentication, forms, and commonly used web application UI elements.

These libraries simplify the integration of AWS services into React applications, providing convenient methods and components for tasks like authentication and data management. They abstract the underlying AWS SDKs, offering a higher-level API that streamlines the development process.

To implement this solution, we can also take advantage of the Next.js server-side rendering (SSR) feature supported by the Amplify libraries.

First, make sure you have the necessary Amplify UI libraries by running the following command:

$ npm install aws-amplify @aws-amplify/ui-react
Enter fullscreen mode Exit fullscreen mode

Next, update your _app.js file to configure Amplify and enable SSR support:

import { Amplify } from 'aws-amplify';
import awsconfig from '../src/aws-exports';
Amplify.configure({
  ...awsconfig,
  ssr: true
});
Enter fullscreen mode Exit fullscreen mode

In your [slug.js] file, make the following changes:

+import { withSSRContext } from "aws-amplify";
+import { Posts } from "../../src/models";
import { format, parseISO } from "date-fns"

export async function getStaticProps(context) {
+  const { DataStore } = withSSRContext(context);
  const { params } = context;
-  const allPosts = getAllPosts();
-  const { data, content } = allPosts.find((item) => item.slug === params.slug);
+  const { slug } = params;
+  const post = await DataStore.query(Posts, slug);
+  const { data, content } = matter(post.content);
+  console.log(data, content);
  const mdxSource = await serialize(content);

  return {
    props: {
      ...data,
-      date: data.date.toISOString(),
+      date: post.createdAt,
      content: mdxSource,
    },
+    revalidate: 60 * 60,
  };
}

-export async function getStaticPaths() {
+export async function getStaticPaths(context) {
+  const { DataStore } = withSSRContext(context);
+  const posts = await DataStore.query(Posts);
+  const paths = posts.map((post) => ({ params: { slug: post.id } }));
  return {
-    paths: getAllPosts().map((post) => ({
-      params: {
-        slug: post.slug,
-      },
-    })),
-    fallback: false,
+    paths,
+    fallback: true,
  };
}
Enter fullscreen mode Exit fullscreen mode

Let's break down the changes:

import { withSSRContext } from "aws-amplify";
import { Posts } from "../../src/models";
Enter fullscreen mode Exit fullscreen mode

Here, we import the withSSRContext function, which enables us to query our data using SSR, and the Posts schema from the GraphQL models.

export async function getStaticProps(context) {
  const { DataStore } = withSSRContext(context);
  const { params } = context;
  const { slug } = params;
  const post = await DataStore.query(Posts, slug);
  const { data, content } = matter(post.content);
  const mdxSource = await serialize(content);
Enter fullscreen mode Exit fullscreen mode

We utilize the getStaticProps function from Next.js, which receives the context object containing the req and res keys from the session.

Using context, we leverage withSSRContext from Amplify to obtain the DataStore function. We also extract the parameters and the slug, which represents the ID of our post request. With the slug and DataStore.query function, we fetch the data and assign it to the post variable. From post, we can retrieve all the relevant post details such as the content, date, and summary.

return {
  props: {
    ...data,
    date: post.createdAt,
    content: mdxSource,
    slug: slug,
  },
  revalidate: 60 * 60,
};
Enter fullscreen mode Exit fullscreen mode

Finally, we return the data for rendering. The revalidate property is used to generate the data on the server-side according to the specified schedule.
In the future we will like to use on On-Demand Incremental Static Regeneration (ISR) but at the moment is not a supported feature: https://docs.aws.amazon.com/amplify/latest/userguide/ssr-Amplify-support.html

The same modifications are made to the getStaticPaths function for generating the paths:

export async function getStaticPaths(context) {
  const { DataStore } = withSSRContext(context);
  const posts = await DataStore.query(Posts);
  const paths = posts.map((post) => ({ params: { slug: post.id } }));
  return {
    paths,
    fallback: true,
  };
}
Enter fullscreen mode Exit fullscreen mode

With these changes in place, you can render the post as before, but now utilizing the Post model datastore instead of static files.

  <div className="mx-5">
    <h2 className="dark:text-white text-3xl mt-8 font-bold">
      {title}
    </h2>
    <div className="text-sm text-gray-600 dark:text-gray-200 mt-4">
      Published {format(parseISO(date), "MMMM do, uuu")}
    </div>
    <article
      className="
+        prose dark:prose-invert
+        prose-a:text-blue-600
+        prose-a:font-light
+        prose-a:italic
+        prose-pre:bg-slate-800
+        prose-img:rounded
+        xl:prose-pre:prose-md
+        lg:prose-pre:prose-sm
+        xl:prose-xl
+        lg:prose-lg
+        prose-xl
+        max-w-sm
+        sm:max-w-lg
+        md:max-w-2xl
+        lg:max-w-3xl
+        xl:max-w-5xl
+        2xl:max-w-5xl
+        lg:prose-img:max-w-5xl
+        pt-6 text-slate-600 dark:text-slate-300 font-light font-sans"
    >
      <MDXRemote {...content} />
    </article>
  </div>
Enter fullscreen mode Exit fullscreen mode

You can find the complete code here.

Finally, once you update a blog on Amplify Studio, depending of the revalidation time, the content of the blog will be recreated from our database and show in our website.


Conclusion

In the context of this blog, DynamoDB is used as the data store for the blog posts. Instead of using MDX files, the blog content is stored in a DynamoDB table, which is accessed and managed using Amplify Studio. This approach provides an easy way to manage blog content without having to deal with the complexities of file-based storage.

In summary, AWS Amplify is a powerful development platform that provides a wide range of services and features for building modern web and mobile applications. Amplify Studio is a visual interface that simplifies the process of managing backend resources, making it an ideal choice for developers who prefer a more visual approach. Next.js is a popular React-based framework that offers several features for building server-side rendered web applications. AWS DynamoDB is a highly available, durable, and secure NoSQL database service that provides fast and predictable performance with seamless scalability.


References


Top comments (0)