Introduction:
- Rest Builder is Liferay’s tool to build REST and GraphQL APIs.
- Rest builder is a tool that can help developers generate RESTful web services quickly and easily.
- REST Builder can be used to create RESTful web services for a wide range of applications, including web applications, mobile applications, and Iot devices.
Benefits :
The benefits of using REST Builder include:
- Development speed:
- you avoid writing JAX-RS annotations, converters, adding support for multipart or layers to organize your code. Everything is generated.
- API scaffolding:
- pagination, filtering, searching, JSON writers, XML generation, even unit, and integration tests are generated.
- GraphQL support out of the box:
- write your REST API and get a GraphQL endpoint for free.
- JSON & XML support:
- APIs return whichever format the consumer prefers.
- Flexibility:
- REST Builder allows developers to customize the generated code to meet their specific needs.
Prerequisites :
- Liferay 7.x
- Basic understanding of Liferay
- Knowledge of API
Environmental Requirements :
- Liferay
- Eclipse IDE
- Blade CLI
- Gradle
Generating APIs with REST Builder
Follow these steps to REST Builder to create a headless REST API for your apps:- Create a project.
- Open eclipse IDE. Select the desired workspace which is created for your project and then click on launch.
![Step to select Eclipse workspace | REST Builder in Liferay 7.x Step to select Eclipse workspace](https://www.ignek.com/wp-content/uploads/2024/03/Step-to-select-Eclipse-workspace.webp)
- Navigate to the File → New → Other.. → Liferay Workspace Project → Enter Project name → Select Build type → Select Product Version → Then click on Finish tab. Open a new project window.
![Create new Liferay Workspace Project | REST Builder in Liferay 7.x Create new Liferay Workspace Project](https://www.ignek.com/wp-content/uploads/2024/03/Create-new-Liferay-Workspace-Project-1024x454.webp)
![Perspective of newly created Liferay Workspace Project | REST Builder in Liferay 7.x Perspective of newly created Liferay Workspace Project](https://www.ignek.com/wp-content/uploads/2024/03/Perspective-of-newly-created-Liferay-Workspace-Project-1024x526.webp)
- Now create a new REST Builder module project
- Navigate to the Project name → Right click on Modules → New → Liferay Module Project and Click on “Next”
- Enter Project name
- Select “Build type” as “Gradle” → Select “Project Template name” as “REST Builder” → Then click on “Next”
![Creating Gradle module for REST Builder project | REST Builder in Liferay 7.x Creating Gradle module for REST Builder project](https://www.ignek.com/wp-content/uploads/2024/03/Creating-Gradle-module-for-REST-Builder-project-1024x469.webp)
- Open a new window. Enter Component class name → Enter Package name → Click on “Finish”
![Defining Component class and package | REST Builder in Liferay 7.x Defining Component class and package](https://www.ignek.com/wp-content/uploads/2024/03/Defining-Component-class-and-package-1024x458.webp)
- The necessary file structure for Rest Builder automatically gets created as below.
![File structure auto creation for Rest Builder | REST Builder in Liferay 7.x File structure auto-creation for Rest Builder](https://www.ignek.com/wp-content/uploads/2024/03/File-structure-auto-creation-for-Rest-Builder-1024x465.webp)
- In your *-impl module’s root folder, write your OpenAPI profile in “rest-openapi.yaml” file.
Writing YAML files is tricky, so you can use the swagger editor to do it, which validates the YAML file against YAML syntax and the OpenAPI specification.
![Creating API structure in swagger editor | REST Builder in Liferay 7.x Creating API structure in swagger editor](https://www.ignek.com/wp-content/uploads/2024/03/Creating-API-structure-in-swagger-editor-1024x482.webp)
// rest-openapi.yaml
info:
description: "TestRestUsers REST API"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
title: "TestRestUsers"
version: v1.0
openapi: 3.0.1
paths:
"/get-user":
get:
operationId: getUserById
parameters:
- in: query
name: userId
required: true
schema:
type: integer
format: int64
responses:
200:
description: "Success Response"
content:
application/json:
schema:
items:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
items:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
- Once you have written your OpenAPI configuration and profile, it’s time to generate your scaffolding for REST and GraphQL.
- Now Build the REST Builder module.
In the terminal, navigate to the root directory of your rest-builder project
Execute the below command to build the rest-builder module
blade gw buildREST
Or
![Build REST Builder module using eclips | REST Builder in Liferay 7.x Build REST Builder module using eclips](https://www.ignek.com/wp-content/uploads/2024/03/Build-REST-Builder-module-using-eclips-1024x465.webp)
- The necessary file structure for the rest-builder gets created as below.
It’s also generates the *ResourceImpl class where you can write your business logic for implementation of your each service.
![File structure for rest builder created | REST Builder in Liferay 7.x File structure for rest-builder created](https://www.ignek.com/wp-content/uploads/2024/03/File-structure-for-rest-builder-created-1024x463.webp)
- After implementing all the business logic for each service, execute below command to deploy your rest-builder module
blade gw deploy
Or
![Deploying rest builder module after implementing logic | REST Builder in Liferay 7.x Deploying rest-builder module after implementing logic](https://www.ignek.com/wp-content/uploads/2024/03/Deploying-rest-builder-module-after-implementing-logic-1024x465.webp)
Now We have performed the CRUD operation for User in OpenAPI and implemented Business Logic for each service.
Write the OpenAPI profile for the user in “xxx-impl/rest-openapi.yaml” like as below:
// rest-openapi.yaml
info:
description: "TestRestUsers REST API"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
title: "TestRestUsers"
version: v1.0
openapi: 3.0.1
paths:
"/get-user":
get:
operationId: getUserById
parameters:
- in: query
name: userId
required: true
schema:
type: integer
format: int64
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
"/get-users":
get:
operationId: getUsers
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: pageSize
schema:
type: integer
responses:
200:
description: "Success Response"
content:
application/json:
schema:
items:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
items:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
"/update-user":
post:
operationId: updateUser
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
"/delete-user":
delete:
operationId: deleteUserById
parameters:
- in: query
name: userId
required: true
schema:
type: integer
format: int64
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
Your APIs are available at this URL:
http://[host]:[port]/o/[APPLICATION_CLASSNAME]/[OPEN_API_VERSION]/
In our case, the API is available at this URL:
http://localhost:8080/o/api
Business Logic for the User:
Write a business logic in “xxx-impl/com.*.portal.restusers.internal.resource.v1_0” file.
1) Add OR Update User
First write the OpenAPI configuration profile to add or update a new User in “rest-openapi.yaml” file
// rest-openapi.yaml
paths:
"/update-user":
post:
operationId: updateUser
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
Write implementation logic for how to add or update User in “xxx-impl/com.*.portal.restusers.internal.resource.v1_0” file.
Note: If you have passed userId as 0, a new user is created.
If you want to update an existing user then you can pass usedId of existing user for update existing user details.
![Update or add user implementation logic | REST Builder in Liferay 7.x Update or add user implementation logic](https://www.ignek.com/wp-content/uploads/2024/03/Update-or-add-user-implementation-logic-1024x450.webp)
// xxx-impl/com.*.portal.restusers.internal.resource.v1_0
package com.projectname.portal.restusers.internal.resource.v1_0;
import java.util.Locale;
import javax.ws.rs.core.Response;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Validator;
import com.projectname.portal.restusers.dto.v1_0.UserObject;
import com.projectname.portal.restusers.resource.v1_0.UserResource;
/**
* @author DELL
*/
@Component(properties = "OSGI-INF/liferay/rest/v1_0/user.properties", scope = ServiceScope.PROTOTYPE, service = UserResource.class)
public class UserResourceImpl extends BaseUserResourceImpl {
@Reference
private UserLocalService userLocalService;
@Override
public UserObject updateUser(UserObject userObject) throws Exception {
long userId = userObject.getUserId();
long companyId = contextCompany.getCompanyId();
Locale locale = contextAcceptLanguage.getPreferredLocale();
User user = null;
ServiceContext serviceContext = new ServiceContext();
serviceContext.setCompanyId(companyId);
serviceContext.setUserId(contextUser.getUserId());
String firstName = userObject.getFirstName();
String lastName = userObject.getLastName();
String screenName = userObject.getScreenName();
String primaryEmailAddress = userObject.getEmail();
try {
user = Validator.isNotNull(userId) ? userLocalService.updateUser(userId, StringPool.BLANK, StringPool.BLANK,
StringPool.BLANK, false, StringPool.BLANK, StringPool.BLANK, screenName, primaryEmailAddress, false,
null, StringPool.BLANK, StringPool.BLANK, StringPool.BLANK, StringPool.BLANK, firstName,
StringPool.BLANK, lastName, GetterUtil.DEFAULT_LONG, GetterUtil.DEFAULT_LONG, true, 10, 10, 1980,
StringPool.BLANK, StringPool.BLANK, StringPool.BLANK, StringPool.BLANK, StringPool.BLANK,
StringPool.BLANK, GetterUtil.DEFAULT_LONG_VALUES, GetterUtil.DEFAULT_LONG_VALUES,
GetterUtil.DEFAULT_LONG_VALUES, null, GetterUtil.DEFAULT_LONG_VALUES, serviceContext)
: userLocalService.addUser(contextUser.getUserId(), companyId, true, null, null, false, screenName,
primaryEmailAddress, locale, firstName, StringPool.BLANK, lastName, GetterUtil.DEFAULT_LONG,
GetterUtil.DEFAULT_LONG, true, 10, 10, 1980, StringPool.BLANK,
GetterUtil.DEFAULT_LONG_VALUES, GetterUtil.DEFAULT_LONG_VALUES,
GetterUtil.DEFAULT_LONG_VALUES, GetterUtil.DEFAULT_LONG_VALUES, true, serviceContext);
userId = user.getUserId();
userObject.setUserId(userId);
userObject.setStatusCode(Response.ok().build().getStatus());
userObject.setStatusMessage("Added Successfully");
} catch (Exception e) {
_log.error(e.getMessage(), e);
userObject.setStatusCode(Response.serverError().build().getStatus());
userObject.setStatusMessage(e.getMessage());
}
return userObject;
}
public static final Log _log = LogFactoryUtil.getLog(UserResourceImpl.class);
}
Add User
Note: Here you have passed userId as 0 for add new user
![Add User json with 0 userId | REST Builder in Liferay 7.x Add User json with 0 userId](https://www.ignek.com/wp-content/uploads/2024/03/Add-User-json-with-0-userId-702x1024.webp)
Update User by userId
Note: Here you have passed the userId of the existing user.
![Edit User json with desired userId | REST Builder in Liferay 7.x Edit User json with desired userId](https://www.ignek.com/wp-content/uploads/2024/03/Edit-User-json-with-desired-userId-712x1024.webp)
2) Get User
First write the OpenAPI configuration profile to get User in “rest-openapi.yaml” file
// rest-openapi.yaml
paths:
"/get-user":
get:
operationId: getUserById
parameters:
- in: query
name: userId
required: true
schema:
type: integer
format: int64
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
Write Implementation logic for how to get User By UserId in “xxx-impl/com.*.portal.restusers.internal.resource.v1_0” file.
![Implement logic for user retrieval | REST Builder in Liferay 7.x Implement logic for user retrieval](https://www.ignek.com/wp-content/uploads/2024/03/Implement-logic-for-user-retrieval-1024x460.webp)
// xxx-impl/com.*.portal.restusers.internal.resource.v1_0
package com.projectname.portal.restusers.internal.resource.v1_0;
import javax.validation.constraints.NotNull;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.service.UserLocalService;
import com.projectname.portal.restusers.dto.v1_0.UserObject;
import com.projectname.portal.restusers.resource.v1_0.UserResource;
/**
* @author DELL
*/
@Component(properties = "OSGI-INF/liferay/rest/v1_0/user.properties", scope = ServiceScope.PROTOTYPE, service = UserResource.class)
public class UserResourceImpl extends BaseUserResourceImpl {
@Reference
private UserLocalService userLocalService;
@Override
public UserObject getUserById(@NotNull Long userId) throws Exception {
User user = userLocalService.getUser(userId);
UserObject userObject = getUserFromModel(user);
return userObject;
}
private UserObject getUserFromModel(User user) {
UserObject userObject = new UserObject();
userObject.setScreenName(user.getScreenName());
userObject.setFirstName(user.getFirstName());
userObject.setLastName(user.getLastName());
userObject.setEmail(user.getEmailAddress());
return userObject;
}
public static final Log _log = LogFactoryUtil.getLog(UserResourceImpl.class);
}
Get User By userId
![Exploring API to get User details By userId | REST Builder in Liferay 7.x Exploring API to get User details By userId](https://www.ignek.com/wp-content/uploads/2024/03/Exploring-API-to-get-User-details-By-userId-1024x963.webp)
3) Delete User
First write the OpenAPI configuration profile to delete existing User in “rest-openapi.yaml” file
// rest-openapi.yaml
paths:
"/delete-user":
delete:
operationId: deleteUserById
parameters:
- in: query
name: userId
required: true
schema:
type: integer
format: int64
responses:
200:
description: "Success Response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
Write Implementation logic for how to delete User in “xxx-impl/com.*.portal.restusers.internal.resource.v1_0″ file.
![Delete user logic in portal file | REST Builder in Liferay 7.x Delete user logic in portal file](https://www.ignek.com/wp-content/uploads/2024/03/Delete-user-logic-in-portal-file-1024x458.webp)
// xxx-impl/com.*.portal.restusers.internal.resource.v1_0
package com.projectname.portal.restusers.internal.resource.v1_0;
import javax.validation.constraints.NotNull;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.service.UserLocalService;
import com.projectname.portal.restusers.dto.v1_0.UserObject;
import com.projectname.portal.restusers.resource.v1_0.UserResource;
/**
* @author DELL
*/
@Component(properties = "OSGI-INF/liferay/rest/v1_0/user.properties", scope = ServiceScope.PROTOTYPE, service = UserResource.class)
public class UserResourceImpl extends BaseUserResourceImpl {
@Reference
private UserLocalService userLocalService;
@Override
public UserObject deleteUserById(@NotNull Long userId) throws Exception {
UserObject userObject = new UserObject();
try {
userLocalService.deleteUser(userId);
userObject.setStatusCode(200);
userObject.setStatusMessage("Deleted Successfully");
} catch (Exception e) {
_log.error(e.getMessage(), e);
userObject.setStatusCode(500);
userObject.setStatusMessage(e.getMessage());
}
return userObject;
}
public static final Log _log = LogFactoryUtil.getLog(UserResourceImpl.class);
}
Delete User By userId
![Exploring API to delete user by userId | REST Builder in Liferay 7.x Exploring API to delete user by userId](https://www.ignek.com/wp-content/uploads/2024/03/Exploring-API-to-delete-user-by-userId-1024x884.webp)
4) Get All Users
First write the OpenAPI configuration profile to get all Users in “rest-openapi.yaml” file
// rest-openapi.yaml
paths:
"/get-users":
get:
operationId: getUsers
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: pageSize
schema:
type: integer
responses:
200:
description: "Success Response"
content:
application/json:
schema:
items:
$ref: "#/components/schemas/UserObject"
application/xml:
schema:
items:
$ref: "#/components/schemas/UserObject"
tags: ["User"]
components:
schemas:
UserObject:
properties:
userId:
type: integer
format: int64
screenName:
type: string
firstName:
type: string
lastName:
type: string
email:
type: string
statusCode:
type: integer
statusMessage:
type: string
Write Implementation logic for how to get all Users in “xxx-impl/com.*.portal.restusers.internal.resource.v1_0″ file.
![Retrieve all Users in implementation logic | REST Builder in Liferay 7.x Retrieve all Users in implementation logic](https://www.ignek.com/wp-content/uploads/2024/03/Retrieve-all-Users-in-implementation-logic-1024x459.webp)
// xxx-impl/com.*.portal.restusers.internal.resource.v1_0
package com.projectname.portal.restusers.internal.resource.v1_0;
import java.util.ArrayList;
import java.util.List;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.vulcan.pagination.Page;
import com.liferay.portal.vulcan.pagination.Pagination;
import com.projectname.portal.restusers.dto.v1_0.UserObject;
import com.projectname.portal.restusers.resource.v1_0.UserResource;
/**
* @author DELL
*/
@Component(properties = "OSGI-INF/liferay/rest/v1_0/user.properties", scope = ServiceScope.PROTOTYPE, service = UserResource.class)
public class UserResourceImpl extends BaseUserResourceImpl {
@Reference
private UserLocalService userLocalService;
@Override
public Page getUsers(Pagination pagination) throws Exception {
List userObjects = new ArrayList<>();
List users = userLocalService.getUsers(pagination.getStartPosition(), pagination.getEndPosition());
for (User user : users) {
UserObject userObject = getUserFromModel(user);
userObjects.add(userObject);
}
return Page.of(userObjects, pagination, userObjects.size());
}
private UserObject getUserFromModel(User user) {
UserObject userObject = new UserObject();
userObject.setScreenName(user.getScreenName());
userObject.setFirstName(user.getFirstName());
userObject.setLastName(user.getLastName());
userObject.setEmail(user.getEmailAddress());
return userObject;
}
public static final Log _log = LogFactoryUtil.getLog(UserResourceImpl.class);
}
Get All Users
Note: Here you have passed page and page-size for getting users.
![Exploring API to get user list with pagination | REST Builder in Liferay 7.x Exploring API to get user list with pagination](https://www.ignek.com/wp-content/uploads/2024/03/Exploring-API-to-get-user-list-with-pagination-802x1024.webp)