Developing an API with REST Builder

After executing gw buildREST, you have two modules: headless-test-api and headless-test-impl.

  • Headless Test API contains the interfaces for your resources and the POJOs of your schemas.

  • Headless Test Impl contains your implementation and the JAX-RS application.

Your generated EntityResource looks like this:

public interface EntityResource {

	public Page<Entity> getEntitiesPage() throws Exception;

	public Entity postEntity(Entity entity) throws Exception;

	public void deleteEntity(Integer entityId) throws Exception;

	public Entity getEntity(Integer entityId) throws Exception;

	public Entity putEntity(Integer entityId, Entity entity) throws Exception;

    //Context methods

	public default void setContextAcceptLanguage(AcceptLanguage contextAcceptLanguage) {}

	public void setContextCompany(Company contextCompany);

	public default void setContextHttpServletRequest(HttpServletRequest contextHttpServletRequest) {}

	public default void setContextHttpServletResponse(HttpServletResponse contextHttpServletResponse) {}

	public default void setContextUriInfo(UriInfo contextUriInfo) {}

	public void setContextUser(User contextUser);

These are generated methods you defined in the OpenAPI profile (the full set as displayed in the examples).

REST builder also generates two implementation files, a base class, with all the JAX-RS, GraphQL and OpenAPI annotations and an empty implementation, EntityResourceImpl:

	properties = "OSGI-INF/liferay/rest/v1_0/",
	scope = ServiceScope.PROTOTYPE, service = EntityResource.class
public class EntityResourceImpl extends BaseEntityResourceImpl {

This is where you implement new methods, by overriding the base class implementation and returning your code. For example, here’s a prototype implementation storing entities in a Map:

Map<Integer, Entity> entities = new HashMap<>();

public Entity getEntity(Integer entityId) throws Exception {
    return entities.get(entityId);

public Page<Entity> getEntitiesPage() throws Exception {
    return Page.of(entities.values());

public void deleteEntity(Integer entityId) throws Exception {

public Entity postEntity(Entity entity) throws Exception {
    entities.put(entity.getId(), entity);
    return entity;

public Entity putEntity(Integer entityId, Entity entity) throws Exception {
    entities.put(entity.getId(), entity);
    return entity;

For the collection, you return a Page object based on a list but there are also utility methods that return the pagination information:

Page.of(list, pagination, totalCount)

Don’t touch the interfaces or the base classes (those are regenerated every time you run REST Builder). Like Service Builder, you only have to maintain the implementation classes, and if you change the API, run REST Builder again and the interfaces are updated. Your business logic could call other REST APIs, use Service Builder or another persistence mechanism.

Development Cycle

While implementing your API’s business logic, you’ll typically improve your API by adding parameters or other paths. For that, you’ll modify the OpenAPI profile and regenerate the API again calling the buildREST command.

The cycle starts anew until you get to the final state and deploy your APIs. They become available at this URL pattern:

http://localhost:8080/o/[application class name]/[OpenAPI version]/

You can also execute jaxrs:check in the OSGi console to see all the JAX-RS endpoints.

GraphQL paths and entities are added automatically to the default GraphQL endpoint:


You can disable GraphQL generation by adding generateGraphQL: false to your rest-config.yaml (generateREST controls the generation of the REST endpoints).

Wrapping Up

So… that’s all!

When everything is ready, you might want to consider publishing your Headless API to Swaggerhub so others can consume it. You can use the following URL pattern for that:

http://localhost:8080/o/[application name]/[application version]/openapi.yaml

The URL for the example above, therefore, would be


This URL has the content of rest-openapi.yaml plus the classes that REST Builder generated for you.

« REST Builder & OpenAPIManaging Collections in REST Builder »
Was this article helpful?
0 out of 0 found this helpful