-
Salesforce Rest API Issue. Metadata/DeployRequest
Salesforce Rest API Issue
Metadata/DeployRequest
May 02, 2022
<hr>
I am facing issue when deploying trigger with salesforce rest api
https://host/services/data/vXX.0/metadata/deployRequest
I am calling the rest api from Apex class. We are creating triggers dynamically and want to deploy it to org with test class. For that we created a folder and kept “classes” and “triggers” folder under that. Then kept package.xml in it. Now creating zip files using Zippex.
Now calling the rest api to deploy trigger. My methods are as below:-
This method is getting code for trigger, test class, package.xml and then zipping it.
public static String triggerDeployment(String triggerName, String apexTriggerCode, String testClassName, String testClassCode){
String triggerMetadata = getTriggerCodeMetadata();
String triggercode = apexTriggerCode;//getTriggerCode();
String triggerTestClassMetadata = getTriggerTestCodeMetadata();
String triggerTestClassCode = testClassCode;//getTriggerTestCode()
String packageString = getPackageXML(triggerName,testClassName);
Zippex sampleZip = new Zippex();
Blob triggerMetadataBlob = Blob.valueOf(triggerMetadata);
sampleZip.addFile('triggers/' + triggerName+'.trigger-meta.xml', triggerMetadataBlob, null);
Blob triggercodeBlob = Blob.valueOf(triggercode);
sampleZip.addFile('triggers/' + triggerName+'.trigger', triggercodeBlob, null);
Blob triggerTestClassMetadataBlob = Blob.valueOf(triggerTestClassMetadata);
sampleZip.addFile('classes/' + testClassName+'.cls-meta.xml', triggerTestClassMetadataBlob, null);
Blob triggerTestClassCodeBlob = Blob.valueOf(triggerTestClassCode);
sampleZip.addFile('classes/' +testClassName+'.cls', triggerTestClassCodeBlob, null);
Blob packageStringBlob = Blob.valueOf(packageString);
sampleZip.addFile('package.xml', packageStringBlob, null);
System.debug('sampleZip --->>>' + sampleZip);
Blob zipData = sampleZip.getZipArchive();
String zipEncoded = EncodingUtil.base64Encode(zipData);
String res = deployZipByRest(zipEncoded, testClassName);
return res;
}
The method named “deployZipByRest” is called from this method.
In this method I have written code to deploy a class using rest api.
public static String deployZipByRest(String bodyEncoded, String testClassName){
String crlf = '\n';
String boundary = '--------------------------BOUNDARY';
String endPoint = System.URL.getOrgDomainUrl().toExternalForm() + '/services/data/v48.0/metadata/deployRequest';
System.debug('endPoint ==>:'+ endPoint);
Map<String, Boolean> deployOptions = new Map<String, Boolean>();
deployOptions.put('rollbackOnError', false);
deployOptions.put('singlePackage', true);
String deploymentOptions = '{"deployOptions" :{"allowMissingFiles" : false,"autoUpdatePackage" : false,"checkOnly" : false,"ignoreWarnings" : false, "performRetrieve" : false,"purgeOnDelete" : false,"rollbackOnError" : false,"runTests" : ["'+ testClassName +'"], "singlePackage" : false,"testLevel" : "RunSpecifiedTests"}}';
Blob bodyPayLoad = getBinaryPostBody(crlf, boundary, deploymentOptions, bodyEncoded);
if(bodyPayLoad.size()>3000000){
return '';
}
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setHeader('Authorization','Bearer '+ UserInfo.getSessionID());
req.setMethod('POST');
req.setHeader('Content-Type', 'multipart/form-data; boundary='+boundary);
req.setBodyAsBlob(bodyPayLoad);
req.setTimeout(120000);
System.debug('body blob size ==>:'+ req.getBodyAsBlob().size());
req.setHeader('Content-Length', String.valueof(req.getBodyAsBlob().size()));
Http http = new Http();
HttpResponse res = http.send(req);
System.debug('status code ==>:'+ res.getStatusCode());
System.debug('response body ==>:'+ res.getBody());
String response = res.getBody();
return response;
}
public static Blob getBinaryPostBody(String crlf, String boundary, String deploymentOptions, String bodyEncoded) {
String header = '--' + boundary + crlf
+ 'Content-Disposition: form-data; name="json"' + crlf
+ 'Content-Type: application/json;' + crlf + crlf
+ deploymentOptions + crlf
+'--' + boundary + crlf
+ 'Content-Disposition: form-data; name="file";filename="deploy.zip"' + crlf
+ 'Content-Type: application/zip;' + crlf + crlf;
String footer = + crlf + '--' + boundary + '--';
String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header));
while(headerEncoded.endsWith('=')){
header += ' ';
headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header));
}
System.debug('bodyEncoded==>'+bodyEncoded);
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
Blob bodyBlob = null;
//last encoded body bytes
String last4Bytes = bodyEncoded.substring(bodyEncoded.length() - 4, bodyEncoded.length());
//if the last 4 bytes encoded base64 ends with the padding character (= or ==) then re-encode those bytes with the footer
//to ensure the padding is added only at the end of the body
if(last4Bytes.endsWith('=')){
System.debug('last4Bytes==>'+last4Bytes);
Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
HttpRequest tmp = new HttpRequest();
tmp.setBodyAsBlob(decoded4Bytes);
String last4BytesFooter = tmp.getBody() + footer;
bodyBlob = EncodingUtil.base64Decode(headerEncoded + bodyEncoded.substring(0, bodyEncoded.length() - 4) + EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
}
else{
bodyBlob = EncodingUtil.base64Decode(headerEncoded + bodyEncoded + footerEncoded);
}
return bodyBlob;
}
What is happening here is.. Our deployment status in org is showing successful. But no element is deployed. Means class is not deployed.
I have followed the following links to work on it.
Deploy sfdc doc
https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_rest_deploy.htm
Nerd@work article
https://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html
NOTE: Deploying zip file is working with MetadataService.MetaPort.
I tried it also from the Postman. Normally Postman is uploading files with multipart. But for this API still its saying undefined for files.
Communities posted on
https://salesforce.stackexchange.com/users/114433/abhi-sisodia
Log In to reply.
Popular Salesforce Blogs
![Salesforce Blockchain](https://images.forcetalks.com/wp-content/uploads/2020/04/17174146/Salesforce-Blockchain1.png)
Introducing Salesforce Blockchain: World’s No.1 CRM Moves into Blockchain with its own Platform
Salesforce just got done with TrailheaDX 2019 this weekend. Algoworks was at TDX19 too, and oh boy, did we have fun! There was a bunch…
![sales cloud marketing cloud](https://images.forcetalks.com/wp-content/uploads/2020/09/02153704/sales-cloud-marketing-cloud.jpg)
How to Import Reports From Salesforce Sales Cloud Into Marketing Cloud Using Imports
In Salesforce Marketing cloud we can import data into the marketing cloud in two ways using imports : Objects and Reports Here I will explain…
![Docusign E-Signature](https://images.forcetalks.com/wp-content/uploads/2021/04/29181434/Docusign-E-Signature-.jpg)
Docusign E-Signature in Salesforce | The Integration Guide
Why We Need DocuSign? As there are lots of business needs in which we need to send an email with a document in which users…
Popular Salesforce Videos
Creating a To-do List with Custom Events | Salesforce Developer Quick Takes
Creating a ToDo list will show us how we can take data from one component and pass it to another. In our ToDo list component,…
Wow Your Customers with Salesforce Customer 360
Salesforce Customer 360 helps companies unite their teams to deliver amazing wow-worthy experiences beyond customer expectations.
How to Use Dispatcher Console in Salesforce Field Service? | Elevate Field Service Delivery | AblyPro
Dispatcher Console makes field service delivery easy for your business. Using the Dispatcher Console included in the Field Service package, your dispatchers can easily schedule,…