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.
Setup Payload CMS Server
Install payload with the following command in your terminal.
npx create-payload-app
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"
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()],
});
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();
You can see I adjusted the port that the server is listening on to match what is in my .env
file
app.listen(3100);
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;
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()
]
});
After manually entering a customer you get this view.
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
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
}
}
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"
}
}
}
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
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
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>
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>
const email = ref("");
const password = ref("");
const router = useIonRouter();
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);
}
};
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 the path to sign in page into your browser, and then the credentials for the Customer you created in the CMS
Confirm login worked by looking at the web console
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
Full Source Code
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
- Part One will take us through…
Top comments (1)
Great stuff! We love seeing how people are building with Payload.