Guide - Create a New Storefront REST Resource

1 Introduction

This article describes how to add a new REST resource to an existing REST API. It is intended as a practical walkthrough which will provide information and understanding to start creating a new REST resource. Also included is the creation of a new persistent object in combination with an own business object.

It is not necessary to copy the source code from each section. Use the support cartridges for your own business as a blueprint:

2 What Do You Learn?

You are able to create a new REST API.
You are able to create a new business object.
You are able to create a new persistent object.
You are able to work with the component framework.
You are list your new REST API in the SMC.
You have access to the new business object about the ApplicationBO.
You have access to the new functionality via ISML.

3 Create a New Business Object

This chapter explains how to create a new support_by_mycoupon business cartridge via Intershop Studio. This cartridge contains a new persistent object MyCouponPO and also the new business object MyCouponBO

3.1 Create a New Persistent Object - MyCouponPO

  1. Add a new folder edl and place the two files MyCoupon.edl and MyCouponPO.edl as shown in the following screenshot:

    MyCoupon
    import "enfinity:/core/edl/com/intershop/beehive/core/types.edl";
    
    external PersistentObject type "com.intershop.beehive.core.capi.domain.PersistentObject";
    
    namespace com.intershop.support.component.mycoupon.internal
    {
    	cartridge interface MyCoupon extends PersistentObject 
    	{
    		/*
    		 * The email for mycoupon
    		 */
    		 attribute email: string required;
    		 
    		 /*
    		  * The coupon text
    		  */
    		 attribute coupon: string required ;
    				
    		 /**
    		  * The creation date
    	      */
              attribute creationDate : datetime required;
    	}
    }
    
    MyCouponPO
    import "enfinity:/support_bc_mycoupon/edl/com/intershop/support/component/mycoupon/capi/MyCoupon.edl";
    import "enfinity:/core/edl/com/intershop/beehive/core/capi/domain/PersistentObjectPO.edl";
    import "enfinity:/core/edl/com/intershop/beehive/core/types.edl";
    
    namespace com.intershop.support.component.mycoupon.internal
    {
    	orm class MyCouponPO extends PersistentObjectPO implements MyCoupon
    	{
    		/*
    		 * The email for mycoupon
    		 */
    		 attribute email: string required;
    		 
    		 /*
    		  * The coupon text for mycoupon
    		  */
    		 attribute coupon: string<256> required ;
    		  
    		 /**
    		  * The creation date
    	      */
              attribute creationDate : datetime required;
    
    		  index(email, coupon);
    	}
    }
    
  2. Prepare a new EDL model.
    1. Select the support_my_mycoupon cartridge.
    2. Open the context menu and click Generate Code (EDL-Models).

      This generates the classes based on your new EDL files.
      In case of success the console output contains the following lines:

      edl generation console output
      Generate code for cartride support_bc_mycoupon
      Generated but NOT changed: '/support_bc_mycoupon/src/main/resources/com/intershop/support/component/mycoupon/internal/MyCouponPO.dbconstraints.oracle.ddl'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/resources/com/intershop/support/component/mycoupon/internal/MyCouponPO.dbconstraints.microsoft.ddl'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/resources/com/intershop/support/component/mycoupon/internal/MyCouponPO.dbindex.oracle.ddl'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/resources/com/intershop/support/component/mycoupon/internal/MyCouponPO.dbindex.microsoft.ddl'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/java/com/intershop/support/component/mycoupon/internal/MyCouponPOKey.java'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/java/com/intershop/support/component/mycoupon/internal/MyCouponPO.java'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/java/com/intershop/support/component/mycoupon/internal/MyCouponPOFactory.java'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/resources/com/intershop/support/component/mycoupon/internal/MyCouponPO.orm'
      Generated but NOT changed: '/support_bc_mycoupon/src/main/java/com/intershop/support/component/mycoupon/internal/MyCoupon.java'

3.2 Create a New Business Object - MyCouponBO

With the newly generated MyCouponPO we can create our own business object. The goal is to use it in our new REST API and to be able to invoke the extension through ApplicationBOAdditionally, we want to use our new business object via ISML and pipelines.

To create a new business project, perform the following steps:

  1. Create a new interface MyCouponBO.
    In this case we keep it simple and our class contains only two methods. Feel free to create more methods for your business layer to hide internal functionality. For more information about business objects, refer to Concept - Business Objects.

    MyCouponBO
    package com.intershop.support.component.mycoupon.capi;
    
    import com.intershop.beehive.businessobject.capi.BusinessObject;
    
    /**
     * A simple business object with only two attributes.
     */
    public interface MyCouponBO extends BusinessObject
    {
        /**
         * @return code of the coupon
         */
        String getCode();
    
        /**
         * 
         * @return email of the coupon
         */
        String getEmail();
    }
    
    MyCouponBOImpl
    package com.intershop.support.component.mycoupon.internal;
    
    import com.intershop.beehive.businessobject.capi.BusinessObjectContext;
    import com.intershop.beehive.core.capi.domain.AbstractPersistentObjectBO;
    import com.intershop.support.component.mycoupon.capi.MyCouponBO;
    
    public class MyCouponBOImpl extends AbstractPersistentObjectBO<MyCouponPO> implements MyCouponBO
    {
        public MyCouponBOImpl(MyCouponPO myCouponPO, BusinessObjectContext context)
        {
            super(myCouponPO, context);
        }
    
        @Override
        public String getCode()
        {
            return this.getPersistentObject()
                            .getCoupon();
        }
    
        @Override
        public String getEmail()
        {
            return this.getPersistentObject()
                            .getEmail();
        }
    }
    
    
    

    Our business object is ready.

  2. Create a repository, therefore create a new interface MyCouponBORepository which manages the life cycle:

    MyCouponBORepository
    package com.intershop.support.component.mycoupon.capi;
    
    import com.intershop.beehive.businessobject.capi.BusinessObjectRepository;
    
    /**
     * Repository for {@link MyCouponBO}.
     */
    public interface MyCouponBORepository extends BusinessObjectRepository
    {
        public static final String EXTENSION_ID = "MyCouponBORepository";
    
        /**
         * Creates a coupon by the given email if the email has already an active coupon, 
         * the active coupon will be returned.
         * 
         * @param email - the email for the coupon
         * 
         * @return a new {@link MyCouponBO} for the given email
         **/
        MyCouponBO createMyCouponBOByEmail(String email);
    
        /**
         * Counts all {@link MyCouponBO}s for the given email. 
         * 
         * @return the count of all {@link MyCouponBO} for a single email
         **/
        int countMyCouponsByEmail(String email);
    
        /**
         * Gets a {@link MyCouponBO} by a coupon code
         * 
         * @param couponCode - the coupon code
         * @return the {@link MyCouponBO} 
         */
        MyCouponBO getMyCouponBOByCode(String couponCode);
    }
    MyCouponBORepositoryImpl
    package com.intershop.support.component.mycoupon.internal;
    
    import java.nio.charset.Charset;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    import com.google.inject.Inject;
    import com.intershop.beehive.core.capi.util.ObjectMapper;
    import com.intershop.beehive.orm.capi.common.ORMObjectCollection;
    import com.intershop.component.repository.capi.AbstractDomainRepositoryBOExtension;
    import com.intershop.component.repository.capi.RepositoryBO;
    import com.intershop.support.component.mycoupon.capi.MyCouponBO;
    import com.intershop.support.component.mycoupon.capi.MyCouponBORepository;
    
    public class MyCouponBORepositoryImpl extends AbstractDomainRepositoryBOExtension
                    implements MyCouponBORepository, ObjectMapper<MyCouponPO, MyCouponBO>
    {
        /**
         * Stores all MyCoupons to it's persistance objects
         */
        private Map<MyCouponPO, MyCouponBO> cache = new HashMap<>();
    
        @Inject
        private MyCouponPOFactory myCouponPOFactory;
        
        public MyCouponBORepositoryImpl(String extensionID, RepositoryBO extendedObject)
        {
            super(extensionID, extendedObject);
        }
    
        /**
         * Returns the {@link MyCouponBO} for it's persistance object. If it's not existing, a new my coupon is created.
         * 
         * @param myCouponPO
         *                            - persistance object, that should converted to its business object
         * @return the {@link MyCouponBO} for the given persistance object
         */
        @Override
        public synchronized MyCouponBO resolve(MyCouponPO myCouponPO)
        {
            if (this.cache.containsKey(myCouponPO))
            {
                return this.cache.get(myCouponPO);
            }
    
            MyCouponBO myCouponBO = new MyCouponBOImpl(myCouponPO, getContext());
            cache.put(myCouponPO, myCouponBO);
    
            return myCouponBO;
        }
    
        /**
         * for the given parameters a new MyCoupon will be created
         */
        @Override
        public MyCouponBO createMyCouponBOByEmail(String email)
        {
            // you can validate the code and so on
            MyCouponPO myCouponPO = this.myCouponPOFactory.create(getDomain(), email, generateCode(), new java.util.Date());
            MyCouponBO myCouponBO = this.resolve(myCouponPO);
            cache.put(myCouponPO, myCouponBO);
            return myCouponBO;
        }      
    
        private String generateCode() 
        {
            byte[] array = new byte[7];
            new Random().nextBytes(array);
            return new String(array, Charset.forName("UTF-8")); 
        }
        
        @Override
        public int countMyCouponsByEmail(String email)
        {
            @SuppressWarnings("unchecked")
            final Collection<MyCouponPO> myCouponPOs = this.myCouponPOFactory
                            .getObjectsBySQLWhere("email = ? ", new String[] { email });
    
            return myCouponPOs.size();
        }
    
        /**
         * Generates a coupon code
         * @return the generated coupon code
         */
        @Override
        public MyCouponBO getMyCouponBOByCode(String couponCode)
        {
            @SuppressWarnings("unchecked")
            final ORMObjectCollection<MyCouponPO> myCouponPOs = this.myCouponPOFactory
                            .getObjectsBySQLWhere("coupon=?", new Object[] { couponCode });
    
            if (myCouponPOs.isEmpty())
            {
                return null;
            }
            return resolve(myCouponPOs.iterator().next());
        }
    }
    
    
    

    Our repository is ready. However, at this stage it is not wired via component framework and can still not be used.

  3. Create a new factory MyCouponBORepositoryExtensionFactory. This factory will be used in our component framework later.

    MyCouponBORepositoryExtensionFactory
    package com.intershop.support.component.mycoupon.internal;
    
    import javax.inject.Inject;
    
    import com.google.inject.Injector;
    import com.intershop.beehive.businessobject.capi.BusinessObjectExtension;
    import com.intershop.component.repository.capi.AbstractDomainRepositoryBOExtensionFactory;
    import com.intershop.component.repository.capi.RepositoryBO;
    import com.intershop.support.component.mycoupon.capi.MyCouponBORepository;
    
    /**
     * Factory class for the {@link MyCouponBORepository}.
     */
    public class MyCouponBORepositoryExtensionFactory extends AbstractDomainRepositoryBOExtensionFactory
    {
        @Inject
        private Injector injector; 
        
        @Override
        public BusinessObjectExtension<RepositoryBO> createExtension(RepositoryBO repository)
        {
            MyCouponBORepositoryImpl myCouponBORepositoryImpl = new MyCouponBORepositoryImpl(MyCouponBORepository.EXTENSION_ID, repository);
            injector.injectMembers(myCouponBORepositoryImpl);
            return myCouponBORepositoryImpl;
        }
    
        @Override
        public String getExtensionID()
        {
            return MyCouponBORepository.EXTENSION_ID;
        }
    }
    
    
  4. Extend the ApplicationBO, so the new business functionality is also available for ISML and Pipeline:

    ISML and Pipeline
    <isset name="MyCouponBORepository" value="#ApplicationBO:Extension("MyCouponBORepository")#" scope="request"/>

    or the Java context:

    Java
    applicationBO.getExtension("MyCouponBORepository")

    It is also already possible to create the two files implementations.component and instances.component. However, this is shown in the next section, Wiring of our New Business Object Factories via Component Framework.

  5. Extend the ApplicationBO with the following classes:

    ApplicationBOMyCouponExtension
    package com.intershop.support.component.mycoupon.capi;
    
    import com.intershop.beehive.businessobject.capi.BusinessObjectExtension;
    import com.intershop.component.application.capi.ApplicationBO;
    
    /**
     * Extension for the {@link ApplicationBO}.
     * </br>
     * Example for usage:
     * <pre>
     * public class MyCouponHandler 
     * {
     *      @Inject
     *      CurrentApplicationBOProvider applicationProvider;
     *  
     *      private MyCouponBORepository getMyCouponBORepository()
     *      {
     *          MyCouponBORepository myCouponBORepository = applicationProvider.getExtension(MyCouponBORepository.class);
     *      }
     *      
     *      public MyCouponBO getMyCouponBOByCode(String couponCode)
     *      {
     *          return getMyCouponBORepository().getMyCouponBOByCode(couponCode);
     *      }      
     * } 
     * </pre>
     */
    public interface ApplicationBOMyCouponExtension extends BusinessObjectExtension<ApplicationBO>
    {
        /**
         * The ID of the created extensions which can be used to get them from the business object later.
         */
        public static final String EXTENSION_ID = "MyCoupon";
    
        /**
         * Returns the {@link MyCouponBORepository}.
         * 
         * @return The {@link MyCouponBORepository}.
         */
        public MyCouponBORepository getMyCouponBORepository();
    }
    
    
    ApplicationBOMyCouponExtensionImpl
    package com.intershop.support.component.mycoupon.internal;
    
    import com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtension;
    import com.intershop.beehive.businessobject.capi.MissingExtensionException;
    import com.intershop.component.application.capi.ApplicationBO;
    import com.intershop.support.component.mycoupon.capi.ApplicationBOMyCouponExtension;
    import com.intershop.support.component.mycoupon.capi.MyCouponBORepository;
    
    public class ApplicationBOMyCouponExtensionImpl extends AbstractBusinessObjectExtension<ApplicationBO>
                    implements ApplicationBOMyCouponExtension
    {
        public ApplicationBOMyCouponExtensionImpl(String extensionID, ApplicationBO extendedObject)
        {
            super(extensionID, extendedObject);
        }
    
        @Override
        public MyCouponBORepository getMyCouponBORepository()
        {
            MyCouponBORepository myCouponBORepository = getExtendedObject()
                            .getRepository(MyCouponBORepository.EXTENSION_ID);
    
            if (myCouponBORepository == null)
            {
                throw new MissingExtensionException("MyCouponBORepository " + MyCouponBORepository.class);
            }
    
            return myCouponBORepository;
        }
    }
  6. Create the factory ApplicationBOMyCouponExtensionFactory class in the same manner as class MyCouponBORepositoryExtensionFactory:

    ApplicationBOMyCouponExtensionFactory
    package com.intershop.support.component.mycoupon.internal;
    
    import com.intershop.beehive.businessobject.capi.AbstractBusinessObjectExtensionFactory;
    import com.intershop.beehive.businessobject.capi.BusinessObjectExtension;
    import com.intershop.component.application.capi.ApplicationBO;
    import com.intershop.support.component.mycoupon.capi.ApplicationBOMyCouponExtension;
    
    /**
     * The interface describes an extension of the application BO which is intended to retrieve the BO repository of the
     * promotion code.
     */
    public class ApplicationBOMyCouponExtensionFactory extends AbstractBusinessObjectExtensionFactory<ApplicationBO>
    {
        @Override
        public BusinessObjectExtension<ApplicationBO> createExtension(ApplicationBO application)
        {
            return new ApplicationBOMyCouponExtensionImpl(ApplicationBOMyCouponExtension.EXTENSION_ID,
                            application);
        }
    
        @Override
        public Class<ApplicationBO> getExtendedType()
        {
            return ApplicationBO.class;
        }
    }
    
    

3.3 Wiring of our New Business Object Factories via Component Framework 

To set up the wiring of our new business object factories via the component framework, perform the following step:

Delegate the factory initialization to the injection framework called component framework. 

implementations.component
<components xmlns="http://www.intershop.de/component/2010"
	scope="global">
	<implementation
		name="MyCouponBORepositoryExtensionFactory"
		implements="BusinessObjectExtensionFactory"
		class="com.intershop.support.component.mycoupon.internal.MyCouponBORepositoryExtensionFactory" />		
	
	<implementation name="ApplicationBOMyCouponExtensionFactory"
                    class="com.intershop.support.component.mycoupon.internal.ApplicationBOMyCouponExtensionFactory">
    </implementation> 
	
</components>
instances.component
<components xmlns="http://www.intershop.de/component/2010">

	<fulfill requirement="extensionFactory"
		of="com.intershop.beehive.core.capi.businessobject.BusinessObjectExtensionFactories">
		<instance with="MyCouponBORepositoryExtensionFactory" />
		<instance with="ApplicationBOMyCouponExtensionFactory" />
	</fulfill>
	
</components>

After server start the ApplicationBO lists the new extension ApplicationBOMyCouponExtension.

3.4 Enable the New Cartridge for DBInit and DBMigrate

Before we can use our new persistent object and create REST calls which use our new business object we have to create two files for the DBInit and DBMigrate process.

  1. Create two files dbinit.properties and dbmigrate.properties:

    dbinit.properties
    pre.Class1 = com.intershop.beehive.core.dbinit.preparer.database.DatabaseTablesPreparer
    dbmigrate
    Class1 = com.intershop.beehive.core.dbmigrate.preparer.database.DatabaseTablesPreparer
    Class2 = com.intershop.beehive.core.dbmigrate.preparer.database.CartridgeDatabaseConstraintsPreparer
    Class3 = com.intershop.beehive.core.dbmigrate.preparer.database.CartridgeDatabaseIndexesPreparer
  2. Modify apps.component by adding the new business cartridge to the existing intershop.B2CResponsive.Cartridges instance. 

    snippet from the apps.component
    <components xmlns="http://www.intershop.de/component/2010">
    
        <!-- ************************************************************************************ -->
        <!-- *           Application Type "intershop.B2CResponsive"                                * -->
        <!-- ************************************************************************************ -->
    
        <instance name="intershop.B2CResponsive.Cartridges" with="CartridgeListProvider">
    		<fulfill requirement="selectedCartridge" value="support_bc_mycoupon"/>
            ...
    	</instance>
  3. Change the build.gradle file for your assembly and add the new cartridge.

    snippet from the build.gradle file
            def storefrontCartridges = [
                'app_sf_base_cm',
                'app_sf_pwa_cm',
                'app_sf_responsive',
                'app_sf_responsive_cm',
                'app_sf_responsive_b2c',
                'app_sf_responsive_smb',
                'as_responsive',
                'app_sf_responsive_b2b',
                'app_sf_responsive_costcenter',
                'as_responsive_b2b',
                'app_sf_responsive_gdpr',
                'app_sf_responsive_rma',
    			'ac_oidc_sf_responsive ',
                'ac_oidc_sf_responsive_smb',
    			'ac_oidc_sf_responsive_b2b',
    			'support_bc_mycoupon'
  4. Run the following commands to create a new table MyCoupon:

    1. gradlew clean publish deployServer

    2. gradlew <your assembly>:dbinit or gradlew <your assembly>:dbmigrate to create your new table MyCoupon.

      If the wiring, publishing and the deploy server task were successful, there should be no errors when starting the server.

We suggest that you download the cartridges and integrate it as blueprint on your test environment and for further development. 

4 Create a New REST API

4.1  Create a new Cartridge support_app_sf_rest_mycoupon

  1. Create a new cartridge e.g.: support_app_sf_rest_mycoupon.
  2. Change the build.gradle file and add your new business cartridge too.

The following snippet from the build.gradle file demonstrates the usage of your new business cartridge in context of our new REST API:

snippet from the build.gradle file
apply plugin: 'java-cartridge'
apply plugin: 'static-cartridge'

intershop
{
    displayName = 'Application - My Coupon REST API'
}


dependencies {
    compile project(':support_bc_mycoupon')
    ...
}

4.2 Create a New Resource - MyCouponResource

We define the resource class as an item resource. Thus we use the AbstractRestResource. For collections use the base class AbstractRestCollectionResource instead.

Create the following resource:

MyCouponResource
package com.intershop.support.app_sf_mycoupon_rest.capi.resource;

import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.google.inject.Inject;
import com.intershop.beehive.core.internal.opexpression.parser.ParseException;
import com.intershop.component.application.capi.CurrentApplicationBOProvider;
import com.intershop.component.rest.capi.RestException;
import com.intershop.component.rest.capi.openapi.OpenAPIConstants;
import com.intershop.component.rest.capi.resource.AbstractRestResource;
import com.intershop.component.rest.internal.RestFrameworkConstants;
import com.intershop.support.app_sf_mycoupon_rest.capi.resourceobject.MyCouponRO;
import com.intershop.support.component.mycoupon.capi.ApplicationBOMyCouponExtension;
import com.intershop.support.component.mycoupon.capi.MyCouponBO;
import com.intershop.support.component.mycoupon.capi.MyCouponBORepository;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "Experimental", description = " ")
@OpenAPIDefinition(extensions = @Extension(
                properties = { @ExtensionProperty(name = OpenAPIConstants.API_ID, value = "promotion") }))
public class MyCouponResource extends AbstractRestResource
{
    private static final String MY_COUPON = "mycoupon";

    @Inject
    private CurrentApplicationBOProvider currentApplicationBOProvider;

    public MyCouponResource()
    {
        super();
        setName(MY_COUPON);
    }

    /**
     * Returns for a given email a coupon.
     */
    @Operation(summary = "Creates a coupon.")
    @POST
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    public Response generateMyCoupon(@QueryParam("email") String email) throws ParseException
    {
        // validate query parameter 'email'
        if (email == null || email.length() == 0)
        {
            throw new RestException().badRequest()
                            .message("Email is required to generate a coupon!")
                            .localizationKey("mycoupon.missing_email.error");
        }

        // get MyCouponBORepository to create a coupon
        ApplicationBOMyCouponExtension applicationBOMyCouponExtension = currentApplicationBOProvider.get()
                        .getExtension(ApplicationBOMyCouponExtension.EXTENSION_ID);
        MyCouponBORepository myCouponBORepository = applicationBOMyCouponExtension.getMyCouponBORepository();

        // create a coupon
        MyCouponBO myCouponBO = myCouponBORepository.createMyCouponBOByEmail(email);

        // validate the business object in case of error throw an exception
        if (myCouponBO == null || myCouponBO.getCode() == null)
        {
            throw new RestException().message("The Coupon code could not be generated!")
                            .localizationKey("mycoupon.generate_not_possible.error");
        }

        MyCouponRO myCouponRO = new MyCouponRO(myCouponBO);

        // make non-cacheable
        setCacheExpires(RestFrameworkConstants.CACHE_EXPIRY_NOCACHE);
        return getResponseBuilder().entity(myCouponRO)
                        .build();
    }
    
    @Override
    public MyCouponResource getRequestSpecificCopy(ResourceContext rc)
    {
        MyCouponResource result = (MyCouponResource)super.getRequestSpecificCopy(rc);
        return result;
    }
}

Info

We recommend to annotate your resource classes too. For details, refer to Cookbook - Developer Tools ac_swagger.

4.3 Create a New Resource Object - MyCouponRO

  1. Define a new resource object MyCouponRO which uses our new business object MyCouponBO. This class holds the data and will be displayed.

    MyCouponRO
    package com.intershop.support.app_sf_mycoupon_rest.capi.resourceobject;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    import com.fasterxml.jackson.annotation.JsonTypeName;
    import com.intershop.component.rest.capi.resourceobject.AbstractResourceObject;
    import com.intershop.support.component.mycoupon.capi.MyCouponBO;
    
    import io.swagger.v3.oas.annotations.media.Schema;
    
    @XmlRootElement(name = MyCouponRO.TYPENAME)
    @JsonTypeName(value = MyCouponRO.TYPENAME)
    /**
     * This is the resource object for my coupon code.
     */
    public class MyCouponRO extends AbstractResourceObject
    {
        public final static String TYPENAME = "MyCoupon";
        public final static String NAME = "MyCoupon";
    
        private String code;
    
        public MyCouponRO(MyCouponBO myCouponBO)
        {
            super(NAME);
            setCode(myCouponBO.getCode());
        }
    
        /**
         * @return the coupon code
         */
        @Schema(description = "The coupon code")
        public String getCode()
        {
            return code;
        }
    
        /**
         * @param code the coupon code to set
         */
        public void setCode(String code)
        {
            this.code = code;
        }
    
        @Override
        @Schema(description = "The type of the object", example = TYPENAME)
        public String getType()
        {
            return TYPENAME;
        }
    }

4.4 Wiring via Component Framework

Currently there are two ways to wire a new REST API: via the component framework, see Cookbook - REST Framework, or via Guice, see Cookbook - REST Framework (Guice Based).

The following example shows wiring via the component framework.

  1. Register the resource as component via the component framework. Therefore we create the following files:

    • contracts.component

    • implementations.component

    • instances.component

      contracts.component
      <components xmlns="http://www.intershop.de/component/2010" scope="global">
      	<contract name="MyCouponResource" class="com.intershop.support.app_sf_mycoupon_rest.capi.resource.MyCouponResource"/>
      </components>
      implementations.component
      <components xmlns="http://www.intershop.de/component/2010">
      	<implementation name="MyCouponResource" class="com.intershop.support.app_sf_mycoupon_rest.capi.resource.MyCouponResource" factory="JavaBeanFactory"
      	implements="AbstractRestResource">
      		<requires name="subResource" contract="RestResource" cardinality="0..n" />
      		<requires name="name" contract="String" cardinality="1..1" />
      	</implementation>
      </components>
      instances.component
      	<components xmlns="http://www.intershop.de/component/2010">
      		<fulfill requirement="subResource" of="intershop.B2CWebShop.RESTAPI.root">
      			<instance name="intershop.B2CWebShop.RESTAPI.MyCouponResource" with="MyCouponResource">
      				<fulfill requirement="name" value="mycoupon" />
      			</instance>
      		</fulfill>
      		<fulfill requirement="resourceACLCartridge" value="support_app_sf_rest_mycoupon" of="intershop.B2CWebShop.RESTAPI.AuthorizationService"/>
       </components>

      instances.component declares that our new REST API will be triggered by the path /mycouponAlso we have extend the B2C REST API.

4.5 Add Permission via resources-acl.properties

An important requirement is to add permission for your new rest call.

Therefore create a new file for it next to the instances.component file:

resources-acl.properties
# Sub-Resource of mycoupon
POST|mycoupon{anyPath\:.*}=isAnyUser

Now any user can use our new REST API. For details, refer to Concept - REST Services Authorization.

5  Check the New REST API in Your SMC 

We have extend the B2C context. Therefore we check in the SMC if our new REST API is visible and works as designed.

  1. Log in to the SMC and choose Site Management.
    This displays a list of all sites.

  2. Click on your channel.

  3. Click Open Swagger UI.
    This opens a new tab showing Swagger UI.
  4. Choose the Promotion entry in the dropdown box. 

    Here you can find a new section Experimental:
  5. Click Try it out.

  6. Enter a test email into the email field and click Execute.


    In case of success the response looks like the following screen:

    The response code is 200. The request was successfully and we are able to create post requests and generate mycoupon codes via our new REST API.

Disclaimer

The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.

Customer Support
Knowledge Base
Product Resources
Tickets