Custom Metadata Types vs Custom Settings vs Custom Labels 💬 In plain words: Three lookalikes: Custom Metadata = configuration that DEPLOYS with your code (best for app settings). Custom Settings = org/user-specific values, changeable at runtime (hierarchy type is great for bypass switches). Custom Labels = translatable text for the UI. 📌 Example: API endpoint URLs per environment → Custom Metadata (deploys with code, sandbox vs prod values). A 'Bypass_Automation__c' checkbox an admin flips during data load → hierarchy Custom Setting. The word 'Submit' translated to Hindi → Custom Label. 🎬 Real-Life Example: The Fee Table Trapped Inside Code Skyline charges a different delivery fee per city. Apex needs those rates on every booking. The Old/Bad Way: if (city == 'Delhi') fee = 50. Else if (city == 'Mumbai') fee = 65. … Every rate change is a code change, a test run, and a deployment. Why this is bad: Business data is trappe...
Here is a solution to upload a file to a third-party system using Apex in Salesforce.
Below is the FormData builder Apex class, which builds the required multipart parameters:
public class FormData {
private final static String Boundary = '1ff13444ed8140c7a32fc4e6451aa76d';
public enum EndingType {
Cr,
CrLf,
None
}
/**
* Returns the request's content type for multipart/form-data requests.
*/
public static String GetContentType() {
return 'multipart/form-data; charset="UTF-8"; boundary="' + Boundary + '"';
}
/**
* Pad the value with spaces until the base64 encoding is no longer padded.
*/
private static String SafelyPad(String value, String valueCrLf64, String lineBreaks) {
String valueCrLf = '';
Blob valueCrLfBlob = null;
while (valueCrLf64.endsWith('=')) {
value += ' ';
valueCrLf = value + lineBreaks;
valueCrLfBlob = Blob.valueOf(valueCrLf);
valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
}
return valueCrLf64;
}
/**
* Write a boundary between parameters to the form's body.
*/
public static String WriteBoundary() {
String value = '--' + Boundary + '\r\n';
Blob valueBlob = Blob.valueOf(value);
return EncodingUtil.base64Encode(valueBlob);
}
/**
* Write a boundary at the end of the form's body.
*/
public static String WriteBoundary(EndingType ending) {
String value = '';
if (ending == EndingType.Cr) {
value += '\n';
} else if (ending == EndingType.None) {
value += '\r\n';
}
value += '--' + Boundary + '--';
Blob valueBlob = Blob.valueOf(value);
return EncodingUtil.base64Encode(valueBlob);
}
/**
* Write a key-value pair to the form's body.
*/
public static String WriteBodyParameter(String key, String value) {
String contentDisposition = 'Content-Disposition: form-data; name="' + key + '"';
String contentDispositionCrLf = contentDisposition + '\r\n\r\n';
Blob contentDispositionCrLfBlob = Blob.valueOf(contentDispositionCrLf);
String contentDispositionCrLf64 = EncodingUtil.base64Encode(contentDispositionCrLfBlob);
String content = SafelyPad(contentDisposition, contentDispositionCrLf64, '\r\n\r\n');
if (key == 'file') {
System.debug(value);
}
String valueCrLf = value + '\r\n';
Blob valueCrLfBlob = Blob.valueOf(valueCrLf);
if (key == 'file') {
System.debug(valueCrLfBlob);
}
String valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
content += SafelyPad(value, valueCrLf64, '\r\n');
return content;
}
public static String writeFileBody(String key, Blob attachBody, String filename) {
String header = '--' + Boundary + '\r\n' +
'Content-Type: application/octet-stream\r\n' +
'Content-Disposition: form-data; name="' + key + '"; filename="' + filename + '"';
String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header + '\r\n\r\n'));
while (headerEncoded.endsWith('=')) {
header += ' ';
headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header + '\r\n\r\n'));
}
String bodyEncoded = EncodingUtil.base64Encode(attachBody);
return headerEncoded + bodyEncoded;
}
public static String append(String key, String value) {
return FormData.WriteBoundary() + WriteBodyParameter(key, value);
}
public static Blob makeBlobWithFile(String key, Blob attachBody, String filename, String otherParamsEncoded) {
String header = '--' + Boundary + '\r\n' +
'Content-Type: application/octet-stream\r\n' +
'Content-Disposition: form-data; name="' + key + '"; filename="' + filename + '"';
String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header + '\r\n\r\n'));
while (headerEncoded.endsWith('=')) {
header += ' ';
headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header + '\r\n\r\n'));
}
String footer = '--' + Boundary + '--';
String bodyEncoded = EncodingUtil.base64Encode(attachBody);
Blob formBlob = null;
String last4Bytes = bodyEncoded.substring(bodyEncoded.length() - 4, bodyEncoded.length());
if (last4Bytes.endsWith('==')) {
last4Bytes = last4Bytes.substring(0, 2) + '0K';
bodyEncoded = bodyEncoded.substring(0, bodyEncoded.length() - 4) + last4Bytes;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
formBlob = EncodingUtil.base64Decode(otherParamsEncoded + headerEncoded + bodyEncoded + footerEncoded);
} else if (last4Bytes.endsWith('=')) {
last4Bytes = last4Bytes.substring(0, 3) + 'N';
bodyEncoded = bodyEncoded.substring(0, bodyEncoded.length() - 4) + last4Bytes;
footer = '\n' + footer;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
formBlob = EncodingUtil.base64Decode(otherParamsEncoded + headerEncoded + bodyEncoded + footerEncoded);
} else {
footer = '\r\n' + footer;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
formBlob = EncodingUtil.base64Decode(otherParamsEncoded + headerEncoded + bodyEncoded + footerEncoded);
}
return formBlob;
}
public static Blob makeBlob(String ParamsEncoded) {
String footer = '--' + Boundary + '--';
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
return EncodingUtil.base64Decode(ParamsEncoded + footerEncoded);
}
}
Here is the file upload method where multiple parameters (document metadata) and the binary file body are sent:
public void uploadFile(Blob attachBody, String filename) {
String contentType = FormData.GetContentType();
String form64 = '';
// Adding document metadata or properties
form64 += FormData.append('key1', 'Value1');
form64 += FormData.append('key2', 'Value2');
// Adding document body with file parameter
Blob formBlob = FormData.makeBlobWithFile('file', attachBody, filename, form64);
String contentLength = String.valueOf(formBlob.size());
HttpRequest httpRequest = new HttpRequest();
httpRequest.setBodyAsBlob(formBlob);
httpRequest.setHeader('Connection', 'keep-alive');
httpRequest.setHeader('Content-Length', contentLength);
httpRequest.setHeader('Content-Type', contentType);
httpRequest.setMethod('POST');
httpRequest.setTimeout(120000);
httpRequest.setHeader('Accept', 'application/json');
httpRequest.setHeader('Authorization', 'Bearer YOUR_TOKEN');
httpRequest.setEndpoint('YOUR_ENDPOINT_URL');
Http http = new Http();
HttpResponse res = http.send(httpRequest);
}
Extract From: muenzpraeger / salesforce-einstein-vision-apex