I'm having a slightly irritating error when trying to add some of my code to a managed package. I'm sure there's something silly that I'm doing.
I have a LWC which calls two separate apex methods - one that just takes a basic parameter (a string) and one that takes a class as a parameter containing properties, arrays etc. A wrapper class essentially.
Both of these methods work absolutely fine in my dev org - the request hits the apex, apex calls out to an API, database updated, LWC redirects to the new record.
I've added this code to a managed package and installed it in a couple of different orgs. The method which just takes a single param works fine, the one that accepts a class as a parameter is bombing out, with this beautiful error message:
{"status":500,"body":{"message":"An internal server error has occurred\nError ID: 316185011-592324 (-524102090)"},"headers":{}}
I've spent quite a bit of time debugging the request in both the dev org and the package, and I believe that everything is fine code wise - the request object is populating with all of the relevant fields and to be honest, the request isn't rocket science so I believe it's something to do with the wiring between the LWC and the apex class. Again, the other method which just takes a single parameter (and is also in the same apex class) works fine including in the package.
So, here's my JS controller code:
handleCreateContact() {
// Show spinner
this.loaded = false;
const evt = new ShowToastEvent({
title: 'Create Contact',
message: 'Sending Request',
variant: 'info',
});
this.dispatchEvent(evt);
console.log('Account ID: ' + this.accountId);
console.log('Contact name: ' + this.contactName);
let apexRequest = {
"AccountId" : this.accountId,
"ContactName" : this.contactName ,
"PostalStreet" : this.contactPostalStreet,
"PostalCity" : this.contactPostalCity,
"PostalState" : this.contactPostalState,
"PostalCode" : this.contactPostalCode,
"PostalCountry" : this.contactPostalCountry
}
console.log('*** create contact request: ' + JSON.stringify(apexRequest));
CreateContacts({ request: apexRequest })
.then(result => {
const evt = new ShowToastEvent({
title: 'Create Contact',
message: 'Contact Created',
variant: 'success',
});
this.dispatchEvent(evt);
console.log('Contact ID: ' + result.SalesforceContactID);
console.log('Result: ' + JSON.stringify(result));
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: result.SalesforceContactID,
actionName: 'view'
},
});
})
.catch(error => {
// Didn't work
console.log('**ERRROR: ' + JSON.stringify(error));
let errorMessage = '';
if (error.status != undefined) {
errorMessage = errorMessage + error.status + ': ';
}
if (error.body.message) {
errorMessage = errorMessage + ' - ' + error.body.message;
}
else if (error.body.pageErrors) {
errorMessage = errorMessage + error.body.pageErrors[0].statusCode + ' - ' + error.body.pageErrors[0].message;
}
const evt = new ShowToastEvent({
title: 'Refresh Contacts Failed',
message: errorMessage,
variant: 'error',
});
this.dispatchEvent(evt);
})
.finally(() => {
this.loaded = true;
});
}
My apex method (class is set to public)
@auraEnabled(cacheable=false)
public static CreateContactResponse CreateContactAura(CreateContactRequest request)
{
return new xContacts().CreatexContact(request);
}
And finally the wrapper classes:
public class CreateContactRequest
{
@AuraEnabled
public Id AccountId { get; set; }
@AuraEnabled
public String ContactName { get; set; }
@AuraEnabled
public String PostalStreet { get; set; }
@AuraEnabled
public String PostalCity { get; set; }
@AuraEnabled
public String PostalState { get; set; }
@AuraEnabled
public String PostalCode { get; set; }
@AuraEnabled
public String PostalCountry { get; set; }
}
public class CreateContactResponse
{
@AuraEnabled
public String xID { get; set; }
@AuraEnabled
public ID SalesforceContactID { get; set; }
}
Given that this is only happening when the code is packaged I suspect it's something around namespacing/security/class access but thought I'd post here first to see if anyone can save me some time redeploying the package 30 times for debugging the issue!
I was wondering whether perhaps the wrapper classes and properties just need to be set to global, but I'm sure I'm missing something stupid here...
Edit: Just to add a bit more info after some investigation...
If I have a method that returns a wrapper class as above, but takes a single input parameter such as an Id then that works in both the dev org and managed package.
I've modified the apex class (different class, easier for testing) from this:
public static GetInvoiceFromDatabaseResponse GetInvoiceFromDatabaseAura(Id SfId)
to this:
public static GetInvoiceFromDatabaseResponse GetInvoiceFromDatabaseAura(testWrapperClass invoiceRequest)
with this wrapper class...
public class testWrapperClass
{
@auraEnabled
public String sfId { get; set; }
}
And that is working in my developer org, but failing in the managed package. So apparently, the issue is specific to using a wrapper class for the input parameter of an apex method, but it's absolutely fine to return a wrapper class.