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
Michael McCormickMichael McCormick 

Apex Web Services Challenge - unclear on return format

The instructions state:

"The method must return the ID and Name for the requested record and all associated contacts with their ID and Name."

I am returning a List<sObject> where the first object is the Account and the remaining objects are the Contacts.

The error message is:

"Executing the 'AccountManager' method failed. Either the service isn't configured with the correct urlMapping, is not global, does not have the proper method name or does not return the requested account and all of its contacts."

I assume it is looking for a different structure to be returned by getAccount() besides List<sObject> but since Account doesn't have a field to store associated Contacts, I'm not sure what to return.

Anyone able to clarify for me what type & structure the return value should have?
Best Answer chosen by Michael McCormick
James LoghryJames Loghry
It should return an Account (singular), but when you query the account, you'll use a relationship query to return the related children contact records.

All Answers

James LoghryJames Loghry
It should return an Account (singular), but when you query the account, you'll use a relationship query to return the related children contact records.
This was selected as the best answer
Michael McCormickMichael McCormick
I was doing this query to get the Contacts, and pulled the Account out of the Contact.
 
[SELECT Id, Name, Account.Id, Account.Name 
                                FROM Contact 
                                WHERE Account.Id = :accountId];

Based on your reply, I see I need a relationship query on Account instead, and now it works. Thanks!
Ajay Ghuge 6Ajay Ghuge 6
Hi ,

This worked for me !!!

@RestResource(urlMapping='/Accounts/*')

global with sharing class AccountManager
{
    @HttpGet
    global static Account getAccount() 
    {
        RestRequest request = RestContext.request;
        List<String> lst = request.requestURI.split('/');                
        String strAccId = lst[lst.size() - 2];
        ResponseWrapper objResp = new ResponseWrapper();
        Account obj = [select Id,Name ,(select Id,Name from Contacts) from Account where Id=:strAccId limit 1];
        return obj ;
    }
}

Regards,
Ajay 
Naveen ChoudharyNaveen Choudhary
What should be the test class for the same as I am getting error whle running the test
Ajay Ghuge 6Ajay Ghuge 6
@IsTest
private class AccountManagerTest{

    @isTest static void testAccountManager() {
        Id recordId = createTestRecord();
        
        Contact objCont = new Contact();
        objCont.LastName = 'Test1';
        objCont.AccountId = recordId ;
        insert objCont ;
        
        Contact objCont2 = new Contact();
        objCont2 .LastName = 'Test2';
        objCont2 .AccountId = recordId ;
        insert objCont2 ;
        
        // Set up a test request
        RestRequest request = new RestRequest();
        request.requestUri =
            'https://na1.salesforce.com/services/apexrest/Accounts/'+recordId+'/contacts';
        request.httpMethod = 'GET';
        RestContext.request = request;
        // Call the method to test
       Account lst = AccountManager.getAccount();
      //Add assert to check the list of size
    }

    // Helper method
    static Id createTestRecord() {
        // Create test record
        Account accTest = new Account(Name='Test Record');
        insert accTest ;
        return accTest.Id;
    }          

}
Bill KratochvilBill Kratochvil
Ajay's AccountManagerTest class worked for me, however I am curious as to why my unit test failed with an error indicating no records returned (System.QueryException: List has no rows for assignment to SObject).  The only difference is I used an "existing" record ID which works when I perform a GET using the same request.requestUri (reference code below) within the Workbench.  

Does the test environment have access to existing records?  The following excerpt from "Getting Started with Apex Unit Tests" is ambiguous - does a "copy" mean a copy of the data or a copy of the org's metadata so it has knowlege of the schema, meaning we always have to create our data within the test?   If so, what is the scope of the data, i.e., only limited to a unit test or to a class?

"Maintaining the security of your data is our highest priority. We don't view or modify any data in your org, and all testing is done in a copy that runs in a secure data center."
@IsTest
private class AccountManagerTest {
    
    @isTest static void testGetCaseById() {
        // Set up a test request
        RestRequest request = new RestRequest();
        
        // The following url works from workbench / Unit test fails
        request.requestUri = '/services/apexrest/Accounts/0015000001BlqjsAAB/contacts';
        request.httpMethod = 'GET';
        RestContext.request = request;
        
        // Call the method to test
        Account thisAccount = AccountManager.getAccount();
        System.assert(thisAccount != null);
    }
}

For reference I use the following method to retrieve data:
@RestResource(urlMapping='/Accounts/*/contacts')
global with sharing class AccountManager {

    @HttpGet
    global static Account getAccount() {
        RestRequest request = RestContext.request;

        // Grab the caseId from the wildcard
		String caseId = request.requestURI.substringBetween('Accounts/','/contacts');        

        System.debug('Using caseId = '+caseId);

        // Return results
        Account result= [SELECT Id, Name, (Select Id, Name From Contacts) 
                        FROM Account
                        WHERE Id = :caseId];
        return result;
    }
}

 
David GranadosDavid Granados
Hello,

I keep getting the following error message eventhough I do "Run All", please help :)

Challenge not yet complete... here's what's wrong:
The 'AccountManager' class did not achieve 100% code coverage via your test methods. Make sure that you chose 'Run All' tests in the Developer Console at least once before attempting to verify this challenge.
suresh bashettysuresh bashetty
Hi David,
Seems your 'AccountManager' class didn't covered 100% of code coverage. We have to click on 'Run Test' button in that 'AccountManagerTest' class and check whether you covered the class 100% or not.
Feisal IbrahimFeisal Ibrahim
@David use the @Ajay Ghuge test for test only. that worked for me. 
Ranjit shindhe 7Ranjit shindhe 7
Below is my code when i test it in workbench. it is working but trail head challenge is in error, Any help is greatly appreciated:
Executing the 'AccountManager' method failed. Either the service isn't configured with the correct urlMapping, is not global, does not have the proper method name or does not return the requested account and all of its contacts.
==========================

@RestResource(urlMapping='/Accounts/*/contacts')
global with sharing class AccountManager {
    @HttpGet
    global static Account getAccount() {
        RestRequest request = RestContext.request;        
        String accountId = request.requestURI.substringBetween('/Accounts/','/contacts');
        Account result =  [SELECT Id, Name, (SELECT Id, Name from contacts) from Account where Id=:accountId];
                               return result;
    }
}
============================
@IsTest
private class AccountManagerTest {
    @isTest static void testGetContactsByAccountId() {
        Id recordId = createTestRecord();
        // Set up a test request
        RestRequest request = new RestRequest();
        request.requestUri =
            'https://yourInstance.salesforce.com/services/apexrest/Accounts/'+recordId+'/contacts';
        request.httpMethod = 'GET';
        RestContext.request = request;
        // Call the method to test
        Account thisAccount = AccountManager.getAccount();
        // Verify results
        System.assert(thisAccount != null);
        System.assertEquals('Test record', thisAccount.Name);
    }    
    // Helper method
    static Id createTestRecord() {
        // Create test record
        Account accountTest = new Account(
            Name='Test record');
            insert accountTest;
        Contact contactTest = new Contact(
        FirstName = 'John',
        LastName = 'Doe',
        AccountId = accountTest.Id);
        insert contactTest;
        return accountTest.Id;
    }          
}
======================================
Christophe Cano 3Christophe Cano 3
I had the same problem few minutes ago. I created a brand new Playground, copy/paste the code and went OK.
I spent more than one hour checking everything. I hope you have the same problem.
Lukesh KarmoreLukesh Karmore
hey ranjit my issue is same getting errror with same code ,  if u solved it then help me here
thank you
 
Kimberley DavisKimberley Davis

Mine was apparently failing because I used a capital C for "Contacts" in my urlMapping, like this:

@RestResource(urlMapping='/Accounts/*/Contacts')

The code worked (I don't remember what all is case-sensitive, but I was consistent across code and test class with "C") and the test worked and I had 100% test coverage but I was still failing. When I changed all my "Contacts" to "contacts" I passed the challenge. :/

 
SAYAN GUINSAYAN GUIN
I am getting this error  "Executing the 'AccountManager' method failed. Either the service isn't configured with the correct urlMapping, is not global, does not have the proper method name or does not return the requested account and all of its contacts", pls anyone tell how to solve this.
Ishan Gupta 9Ishan Gupta 9
Same error I'm getting as Sayan Guin. Below is my code. Please help.
 
@RestResource(urlMapping='/Accounts/*/contacts')
global with sharing class AccountManager {
    @HttpGet
    global static Account getAccount() {
        RestRequest request = RestContext.request;
        String aId = request.requestURI.substringBetween('/Accounts/', '/contacts');
        Account accObj = [SELECT ID, Name, (SELECT Id, Name from Contacts) FROM Account WHERE id =: aId LIMIT 1];
        return accObj;
    }
}
 
@isTest
private class AccountManagerTest
{
    @isTest static void testGetAccount ()
    {
        Id recordId = createTestRecord ();
        RestRequest request = new RestRequest ();
        request.requestUri = 'https://yourInstance.salesforce.com/services/apexrest/Accounts/' + recordId + '/contacts';
        request.httpMethod = 'GET';
        RestContext.request = request;
        Account thisAccount = AccountManager.getAccount();
        System.assert (thisAccount != null);
        System.assertEquals ('Test Record', thisAccount.Name);

    }

    static Id createTestRecord ()
    {
        Account testAccount = new Account (Name = 'Test Record');
        insert testAccount;
        Contact testContact = new Contact (AccountId = testAccount.Id);
        return testAccount.Id;
    }

}

 
Ben Johnson 65Ben Johnson 65
@Ishan - This may not work for others, but it solved my problem. In the getAccount() function.

change this line:
String aId = request.requestURI.substringBetween('/Accounts/', '/contacts');

To this:
String aId = request.requestURI.substringBetween('/Accounts/', '/');

My trailhead playground has the URI as '.../Accounts/<id>/Contacts', whereas the verification test for the challenge has it as '.../Accounts/<id>/contacts'. So if you pass the test, you get an error on the challenge, whereas if your code could pass the challenge, it will fail the unit test (and thus the challenge too). Just using the forward slash to find the substring eliminates the issue.
yogesh watileyogesh watile

You can also try below codes to pass the challenge. it works for me.

AccountManager.apxc
@RestResource(urlMapping='/Accounts/*/contacts')
Global with sharing class AccountManager {
    @HttpGet
    global static Account getAccount(){
        RestRequest request = RestContext.request;
        //Grab the accountId from end of URL
        String accountId = request.requestURI.substringBetween('Accounts/','/contacts');
        Account acc = [select Id,Name,(select Id,Name from Contacts) from Account where Id = :accountId];
        system.debug('Account and Related Contacts->>>>'+acc);
        return acc;
    }
}

AccountManagerTest.apxc
@isTest
private class AccountManagerTest {
    //Helper method to create dummy record
    static Id createTestRecord(){
        //Create test record
        Account TestAcc = new Account(Name='Test Account', Phone='8786757657');
        insert TestAcc;
        List<Contact> conList = new List<Contact>();
        Contact TestCon = new Contact();
        for(Integer i=1;i<=3;i++){
            TestCon.LastName = 'Test Contact'+i;
            TestCon.AccountId = TestAcc.Id;
            //conList.add(TestCon);
            insert conList;//Its not best practice but I have use it for testing purposes
        }
        //insert conList;
        //insert TestAcc;
        return TestAcc.Id;
    } 
    
    //Method to test getAccount()
    @isTest static void getAccountTest(){
        Id recordId = createTestRecord();
        //setup a test request
        RestRequest request = new RestRequest();
        //set request properties
        request.requestURI = 'https://yourInstance.salesforce.com/services/apexrest/Accounts/' + recordId +'/contacts';
        request.httpMethod = 'GET';
        // Finally, assign the request to RestContext if used
        RestContext.request = request;
        //End test setup
        
        //Call the method
        Account thisAcc = AccountManager.getAccount();
        //Verify the result
        system.assert(thisAcc != null);
        system.assertEquals('Test Account', thisAcc.Name);
        //system.assertEquals(3, thisAcc.Contact__c.size()); how to get this
    }
}