Getting Started with Payload CMS & Vue JS

Aaron K Saunders - Sep 22 '23 - - Dev Community

From Payload CMS Documentation - A headless CMS is a system that sticks to what it's good at—managing content. It concentrates solely on granting administrators an effective way to author and maintain content but doesn't control how and where that content is used.

Another definition I found

A headless CMS is a content management system that separates the presentation layer (where content is presented) from the backend (where content is managed). A headless CMS allows you to manage content in one place and be able to deploy that content on any digital channel you choose.

Video Series

In this video series, we will set up Payload CMS Headless CMS, create a Customers collection, log in as a Customer, create an account as a Customer. Then build a simple vuejs website that can login using the API created by Payload CMS and finally look at the changes needed to go from website to mobile application with Ionic Framework.

Series Playlist

Setup Payload CMS Server

Install payload with the following command in your terminal.



npx create-payload-app


Enter fullscreen mode Exit fullscreen mode

the database…

At this time Payload CMS only supports MongoDB.

You can create a free account at Mongo DB Atlas for a cloud-hosted solution - See Website

In this example, I will be using the docker file, docker-compose.yml provided, and only launch the Mongo database service.

Project Configuration

After it is installed and you switch to the project directory you can configure the server. Open up the .env file and make the appropriate changes.

The installation process will add the basics, so all you will need to add is the PAYLOAD_PUBLIC_SERVER_URL, that value will be specific to your environment



MONGODB_URI=mongodb://127.0.0.1:27017/payload-test-1
PAYLOAD_SECRET=4f5b1d73bb08944a9e6d2506
PAYLOAD_PUBLIC_SERVER_URL="http://localhost:3100"


Enter fullscreen mode Exit fullscreen mode

Update the server config payload.config.ts



// payload.config.ts
import { buildConfig } from "payload/config";
import path from "path";
import Users from "./collections/Users";
import { payloadCloud } from "@payloadcms/plugin-cloud";

export default buildConfig({
  serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
  cors: [ ],
  csrf: [ ],
  admin: {
    user: Users.slug,
  },
  collections: [Users],
  typescript: {
    outputFile: path.resolve(__dirname, "payload-types.ts"),
  },
  graphQL: {
    schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"),
  },
  plugins: [payloadCloud()],
});


Enter fullscreen mode Exit fullscreen mode

you can open the server.ts file to make any additional configurations for the express server that is running Payload CMS.

I will ensure the server port is the same as in my .env file.



// server.ts

import express from 'express';
import payload from 'payload';

require('dotenv').config();
const app = express();

// Redirect root to Admin panel
app.get('/', (_, res) => {
  res.redirect('/admin');
});

const start = async () => {
  // Initialize Payload
  await payload.init({
    secret: process.env.PAYLOAD_SECRET,
    mongoURL: process.env.MONGODB_URI,
    express: app,
    onInit: async () => {
      payload.logger.info("Payload Admin URL: " + payload.getAdminURL())
    },
  })

  // Add your own express routes here

  app.listen(3100);
}

start();


Enter fullscreen mode Exit fullscreen mode

You can see I adjusted the port that the server is listening on to match what is in my .env file



app.listen(3100);


Enter fullscreen mode Exit fullscreen mode

Creating the Customer Collection

Finally, let's create a new collection called Customers, this will be the collection of application users. Payload CMS creates a default collection Users, which in this example will be system administrators and people who need to login directly to the Payload CMS console

The code for the Customer Collection is listed below.



// /collections/Customers.ts

import { CollectionConfig } from "payload/types";

const Customers: CollectionConfig = {
  slug: "customers",
  auth: true,
  admin: {
    useAsTitle: "email",
  },
  fields: [
    // Email added by default
    // Add more fields as needed
    {
      name: "full_name",
      type: "text",
      label: "Full Name",
      required: true,
    },
    {
      name: "birthday",
      type: "date",
      label: "Birthday",
      required: true,
    },
  ],
};

export default Customers;


Enter fullscreen mode Exit fullscreen mode

Update configuration in payload.config.ts to include the new Collection Customers



// payload.config.ts

import { buildConfig } from 'payload/config';
import path from 'path';
import Users from './collections/Users';
import { payloadCloud } from '@payloadcms/plugin-cloud';
import Customers from './collections/Customers';

export default buildConfig({
  serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
  admin: {
    user: Users.slug,
  },
  collections: [
    Users,
    Customers
  ],
  typescript: {
    outputFile: path.resolve(__dirname, 'payload-types.ts'),
  },
  graphQL: {
    schemaOutputFile: path.resolve(__dirname, 'generated-schema.graphql'),
  },
  plugins: [
    payloadCloud()
  ]
});


Enter fullscreen mode Exit fullscreen mode

Login to Console
Image description

View Collections
Image description

Create A Customer
Image description

After manually entering a customer you get this view.
Image description

REST API or GraphQL API, Take What You Like

Ad you can see the API URL in the lower right that you can click on and see the JSON object returned. This URL is using REST API by default.

I will be using REST API in this example, additional information in using the REST API can be found here - REST API Overview



http://localhost:3100/api/customers/650dd606d137671cd4d62593?locale=en


Enter fullscreen mode Exit fullscreen mode

Image description

You also get GraphQL support out of the box, see the playground here http://localhost:3100/api/graphql-playground. Be sure to use the URL that is appropriate for your configuration.

Additional information on GraphQL API - https://payloadcms.com/docs/graphql/overview

I can make the same query as I did above



query getCustomer {
  Customer(id: "650dd606d137671cd4d62593") {
    id
    full_name
    email
    birthday
    createdAt
    updatedAt
  }
}


Enter fullscreen mode Exit fullscreen mode

And get the correct results



{
  "data": {
    "Customer": {
      "id": "650dd606d137671cd4d62593",
      "full_name": "aaron clerarlyinnovative",
      "email": "aaron@mail.com",
      "birthday": "2023-09-22T04:00:00.000Z",
      "createdAt": "2023-09-22T17:59:34.571Z",
      "updatedAt": "2023-09-22T18:01:10.593Z"
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Setup Ionic Vue Client

Ionic Framework UI Components are used to build a website and then a mobile application is built using Ionic Capacitor. Ionic UI components are not required but are used for UX. The vue js code presented here will work fine in a separate application.

Use Ionic Framework cli to create a new Vue js project using the blank template.



npx ionic start --type vue


Enter fullscreen mode Exit fullscreen mode

Update the router in the new project to support the two new routes, /sign-in and /sign-up. Make the following changes to /router/index.ts



import { createRouter, createWebHistory } from '@ionic/vue-router';
import { RouteRecordRaw } from 'vue-router';
import HomePage from '../views/HomePage.vue'
import SignIn from '@/views/SignIn.vue';
import SignUp from '@/views/SignUp.vue';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: HomePage
  },
  {
    path: '/sign-in',
    name: 'SignIn',
    component: SignIn
  },
  ,
  {
    path: '/sign-up',
    name: 'SignUP',
    component: SignUp
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router


Enter fullscreen mode Exit fullscreen mode

Create Login Page

Create a new file in the views directory called SignIn.vue and add the code below to create the basic page template.



<template>
  <ion-page>
    <ion-header :translucent="true">
      <ion-toolbar>
        <ion-title> Payload CMS - Ionic Vue</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content :fullscreen="true" >
      <h3 style="margin-left:16px">Sign In</h3>
      <ion-list :inset="true">
        <form @submit.prevent="handleLogin">
          <ion-item>
            <ion-input
              v-model="email"
              name="email"
              label="Email"
              label-placement="stacked"
              autocomplete="email"
              type="email"
            ></ion-input>
          </ion-item>
          <ion-item>
            <ion-input
              v-model="password"
              name="password"
              label="Password"
              label-placement="stacked"
              autocomplete="new-password"
              type="password"
            ></ion-input>
          </ion-item>
          <div class="ion-text-center">
            <ion-button type="submit" fill="clear">Sign In</ion-button>
            <ion-button
              type="button"
              fill="clear"
              @click="router.push('/sign-up')"
              >Create A New Account</ion-button
            >
          </div>
        </form>
      </ion-list>
    </ion-content>
  </ion-page>
</template>


Enter fullscreen mode Exit fullscreen mode

Add Imports and component properties to the file.



<script setup lang="ts">
import {
  IonContent,
  IonHeader,
  IonPage,
  IonTitle,
  IonToolbar,
  IonList,
  IonItem,
  IonInput,
  IonButton,
  useIonRouter,
} from "@ionic/vue";
import { ref } from "vue";

... new code goes here

</script>


Enter fullscreen mode Exit fullscreen mode



const email = ref("");
const password = ref("");
const router = useIonRouter();


Enter fullscreen mode Exit fullscreen mode

Add Login Function

The login function is going to make a REST API call to the Payload CMS backend to authenticate the user.

We use the refs we created above to pass the email and password values to the API call and if successful it will return the user information and the JWT for for authenticating the user in future API calls



const handleLogin = async () => {
  try {
    const resp = await fetch("http://localhost:3100/api/customers/login", {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        email: email.value,
        password: password.value,
      }),
    });

    if (!resp.ok) {
      const errorMsg = (await resp.json())?.errors[0].message;
      throw new Error(errorMsg);
    }
    const user = await resp.json();
    console.log(user);

    // goto home
    router.replace("/home");
  } catch (error: any) {
    alert("Sign In Error " + error.message);
  }
};


Enter fullscreen mode Exit fullscreen mode

Update server to address CORS issue; add the two lines below to the server configuration in payload.config.ts



  cors: ['http://localhost:5173'],
  csrf: ['http://localhost:5173'],


Enter fullscreen mode Exit fullscreen mode

Enter the path to sign in page into your browser, and then the credentials for the Customer you created in the CMS

Image description

Confirm login worked by looking at the web console

Image description

We can also look in the web developer console and see that we have an HTTP cookie from the server that contains the JWT for the authenticated user

Image description

Full Source Code

GitHub logo aaronksaunders / payload-vue-ionic-video

Source code from the video series, Getting Started with PayloadCMS & Vue JS - Free, Open Source, Typescript, Extensible.

payload-vue-ionic-video

Source code from the video series, Getting Started with PayloadCMS & Vue JS - Free, Open Source, Typescript, Extensible. See Video Here

In this video series, we will set up PayloadCMS Headless CMS, create a Customers collection, log in as a Customer, create an account as a Customer. Then build a simple vuejs website that can login using the API created by PayloadCMS and finally look at the changes needed to go from website to mobile application with Ionic Framework.

PayloadCMS - The best way to build a modern backend + admin UI. No black magic, all TypeScript, and fully open-source, Payload is both an app framework and a headless CMS. @payloadcms

Ionic Framework - The mobile SDK for the Web An open-source mobile UI toolkit for building modern, high-quality cross-platform mobile apps from a single code base in React.Vue.Angular. @IonicFramework

The Series

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .