7

We are building a product that will make use of multiple Lightning Web Components (LWCs), and some of those will make use of @AuraEnabled Apex methods. We also plan to provide an API that non-LWC UI can access. (In the past, we have provided such APIs by using @RestResource Apex classes receiving and sending JSON.)

Our present idea is to go ahead and build the @AuraEnabled Apex code methods/classes first, and then later wrap them in a single @RestResource Apex class that dispatches the requests according to the URL pattern to the relevant @AuraEnabled methods/classes. (I assume in this case the @AuraEnabled(cacheable=true) annotation will be ignored.)

Has anyone done this? Pros/cons?

7
  • 3
    From a separation of concerns perspective it is better to provide the business logic in one class and to provide appropriate (at)AuraEnabled and (at)RestResource facades in two separate classes that leverage the business logic class.
    – Phil W
    Commented Feb 4, 2020 at 15:50
  • Yep @PhilW, Yeah fair point. Perhaps the separation should be at the method level e.g. the @AuraEnabled method calls a plain method (also called by the @RestResource code), but then that is close to what I am already proposing. The only extra concern for the @AuraEnabled case is the @AuraEnabled annotation...
    – Keith C
    Commented Feb 4, 2020 at 16:16
  • 2
    Well, it rather depends on whether the business logic is 1:1 with any one of the methods exposed to the "APIs". I said "facade" because these frequently provide a way to view and interact with the business logic and related data is subtly different ways. One of the benefits of such an approach is allowing you to refactor the behind-the-scenes code without impacting any of your APIs (you can also think of these as the traditional layers in an application - front end<->API<->business logic<->persistence). The API layer might also encapsulate more of the security concerns too.
    – Phil W
    Commented Feb 4, 2020 at 16:45
  • Hi @PhilW, thanks for your attention here! If a layer does something significant then +1; I'm allergic to thin layers that just cause method interfaces to be duplicated e.g. the ugly controller/helper setup in Aura.
    – Keith C
    Commented Feb 4, 2020 at 16:49
  • 2
    @PhilW, In this case, I don't think we would want separate access rights for the two access mechanisms, but you are right that security needs to be factored into the approach (as always).
    – Keith C
    Commented Feb 4, 2020 at 17:57

1 Answer 1

3

Initial coding of the KISS solution:

global class Aura {

    // Call this from the REST API
    public static Object execute(String operation, String requestJson) {
        switch on operation {
            when 'op1' {
                return op1((Op1Params) JSON.deserialize(requestJson, Op1Params.class));
            }
            when 'op2' {
                return op2((Op2Params) JSON.deserialize(requestJson, Op2Params.class));
            }
            ...
        }
    }

    // Method used by LWC
    @AuraEnabled
    global static Result__c op1(Op1Params params) {
        ...
    }

    // Method used by LWC
    @AuraEnabled
    global static Result__c op2(Op2Params params) {
        ...
    }

    ...
}

and:

@RestResource(urlMapping = '/xyz/...')
global inherited sharing class Rest {

    ....

    @HttpPost
    global static void doPost() {

        Savepoint sp = Database.setSavepoint();
        try {
            dispatch(RestContext.request, RestContext.response);
        } catch (AuraHandledException e) {
            res.responseBody = Blob.valueOf(e.getMessage());
            res.statusCode = BAD_REQUEST;
            Database.rollback(sp);
        } catch (Exception e) {
            res.responseBody = Blob.valueOf(sanitizedMessage(e));
            res.statusCode = INTERNAL_SERVER_ERROR;
            Database.rollback(sp);
        }
    }

    private static void dispatch(RestRequest req, RestResponse res) {

        String[] parts = req.requestURI.split('\\/');
        String operation = parts.size() > 1 ? parts[1] : null;
        String requestJson = req.requestBody.toString();

        Object result = Aura.execute(operation, requestJson);

        res.responseBody = toJsonBlob(result);
        res.statusCode = OK;
    }
}
3
  • It is the first time I see functions like Aura.execute and toJsonBlob, where can I find them? Commented Apr 20, 2021 at 19:23
  • Hi @GabrielSerranoSalas, Those are just locally created small methods.
    – Keith C
    Commented Apr 20, 2021 at 20:35
  • Aura.execute as well? I have seen Aura.redirect in the past, although never documented anywhere. Just though Aura.execute could be similar Commented Apr 20, 2021 at 20:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .