Skip to content

Conversation

@github-classroom
Copy link

@github-classroom github-classroom bot commented Oct 22, 2025

👋! GitHub Classroom created this pull request as a place for your teacher to leave feedback on your work. It will update automatically. Don’t close or merge this pull request, unless you’re instructed to do so by your teacher.
In this pull request, your teacher can leave comments and feedback on your code. Click the Subscribe button to be notified if that happens.
Click the Files changed or Commits tab to see all of the changes pushed to the default branch since the assignment started. Your teacher can see this too.

Notes for teachers

Use this PR to leave feedback. Here are some tips:

  • Click the Files changed tab to see all of the changes pushed to the default branch since the assignment started. To leave comments on specific lines of code, put your cursor over a line of code and click the blue + (plus sign). To learn more about comments, read “Commenting on a pull request”.
  • Click the Commits tab to see the commits pushed to the default branch. Click a commit to see specific changes.
  • If you turned on autograding, then click the Checks tab to see the results.
  • This page is an overview. It shows commits, line comments, and general comments. You can leave a general comment below.
    For more information about this pull request, read “Leaving assignment feedback in GitHub”.

Subscribed: @Adam-Atoms

postCreateDummyJSONUser(i);
}
}

Check warning

Code scanning / regex

Found trailing whitespace at the end of a line of code. Warning

Found trailing whitespace at the end of a line of code.
};
// Serialize the map into a JSON string.
String contJson = JSON.serialize(contMap);

Check warning

Code scanning / regex

Found trailing whitespace at the end of a line of code. Warning

Found trailing whitespace at the end of a line of code.
Comment on lines +1 to +30
public with sharing class ContactTriggerHelper {

public static void checkIds(List<Contact> contacts) {
List<String> dummyJsonIds = new List<String>();
for (Contact cont : contacts) {
if (cont.DummyJSON_Id__c == null) {
cont.DummyJSON_Id__c = String.valueOf(Integer.valueOf((math.random() * 100)));
}
if (Integer.valueOf(cont.DummyJSON_Id__c) <= 100) {
dummyJsonIds.add(cont.DummyJSON_Id__c);
}
}
if (!dummyJsonIds.isEmpty()) {
DummyJSONCallout.getDummyJSONAsync(dummyJsonIds);
}
}


public static void syncUpdate(List<Contact> contacts ) {
List<Id> contactIds = new List<Id>();
for (Contact cont : contacts) {
if (Integer.valueOf(cont.DummyJSON_Id__c) > 100) {
contactIds.add(cont.Id);
}
}
if(!contactIds.isEmpty()) {
DummyJSONCallout.postDummyJsonAsync(contactIds);
}
}
} No newline at end of file

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning

Missing ApexDoc comment
Comment on lines +3 to +16
public static void checkIds(List<Contact> contacts) {
List<String> dummyJsonIds = new List<String>();
for (Contact cont : contacts) {
if (cont.DummyJSON_Id__c == null) {
cont.DummyJSON_Id__c = String.valueOf(Integer.valueOf((math.random() * 100)));
}
if (Integer.valueOf(cont.DummyJSON_Id__c) <= 100) {
dummyJsonIds.add(cont.DummyJSON_Id__c);
}
}
if (!dummyJsonIds.isEmpty()) {
DummyJSONCallout.getDummyJSONAsync(dummyJsonIds);
}
}

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning

Missing ApexDoc comment
Comment on lines +19 to +29
public static void syncUpdate(List<Contact> contacts ) {
List<Id> contactIds = new List<Id>();
for (Contact cont : contacts) {
if (Integer.valueOf(cont.DummyJSON_Id__c) > 100) {
contactIds.add(cont.Id);
}
}
if(!contactIds.isEmpty()) {
DummyJSONCallout.postDummyJsonAsync(contactIds);
}
}

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning

Missing ApexDoc comment
Comment on lines +38 to +42
public static void getDummyJSONAsync(List<String> JsonIds) {
for (String j : JsonIds) {
getDummyJSONUserFromId(j);
}
}

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning

Missing ApexDoc comment
// Set the HTTP method to POST.
postUserRequest.setMethod('POST');
// Set the body using generateDummyJsonUserPayload method.
String contJsonBody = DummyJSONCallout.generateDummyJsonUserPayload(contactId);

Check warning

Code scanning / PMD

Variable 'contJsonBody' defined but not used Warning

Variable 'contJsonBody' defined but not used
Contact contToUpdate = new Contact();
contToUpdate.Id = contactId;
contToUpdate.DummyJSON_Last_Updated__c = Datetime.now();
update contToUpdate;

Check failure

Code scanning / PMD

Validate CRUD permission before SOQL/DML operation or enforce user mode Error

Validate CRUD permission before SOQL/DML operation or enforce user mode
update contToUpdate;
}
} catch (Exception e) {
System.debug('Erron on POST to DummyJSON ::: ' + e.getMessage());

Check warning

Code scanning / PMD

Avoid debug statements since they impact on performance Warning

Avoid debug statements since they impact on performance
update contToUpdate;
}
} catch (Exception e) {
System.debug('Erron on POST to DummyJSON ::: ' + e.getMessage());

Check warning

Code scanning / PMD

Calls to System.debug should specify a logging level. Warning

Calls to System.debug should specify a logging level.
private static String generateDummyJsonUserPayload(String contactId) {
// Query the contact to get the field values to generate the JSON payload.

List<Contact> contList = [SELECT Id, FirstName, LastName, Email, Phone FROM Contact WHERE Id = :contactId];

Check failure

Code scanning / PMD

Validate CRUD permission before SOQL/DML operation or enforce user mode Error

Validate CRUD permission before SOQL/DML operation or enforce user mode
Copy link

@walters954 walters954 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Adam! 👋

I can see you've put in significant effort on this integrations module - great job on creating a trigger handler class and implementing the HTTP callout patterns! However, there are some critical issues that will prevent your code from working in production that need to be addressed.

What You Did Well ✅

  • Excellent separation of concerns by creating the ContactTriggerHelper class
  • Good error handling with try-catch blocks
  • Proper null checking throughout your code
  • Using Named Credentials - great security practice!
  • Clean JSON serialization/deserialization logic

Critical Issues That Must Be Fixed 🚨

I've left detailed inline comments, but the main issue is that callouts from triggers require @future annotation. Without this, your code will fail with "Callout from triggers are currently not supported" errors when it runs.

Your Next Steps 🎯

  1. Add @future(callout=true) to your callout methods
  2. Fix the missing setBody() call in your POST request
  3. Add the Content-Type header for your POST request
  4. Consider bulkification - your current async wrappers will hit governor limits with multiple records

Once you address these issues, your integration will be solid! Feel free to reach out if you have questions about the @future annotation or bulkification patterns.

Keep coding! 💪

getDummyJSONUserFromId(j);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Critical Issue: This method needs the @future(callout=true) annotation!

Callouts from triggers are not allowed in Salesforce. When your trigger calls this method, it will fail with:

Callout from triggers are currently not supported

Fix:

@future(callout=true)
public static void getDummyJSONUserFromId(String dummyUserId) {
    // ... rest of your code
}

Note: When using @future, all parameters must be primitives (String, Integer, Id, etc.) - no complex objects like Lists of Contacts.

upsert cont DummyJSON_Id__c; //insert/update from the JSON response using the external id (dummyUserId)
try {
HttpRequest userRequest = new HttpRequest();
// Set the endpoint URL. Use direct URL or for best practices use Named Credential.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint URL is missing the user ID! The DummyJSON API expects the ID in the URL path.

It should be:

userRequest.setEndpoint('callout:DummyJsonUser/' + dummyUserId);

This way you're calling /users/{id} to get a specific user.

}
}
if (!dummyJsonIds.isEmpty()) {
DummyJSONCallout.getDummyJSONAsync(dummyJsonIds);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Governor Limit Issue: This approach will fail with bulk operations!

Your getDummyJSONAsync method loops and calls getDummyJSONUserFromId for each ID. Since that method will need @future, you can't call it multiple times in a loop (max 50 @future calls per transaction).

Better approach:

public static void checkIds(List<Contact> contacts) {
    List<String> dummyJsonIds = new List<String>();
    for (Contact cont : contacts) {
        if (cont.DummyJSON_Id__c == null) {
            cont.DummyJSON_Id__c = String.valueOf(Integer.valueOf((math.random() * 100)));
        }
        if (Integer.valueOf(cont.DummyJSON_Id__c) <= 100) {
            dummyJsonIds.add(cont.DummyJSON_Id__c);
        }
    }
    if (!dummyJsonIds.isEmpty()) {
        // Pass the whole list to a SINGLE @future method
        getDummyJSONUsersAsync(JSON.serialize(dummyJsonIds));
    }
}

@future(callout=true)
public static void getDummyJSONUsersAsync(String jsonIds) {
    List<String> ids = (List<String>)JSON.deserialize(jsonIds, List<String>.class);
    // Make one callout for each ID here
}

This keeps you within governor limits!

}
}

public static void postCreateDummyJSONUser(String contactId) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Critical Issue: Same problem here - this method needs @future(callout=true)!

@future(callout=true)
public static void postCreateDummyJSONUser(String contactId) {
    // ... rest of your code
}

try {
// Create HTTP request to send.
HttpRequest postUserRequest = new HttpRequest();
// Set the endpoint URL. Use direct URL or for best practices use Named Credential.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing required calls: Your POST request is incomplete! You're generating the JSON payload but never setting it as the request body, and you're missing the Content-Type header.

Add these lines:

postUserRequest.setHeader('Content-Type', 'application/json');
postUserRequest.setBody(contJsonBody);

Without setBody(), you're sending an empty POST request!

cont.Email = (String)responseMap.get('email');
cont.Phone = (String)responseMap.get('phone');
cont.Birthdate = Date.valueOf((String)responseMap.get('birthDate'));
// Deserialize the address from the JSON response.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice null checking here! 👍

One small improvement - you could use isEmpty() for the email check too:

cont.Email = String.isBlank(cont.Email) ? 'unknown' : cont.Email

isBlank() checks for both null and empty strings, which is more defensive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants