function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ignacio de la torreIgnacio de la torre 

How to save/insert Custom Object created from an Api callout?

Hello and thanks for reading :)
This is what I'm trying to achive:

I have a searchbox 
<!--Search Box -->
        <lightning:input type="search" label="Enter character ID" aura:id="characterID" onchange="{!c.APICallout}"/>

that expects a number (this would be an integer ID for a star wars character). When the user inputs this number, the searchbox (onChange) makes a call to the API and returns a valid json (star wars character), looks something like this  
{
    "name": "Luke Skywalker",
    "height": "172",
    "mass": "77",
    "hair_color": "blond",
    "skin_color": "fair",
    "eye_color": "blue",
    "birth_year": "19BBY",
    "gender": "male",
    "homeworld": "https://swapi.dev/api/planets/1/",
    "created": "2014-12-09T13:50:51.644000Z",
    "edited": "2014-12-20T21:17:56.891000Z",
    "url": "https://swapi.dev/api/people/1/"
}
that fills up the form that is beyond the searchbox (can you see both in the component ? ) with the attributes of the character returned from the API callout.

This part is working fine !! (needs fixes, but works)

Second part would be to Save the character by clicking a button in the form.
<lightning:button label="Create Star Wars Character" 
     class="slds-m-top--medium"
      variant="brand"
      onclick="{!c.clickCreate}"/>
this is not working and needs help.

------------------

This is the component
<aura:component controller="starWarsCallout">

    <aura:attribute name="characters" type="SWCharacter__c[]"/>

    <aura:attribute name="newSWCharacter" type="SWCharacter__c"
         default="{ 'sobjectType': 'SWCharacter__c',
                        'Name': '',
                        'Height__c': 0,
                        'SkinColor__c': '',
                        'Gender__c': '',
                        'Planet__c': ''}"/>

    <aura:attribute name="response" type="Map"/>

    <aura:attribute name="CharacterName" type="String"/>
    <aura:attribute name="CharacterHeight" type="Integer"/>
    <aura:attribute name="CharacterSkinColor" type="String"/>
    <aura:attribute name="CharacterPlanet" type="String"/>
    <aura:attribute name="CharacterGender" type="String"/>   

    <aura:attribute name="ListOfFilms" type="String[]"/>
    <aura:attribute name="ListOfSpecies" type="String[]"/>
    <aura:attribute name="ListOfVehicles" type="String[]"/>
    <aura:attribute name="ListOfStarships" type="String[]"/>

    <!--Header -->
    <div class="slds-m-around--medium">
        <!--Search Box -->
        <lightning:input type="search" label="Enter character ID" aura:id="characterID" onchange="{!c.APICallout}"/>

        <!--iterate the list of Films-->    
         <h3 class="slds-section-title--divider">List Of Films</h3>
        <ul class="slds-list--dotted">
            <aura:iteration items="{!v.ListOfFilms}" var="film">
                <li>{!film}</li>
            </aura:iteration>
        </ul>

        <!--iterate the list of Species-->    
        <h3 class="slds-section-title--divider">List Of Species</h3>
        <ul class="slds-list--dotted">
            <aura:iteration items="{!v.ListOfSpecies}" var="specie">
                <li>{!specie}</li>
            </aura:iteration>
        </ul>

        <!--iterate the list of Vehicles-->
        <h3 class="slds-section-title--divider">List Of Vehicles</h3>
        <ul class="slds-list--dotted">
            <aura:iteration items="{!v.ListOfVehicles}" var="vehicle">
                <li>{!vehicle}</li>
            </aura:iteration>
        </ul>

        <!--iterate the list of StarShips-->
        <h3 class="slds-section-title--divider">List Of StarShips</h3>
        <ul class="slds-list--dotted">
            <aura:iteration items="{!v.ListOfStarships}" var="starship">
                <li>{!starship}</li>
            </aura:iteration>
        </ul>
    </div>


    <!-- BOXED AREA -->
        <fieldset class="slds-box slds-theme--default slds-container--small">
        <legend id="characterform" class="slds-text-heading--small 
          slds-p-vertical--medium">
          Add Character
        </legend>
            <!-- CREATE NEW CHARACTER FORM -->
            <form class="slds-form--stacked">          
                <lightning:input type="text" aura:id="peopleform" label="Character Name"
                name="characterName"
               value="{!v.CharacterName}"
                required="true"/> 
                <lightning:input type="number" aura:id="peopleform" label="Height"
                                 name="characterHeight"
      value="{!v.CharacterHeight}"/>
      <lightning:input type="text" aura:id="peopleform" label="Gender"
                                 name="characterGender"
       value="{!v.CharacterGender}"/>
       <lightning:input type="text" aura:id="characterform" label="Planet"            name="characterPlanet"
      value="{!v.CharacterPlanet}"/>
       <lightning:input type="text" aura:id="characterform" label="Skin Color"               name="characterSkincolor"
        value="{!v.CharacterSkinColor}"/>
       <lightning:button label="Create Star Wars Character" 
     class="slds-m-top--medium"
      variant="brand"
      onclick="{!c.clickCreate}"/>
            </form>
        </fieldset>
</aura:component>

This is the c.clickCreate() function
 
clickCreate: function(component, event, helper) {
        var validSWCharacter = component.find('peopleform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validSWCharacter){

            // Create the new character
            var newSWCharacter = component.get("v.newSWCharacter");
            newSWCharacter.Name = component.get('v.CharacterName');
            newSWCharacter.Height__c = component.get('v.CharacterHeight');
            newSWCharacter.SkinColor__c = component.get('v.CharacterSkinColor');
            newSWCharacter.Planet__c = component.get('v.CharacterPlanet');
            newSWCharacter.Gender__c = component.get('v.CharacterGender');
            console.log("Create Character: " + JSON.stringify(newSWCharacter));
            helper.createSWCharacter(component, newSWCharacter);
        }
    }

this is the createSWCharacter() function
 
createSWCharacter: function(component, character) {
        var action = component.get("c.saveCharacter");
        action.setParams({
            "character": character
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                var characters = component.get("v.characters");
                characters.push(character);
                component.set("v.characters", characters);
            } else{
                console.log('errorrrr2');
            }
        });

        $A.enqueueAction(action);
    }

and finally this is the saveCharacter() method in the APEX controller:
 
@AuraEnabled
public static SWCharacter__c saveCharacter(SWCharacter__c character) {
    // Perform isUpdateable() checking first, then
    insert character;
    return character;
}

So if you read up to hear and understod the code, the problem is here in the "insert character" in the APEX controller that is not working, not saving the character to the data base BUT it is returning the valid character which is weird because it's not saving it properly first :/ 
Alain CabonAlain Cabon
You can verify if there is an error.
 
@AuraEnabled 
public static Account saveCharacter(SWCharacter__c character1) { 
   Database.DMLOptions dml = new Database.DMLOptions(); 
   dml.DuplicateRuleHeader.AllowSave = false;
   Database.SaveResult sr = Database.insert(character1,dml);
   
   if (sr.isSuccess()) {
       System.debug('Save - success');
   } else {
       // Operation failed, so get all errors                
       for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Fields that affected this error: ' + err.getFields());
        }
       // Insertion failed due to duplicate detected
       for(Database.Error duplicateError : sr.getErrors()){
          Datacloud.DuplicateResult duplicateResult = ((Database.DuplicateError)duplicateError).getDuplicateResult();
          System.debug('Duplicate records have been detected by ' + duplicateResult.getDuplicateRule());
           System.debug(duplicateResult.getErrorMessage());
       }
   }
    return character1;
}
Alain CabonAlain Cabon
character1 (not important to change it) because character is also permitted. It is not a reserved word.
createSWCharacter: function(component, character) {
        var action = component.get("c.saveCharacter");
        action.setParams({
            "character1": character
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                var characters = component.get("v.characters");
                characters.push(character);
                component.set("v.characters", characters);
            } else{
                console.log('errorrrr2');
            }
        });

        $A.enqueueAction(action);
    }

 
Ignacio de la torreIgnacio de la torre
Hello Alain! Thanks for your help!
That worked, I now can get the error "15:58:50:034 USER_DEBUG [32]|DEBUG|REQUIRED_FIELD_MISSING: Required fields are missing: [Name]" which I don't fully understand since I'm filling the character with all the needed information before saving it ... I'm actually printing it before and after to see what's going on at it all seems fine, but the error is still there. Can you see something wrong with the Name variable ?
Alain CabonAlain Cabon
You provide a value for the Name indeed but this value is probably null.

newSWCharacter.Name = component.get('v.CharacterName');

It is better to search the value of field by its aura:id

  <lightning:input type="text" aura:id="charactername1" label="Character Name"
                name="characterName"
               value="{!v.CharacterName}"  

newSWCharacter.Name = component.find('charactername1').get('v.value');

Finding Components by ID:
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_cb_find_by_id.htm
 
Ignacio de la torreIgnacio de la torre
Hi Alain! Thanks again for the help.
I did changed that to see if it worked but it's still returning the same error.
I didn't understood your solution though, since before getting the name in the clickCreate() function 
clickCreate: function(component, event, helper) {
        var validSWCharacter = component.find('peopleform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validSWCharacter){

            // Create the new character
            var newSWCharacter = component.get("v.newSWCharacter");
            newSWCharacter.Name = component.get('v.CharacterName');
            newSWCharacter.Height__c = component.get('v.CharacterHeight');
            newSWCharacter.SkinColor__c = component.get('v.CharacterSkinColor');
            newSWCharacter.Planet__c = component.get('v.CharacterPlanet');
            newSWCharacter.Gender__c = component.get('v.CharacterGender');
            console.log("Create Character: " + JSON.stringify(newSWCharacter));
            helper.createSWCharacter(component, newSWCharacter);
        }
    }

I am validating that the character is indeed a valid character, and the fields are not null or wrong.
Weird thing is that I did console.log() this line " newSWCharacter.Name = component.get('v.CharacterName');"  and it is returning the expected Name, it's not null or anything. Same happens when I return the Object in the Apex Controller after "inserting" the character, it's indeed returns a valid character with all the fields completed and no null ones, wich is weird because it is what I'm expecting it to return, but the character is not saving.
Alain CabonAlain Cabon
What is the value of  component.get('v.CharacterName')?

console.log("CharacterName :" + component.get('v.CharacterName'));

You can see this value into the console of the Chrome Dev Tools  https://developers.google.com/web/tools/chrome-devtools

Could you post this value here (please)?
Ignacio de la torreIgnacio de la torre
That debug is returning the expected character name : CharacterName :Darth Vader in this case.
I also system.debug(character1) before inserting it in the APEX Controller and it's returning a valid and expected character 
17:18:58:007 USER_DEBUG [24]|DEBUG|characterrrr---> SWCharacter__c:{Planet__c=http://swapi.dev/api/planets/1/, SkinColor__c=white, Gender__c=male, Height__c=202, Name=Darth Vader}
but right after
17:18:58:015 USER_DEBUG [32]|DEBUG|The following error has occurred.
17:18:58:037 USER_DEBUG [33]|DEBUG|REQUIRED_FIELD_MISSING: Required fields are missing: [Name]
17:18:58:037 USER_DEBUG [34]|DEBUG|Fields that affected this error: (Name)

and not inserting the character because of the Name ... which it IS there .... why is it doing this ? :/


Thanks for your valuable time Alain :D
Alain CabonAlain Cabon
 
@AuraEnabled 
public static SWCharacter__c  saveCharacter(SWCharacter__c character1) { 
     if (character1 != null ) {
         System.debug("Name: " + character1.Name);
    } else {
        System.debug("character1 is null");
   }

 
Ignacio de la torreIgnacio de la torre
Name is as expected 
17:45:53:003 USER_DEBUG [24]|DEBUG|Name: Darth Vader
but won't let me save the character !
This IS weird
 
Alain CabonAlain Cabon
The field Name is a special (default) field in almost all the objects.

Do you activate a trigger or a process when you create a record of SWCharacter__c  ?

                 var characters = component.get("v.characters");
                characters.push(character);  // that seems useless
                component.set("v.characters", characters);
 
Ignacio de la torreIgnacio de la torre
That line was indeed useless haha ... I was trying some things.
Nope, nothing triggered, it's pretty much a new org.
What do you do in this cases ? Write all over ? Keep on asking ?
Because I can't think on anything else to debug 
 
Ignacio de la torreIgnacio de la torre
I erased the second for loop inside the saveCharacter method and it now looks like this
 
@AuraEnabled 
public static SWCharacter__c saveCharacter(SWCharacter__c character) { 
    
         if (character != null ) {
         System.debug('Nameeeee: ' + character.Name);
    	} else {
        System.debug('character is null');
   		}
    
   Database.DMLOptions dml = new Database.DMLOptions(); 
   dml.DuplicateRuleHeader.AllowSave = false;
   system.debug('characterrrr---> ' + character);
   Database.SaveResult sr = Database.insert(character, dml);
   
   if (sr.isSuccess()) {
       System.debug('Save - success');
   } else {
       // Operation failed, so get all errors                
       for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Fields that affected this error: ' + err.getFields());
        }
   }
    return character;
}

it was throwing an error in the second for loop that was checking for duplicates.


That changed the output of the createSWCharacter() function
    createSWCharacter: function(component, character) {
        console.log('chracter --> ' + character)
        
        var action = component.get("c.saveCharacter");
        console.log('action ---> ' + action)
        action.setParams({
            "character": character
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                console.log('CREATED SUCCESS')
                var characters = component.get("v.characters");
                characters.push(character);
                component.set("v.characters", characters);
            } else{
                console.log('errorrrr2');
            }
        });
        
        $A.enqueueAction(action);
    }

and it's now logging 'CREATED SUCCESS" to the console but still doesn't creates the character !

On the other hand the APEX logs are 
 
20:10:07:004 VARIABLE_ASSIGNMENT [EXTERNAL]|this|{"DuplicateRuleHeader":"0x6da8653c"}|0x43b22714
20:10:07:004 USER_DEBUG [31]|DEBUG|characterrrr---> SWCharacter__c:{Planet__c=http://swapi.dev/api/planets/2/, SkinColor__c=light, Gender__c=female, Height__c=150, Name=Leia Organa}
20:10:07:010 VARIABLE_SCOPE_BEGIN [32]|sr|Database.SaveResult|true|false
20:10:07:010 VARIABLE_ASSIGNMENT [32]|sr|{"success":false,"errors":[{"status":"REQUIRED_FIELD_MISSI (2 more) ...","message":"Required fields are  (15 more) ..."}]}|0x53815baa
20:10:07:011 VARIABLE_ASSIGNMENT [38]|err|"Error [statusCode=REQUIRED_FIELD_MISSING, code=[xmlrpc=1204, statusCode=REQUIRED_FIELD_MISSING, exceptionCode=null, scope=PublicApi, http=400], message=Required fields are missing: [Name], fields=[Name]]"|0x5e154793
20:10:07:029 USER_DEBUG [40]|DEBUG|REQUIRED_FIELD_MISSING: Required fields are missing: [Name]



 
Ignacio de la torreIgnacio de la torre
I fixed it @Alain Cabon !
Thank you sooooo much for your time.
Goku ZeusGoku Zeus
We explore the value of the entire globe and calculate how much the Earth is worth.
https://www.theamericanbulletin.com/if-the-earth-can-buy-how-much-does-the-earth-cost/