Strapi CMS Integration
What is Strapi?
Strapi is an open-source, Node.js-based headless CMS that empowers developers to build flexible APIs easily. It provides a customizable admin panel to manage content and deliver it through a REST or GraphQL API.
Key Features
- Headless CMS: Decouples the frontend from the backend content management, allowing for greater flexibility in choosing the presentation layer (React, Vue, Angular, etc.).
- Customizable Content Types: Create custom data structures and content types to fit your specific needs.
- REST & GraphQL APIs: Provides both REST and GraphQL endpoints for retrieving content.
- Admin Panel: Intuitive and customizable admin panel for content creators to easily manage content.
- Authentication & Permissions: Built-in user authentication and advanced role-based permissions to control access to content and functionalities.
- Plugins: Extensible architecture with a rich ecosystem of plugins for added features, such as SEO, internationalization, and more.
- Database Support: Supports multiple databases, including PostgreSQL, MySQL, SQLite, and MongoDB.
Setup
1. Installation
npm install -g @strapi/cli
# Create a new Strapi project
strapi new my-project --quickstart #uses SQLite for default
# or to specify a database:
# strapi new my-project
Follow the prompts if you choose the non-quickstart method to configure database details, admin user etc.
2. Starting the Strapi Server
cd my-project
npm run develop
This will start the Strapi server and open the admin panel in your browser (usually at http://localhost:1337/admin
).
3. Creating Content Types
- Log in to the Strapi admin panel.
- Click on "Content-Type Builder" in the left sidebar.
- Create new "Collection Types" or "Single Types" based on your data structure.
- Add fields (text, number, image, relation, etc.) to your content types.
- Save your content types.
4. Adding Content
- Navigate to the created content type in the left sidebar.
- Click "Add New [Content Type Name]".
- Fill in the fields with your content.
- Save and publish the content. Content must be published to be available from the API by default.
Frontend Integration
Fetching Data with REST API
// Example using fetch API
const apiUrl = "http://localhost:1337/api/articles"; // adjust path and port if different
const fetchData = async () => {
try {
const response = await fetch(apiUrl);
const data = await response.json();
console.log(data.data); // log array of article objects with their attributes
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
Important Notes About the API Response :
- If the
populate
query parameter isn't used, relational fields will only return the ID(s) - The structure of the response is always important for looping:
data
- Either a single object or an array of objects, based on whether the Content Type is a Single or Collection Type.- Each element of the array:
id
- the primary key for that recordattributes
- all the attributes for that content typemeta
- pagination data
- Each element of the array:
meta
- object containing pagination information.
Fetching relational data
Use the populate
query parameter to fetch relational data. For example, if an Article has a relation field author
, use:
const apiUrl = "http://localhost:1337/api/articles?populate=author";
To populate every relational field in the articles
Content Type:
const apiUrl = "http://localhost:1337/api/articles?populate=*";
Fetching Data with GraphQL API
- Enable the GraphQL plugin: In the Strapi admin panel, go to "Marketplace" and install the GraphQL plugin.
- Configure Permissions: Grant public access to the necessary content types in the GraphQL plugin settings.
// Example using axios and GraphQL
import axios from "axios";
const graphqlApiUrl = "http://localhost:1337/graphql";
const query = `
query {
articles {
data {
id
attributes {
title
content
}
}
}
}
`;
const fetchData = async () => {
try {
const response = await axios.post(graphqlApiUrl, { query });
const data = response.data.data.articles.data;
console.log(data); // Log array of the article objects
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
Authentication in Frontend Application
To access protected content types, you need to implement authentication in your frontend application. Strapi provides a REST API for user registration and login.
Register a User
const registerUser = async (username, email, password) => {
try {
const res = await fetch("http://localhost:1337/api/auth/local/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: username,
email: email,
password: password,
}),
});
const data = await res.json();
if (data.error) {
console.error("Registration failed:", data.error.message);
} else {
console.log("Registration successful:", data);
}
return data;
} catch (error) {
console.error("Registration error:", error);
}
};
Login a User
const loginUser = async (identifier, password) => {
try {
const res = await fetch("http://localhost:1337/api/auth/local", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
identifier: identifier,
password: password,
}),
});
const data = await res.json();
if (data.error) {
console.error("Login failed:", data.error.message);
} else {
console.log("Login successful:", data);
}
return data;
} catch (error) {
console.error("Login error:", error);
}
};
After a successful login, Strapi provides a JWT (JSON Web Token) that you need to store securely (e.g., in local storage or cookies).
Accessing Protected Endpoints
To access protected endpoints, include the JWT in the Authorization
header of your requests:
const apiUrlSecured = 'http://localhost:1337/api/private-content'; //Example Route protected by permissions. Edit in Strapi Admin Panel.
const jwtToken = localStorage.getItem('jwt'); //Retrieve JWT from local storage
const fetchSecuredData = async () => {
try {
const response = await fetch (apiUrlSecured, {
method: 'GET',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();
if (data.error) {
console.error('Cannot Access Protected Endpoint:', data.error.message);
} else {
console.log('Successfully fetched protected data:', data);
}
} catch (error) {
console.error('Error fetching secured data:', error);
}
Best Practices
- Define Content Types Carefully: Plan your data structure thoroughly before creating content types.
- Use Environment Variables: Configure database connection details and other sensitive information using environment variables. This is set in
.env
files at the root of your project. - Optimize Images: Use a Strapi plugin or external service to optimize images.
- Implement Caching: Cache API responses on the frontend to improve performance.
- Secure Your API: Implement proper authentication and authorization to protect your API endpoints and content.
- Use a Reverse Proxy: Consider using a reverse proxy (like Nginx) in front of Strapi for better performance, security, and load balancing.
Troubleshooting
- "Forbidden" Errors: Check the roles and permissions settings in Strapi to ensure the correct access rights are granted.
- Database Connection Issues: Verify that your database connection settings are correct and that the database server is running.
- API Endpoint Not Found: Double-check the API endpoint URL and ensure that the content type has been created and published.