Requirements of Service Wrappers

All base service classes must extend the ServiceBase class. There is a base wrapper class named ServiceBase that contains the getInstance method and other helper methods. The getInstance method will auto-check the CMT (Custom Metadata Type) to see if there is an override, and it will instantiate based on that. Not all service classes that are global will be overridable by default but will still use the getInstance method.

/*
 * -----------------------------------------------------------------------------
 * COPYRIGHT (C) 2018, FONTEVA, INC.
 * ALL RIGHTS RESERVED.
 *
 * ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS THE PROPERTY OF FONTEVA
 * INCORPORATED AND ITS SUPPLIERS, IF ANY. THE INTELLECTUAL AND TECHNICAL
 * CONCEPTS CONTAINED HEREIN ARE PROPRIETARY TO FONTEVA INCORPORATED AND
 * ITS SUPPLIERS AND MAY BE COVERED BY U.S. AND FOREIGN PATENTS, PATENTS IN
 * PROCESS, AND ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW. DISSEMINATION
 * OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL IS STRICTLY FORBIDDEN
 * UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED FROM FONTEVA, INC.
 * -----------------------------------------------------------------------------
 */
/**
 * Service class to execute CRUD operations on the Venue object.
 */
@RestResource(urlMapping='/TermService/*')
global inherited sharing class TermServiceCustom extends FDService.TermService {

    private static final String feature = 'Term_Service';

    /**
     * Get Instance of TermService.
     *
     * @return TermService
     */
    global static TermService getInstance() {
        return (TermService)ServiceBase.getInstanceHelper(MembershipConfiguration.MODULE_NAME,feature,TermService.class.getName());
    }


    /**
     * TermService Constructor that should not be called directly.
     */
    global TermService () {}

    
    /**
     * Get list of Term objects using the SearchRequest object as criteria
     *
     * @param sr SearchRequest
     *
     * @return List<Term>
     */
    global List<Term> get(SearchRequest sr) {
        return Term.getInstance(sr.executeQuery(OrderApi__Renewal__c.SObjectType));
    }
}
JAVA

Each wrapper class should have a private, final variable-named feature. This string variable is used to power the dependency injection overrides via CMTs.

REST API Service Layer

Each wrapper class should also be exposed as REST API endpoints so that we can have both an Apex API and REST API. The URL mapping name should be the service class name. There is a base RestUtils class that will contain helper methods, such as check for required params or get current params. This will be expanded in the future to include pull version, etc.

The response from the REST API needs to use a response wrapper class so we have a uniform JSON response. The class is RestResponse and has a method called generateResponse, which will build the JSON.

{
    "metadata": {},
    "errors": [],
    "data": [
        {
            "fieldToPackageMap": null,
            "thumbnailImageUrl": null,
            "startDate": "2018-07-11",
            "name": "New Event",
            "isMultiCurrency": true,
            "isFeatured": false,
            "id": "a1h3B000000mh9lQAA",
            "endDate": "2018-07-12",
            "displayName": "New Event",
            "description": null,
            "currencyISOCode": "USD",
            "bannerImageUrl": null
        }
    ]
}
JS