A Beginner's Guide to Liferay APIs: Fetching Data with Simple JavaScript
If you have been working with Liferay, you already know it is an incredible platform for managing content, building websites, and organizing user data. But what happens when you want to take the data stored inside Liferay and show it on a completely different, external website?
For example, what if you have a simple HTML landing page, and you want to display the latest news articles from your Liferay portal right on that page?
In the past, doing this required complex server-side coding and a deep understanding of Java. Today, thanks to Liferay's Headless APIs, you can accomplish this using basic HTML and a little bit of JavaScript. In this comprehensive, beginner-friendly guide, we are going to learn what an API is, how Liferay handles them, and how to write the code to connect your external page to your Liferay database.
Understanding the Basics: What is an API?
Before we look at the code, let's understand the concept. API stands for Application Programming Interface. That sounds highly technical, but it is actually a very simple concept.
Imagine you are sitting at a restaurant. You look at the menu and decide you want a burger. You don't go into the kitchen and cook the burger yourself. Instead, you tell the waiter what you want. The waiter takes your request to the kitchen, the kitchen makes the food, and the waiter brings it back to your table.
In web development:
- You (The Customer): Are the external HTML website.
- The Kitchen: Is Liferay (holding all the data and content).
- The Waiter: Is the API. It carries your request for data to Liferay, and brings the data back to your website.
Liferay comes pre-packaged with hundreds of these "waiters" ready to take your orders. They are called Headless APIs.
Step 1: Preparing Liferay for Outside Visitors (CORS)
By default, Liferay is highly secure. If a random website tries to ask Liferay for data, Liferay acts like a bouncer at a club and blocks the request. We need to tell Liferay that it is okay to share data with our local computer while we build this project.
This security feature is called CORS (Cross-Origin Resource Sharing). Here is how to configure it:
- Log into your Liferay instance as an Administrator.
- Click the Global Menu (top right) and go to Control Panel → System Settings.
- Under the "Security Tools" section, click on CORS.
- Click the Add button to create a new configuration.
- In the URL Pattern box, type:
/o/*(This tells Liferay to apply this rule to all APIs). - In the Allowed Origins box, type:
*(Note: In a real business scenario, you would type your exact website address here, but the asterisk is perfect for learning and testing). - Click Save.
Your Liferay "bouncer" will now let your HTML page through the door!
Step 2: Building the HTML Structure
Now, let's create our external website. Create a brand new folder on your computer, and inside it, create a file called index.html. Open this file in your favorite text editor (like Notepad, VS Code, or Sublime Text).
We are going to create a very simple page with a button. When we click the button, we want a list of blogs to appear.
Here is the HTML code to get us started:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Liferay App</title>
<style>
body { font-family: Arial, sans-serif; padding: 40px; background: #f4f4f9; }
.blog-card { background: white; padding: 20px; margin-bottom: 15px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
button { padding: 10px 20px; background: #0B5FFF; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
button:hover { background: #0044cc; }
</style>
</head>
<body>
<h1>Latest Company News</h1>
<button id="fetchDataBtn">Load Articles from Liferay</button>
<!-- This empty div is where we will inject the Liferay data -->
<div id="blogContainer" style="margin-top: 20px;"></div>
</body>
</html>
This is standard HTML with a little bit of CSS to make it look pretty. Notice the empty <div id="blogContainer">. This is our blank canvas.
Step 3: Writing the JavaScript (The Magic)
Now for the fun part. We need to write a script that acts as the "waiter," asking Liferay for the blog posts. We will use the modern JavaScript fetch() function.
Add the following code right above the closing </body> tag in your HTML file.
<script>
// 1. Set up our Liferay details
const liferayUrl = "http://localhost:8080";
const siteId = "20121"; // Replace this with your actual Liferay Site ID
// We use Basic Authentication for testing (Email:Password)
const username = "test@liferay.com";
const password = "test";
const credentials = btoa(username + ":" + password); // Encodes it to Base64
// 2. Select our HTML elements
const button = document.getElementById("fetchDataBtn");
const container = document.getElementById("blogContainer");
// 3. Create the function to get the data
async function getLiferayBlogs() {
container.innerHTML = "Loading data from Liferay...";
try {
// This is where we "call the waiter" (API Request)
const response = await fetch(liferayUrl + "/o/headless-delivery/v1.0/sites/" + siteId + "/blog-postings", {
method: "GET",
headers: {
"Authorization": "Basic " + credentials,
"Accept": "application/json"
}
});
// If the bouncer blocks us, or the page is gone, throw an error
if (!response.ok) {
throw new Error("Whoops! Liferay returned an error: " + response.status);
}
// Convert the Liferay data into readable JSON format
const data = await response.json();
// Send the data to our display function
displayBlogs(data.items);
} catch (error) {
container.innerHTML = "<p style='color:red;'>" + error.message + "</p>";
}
}
// 4. Create a function to display the data on the screen
function displayBlogs(blogArray) {
// Clear the "loading" message
container.innerHTML = "";
// Loop through every blog Liferay sent us
blogArray.forEach(blog => {
// Create a new visual card for each blog
const blogHTML = `
<div class="blog-card">
<h2>${blog.headline}</h2>
<p>${blog.articleBody}</p>
<small>Written by: <strong>${blog.creator.name}</strong></small>
</div>
`;
// Add it to our empty container
container.innerHTML += blogHTML;
});
}
// 5. Tell the button to run our function when clicked
button.addEventListener("click", getLiferayBlogs);
</script>
How this code works in plain English:
- Lines 2-8: We define the address to our Liferay server, our Site ID, and our login credentials so Liferay knows we are allowed to see the data.
- Lines 16-27: The
fetch()command travels to the Liferay server and politely asks for the blog posts. We useawaitto tell the browser to wait patiently until Liferay responds. - Lines 40-55: Once Liferay hands us the data (in a format called JSON), we loop through every single blog post. For each one, we dynamically create a block of HTML containing the Headline, the Body, and the Author's Name, and we inject it into our page!
Step 4: Run Your Code!
Make sure your Liferay server is running in the background. Then, simply double-click your index.html file to open it in Google Chrome or Firefox.
Click the blue "Load Articles from Liferay" button. Within a fraction of a second, the page will communicate with Liferay and magically populate your screen with the latest blog posts!
💡 Pro Tips for Future Developers
As you get more comfortable with this, keep these advanced tips in mind:
- Finding Your Site ID: If you don't know what your Site ID is, log into Liferay, go to your Site, click Site Builder → Pages, click the gear icon (Configuration) for the site, and you will see the Site ID listed at the top.
- Security Warning: In our tutorial, we hard-coded our email and password into the JavaScript. This is fine for learning on your local computer, but never do this on a live public website! In the real world, you would use a secure method called OAuth 2.0 to get a temporary token instead.
- Fetch Anything: You aren't limited to blogs! By simply changing the URL in the
fetch()command, you can request Users, Documents, Categories, or Web Content Articles.
⚠️ Common Errors & Fixes
Programming is all about trial and error. If it doesn't work on the first try, don't panic! Check these common issues:
1. "CORS policy blocked the request"
If you see a red CORS error in your browser's developer console (F12), it means you skipped Step 1 of this guide. Liferay is blocking you. Go back and ensure you set up the CORS configuration in the Liferay Control Panel.
2. "Error: 401 Unauthorized"
This means your login credentials are wrong. Make sure the email and password in your JavaScript code match an Administrator account on your Liferay server.
3. "Error: 404 Not Found"
A 404 error means the API route doesn't exist. This usually happens if you type the siteId incorrectly. Double-check that your Site ID matches the one inside Liferay.
Conclusion
Congratulations! You have just successfully decoupled Liferay. By separating the data (Liferay) from the visual display (your HTML page), you have taken your first major step into the world of Headless Architecture.
Using this exact same method, you could build a mobile app, a smartwatch app, or a React dashboard that all pull their information from your central Liferay system.
What kind of data are you hoping to pull out of Liferay? Let me know in the comments below, and I might write a specific tutorial for it!
Frequently Asked Questions
1. Do I need to install Node.js or React to use Liferay APIs?
No! As you saw in this tutorial, you can connect to Liferay APIs using nothing but a plain text file, basic HTML, and the standard JavaScript built directly into every web browser.
2. Can I use this method to send data BACK to Liferay?
Yes. In this tutorial, we used a "GET" request to read data. If you want to create a new blog post from your HTML page, you would change the method to "POST" and send the text data in the body of the request.
3. What is JSON?
JSON stands for JavaScript Object Notation. It is simply a lightweight, organized text format that computers use to talk to each other. When Liferay sends us the blogs, it sends them as JSON, which makes it very easy for our JavaScript to read.
4. Does this work on older versions of Liferay?
The specific "Headless Delivery" APIs used in this tutorial were introduced in Liferay DXP 7.1 and perfected in 7.2, 7.3, and 7.4. If you are using Liferay 7.0 or older (like 6.2), you will have to use the older JSON Web Services (/api/jsonws).
5. Can I fetch images using the API?
Yes. The API will return the URL path to the image (e.g., /documents/portlet_file_entry/...). You can take that path, add your http://localhost:8080 to the front of it, and put it inside an HTML <img src="..."> tag to display it on your site.


Comments
Post a Comment