Post ‘multipart/form-data’ out of Salesforce.com with APEX


¿Es cierto que Salesforce no permite realizar peticiones HTTP (callouts) con datos multipart/form-data desde APEX? Pues la respuesta es que Salesforce sí lo permite, lo único que tenemos que tener en cuenta es qué tipo de datos admite el servidor destino al que enviamos la petición.

Esto es muy importante cuando queremos subir archivos desde Salesforce (vía APEX, por supuesto) a un servidor externo a Salesforce, como Box o WatchDox, por ejemplo. Esto resulta económicamente rentable, cuando el coste de almacenamiento del servidor externo es inferior al coste de almacenaniento de Salesforce.

Lo primero que debemos averiguar es qué tipo de datos admite el servidor externo en las peticiones con datos multipart/form-data. Puede ser que el servidor externo sólo admita contenido binario, o puede ser que admita contenido codificado en base64, o ambos.

En el primero de los casos, en el que el servidor destino sólo admita contenido binario, Enrico Murro, miembro de Cloudspokes al igual que yo, ha desarrollado hace escasos días una magnífica solución, que puedes ver aquí. Se trata de una solución que muchos desarrolladores de Salesforce estaban esperando, y que gracias a este reto de Cloudspokes en el que ambos hemos participado, pudimos investigar a fondo sobre este tema.

Si el servidor destino admite también contenido codificado en base64, en este caso la solución es mucho más sencilla. Esta fue la opción que yo opté para este reto, ya que el servidor destino admitía ambos tipos de contenido.

A continuación muestro un código de ejemplo para este tipo de servidores:

public static HTTPResponse uploadFile(String fileName, Blob fileBody, String contentType){

		// Body
		String boundary = String.valueOf(DateTime.now().getTime());
		String body = '------------' + boundary + '\r\n';
        body+='Content-Disposition: form-data; name="data"; filename="' + fileName + '"\r\n';
        body+='Content-Transfer-Encoding: base64\r\n';
        if ((contentType == null) || (contentType == '')){contentType = 'application/octet-stream';}
        body+='Content-Type: ' + contentType + '\r\n\r\n';
        body+=EncodingUtil.base64Encode(fileBody);
       	body+='\r\n------------' + boundary + '--';

		// Instantiate a new HTTP request, specify the method (POST) as well as the endpoint
		HttpRequest req = new HttpRequest();

		// Set headers
		req.setHeader('Content-Type', 'multipart/form-data; boundary=----------' + boundary);
		req.setHeader('Content-Length',String.valueof(body.length()));

		// Set body
		req.setBody(body);

        // Set method and endpoint
		req.setMethod('POST');
		req.setEndpoint('http://www.TuServidorExterno.com');

		// Send HTTP request and get HTTP response
		Http http = new Http();
 		return(http.send(req));
    }

Puedes ver el vídeo de esta funcionalidad en acción correspondiente a mi solución creada para el reto de Cloudspokes, la cual permite subir todo tipo de archivos de hasta 3Mb a WatchDox desde Salesforce. Si el explorador web soporta HTML5, se pueden seleccionar varios archivos para subirlos en el mismo proceso, soporta drag&drop, y además se muestra una barra de progreso por cada archivo que se quiere subir.

Espero que este post os sirva de ayuda.

Acerca de José Luis Almazán

Senior Salesforce Developer y cofundador de ticMind Consulting (Consultoría Salesforce y Force.com y parter de Salesforce en Madrid). Poseo una amplia experiencia con más de 10 años en desarrollos en C# .NET, y más de 4 años en desarrollos en Salesforce. En la actualidad trabajo como Freelance en proyectos de Salesforce. Realizo trabajos de desarrollo, integración y administración de Salesforce CRM. Mi principal dedicación con Salesforce la he centrado en realizar desarrollos avanzados en Force.com. Poseo amplia experiencia en Visualforce, APEX, Remoting, Web Services, Future, SOAP API, REST API, Bulk API, Streaming API, Metadata API, Chatter REST API, Database.com, Sites, AJAX Toolkit, Triggers, Workflows... He realizado integraciones en Force.com con otros servicios, como Pusher, Tokbox, Box, WatchDox, Google Cloud Storage (XML API y JSON API), Google Maps API... Y en la parte cliente, amplia experiencia con HTML, HTML5, Javascript, jQuery, CSS... He trabajado en varios proyectos muy importantes de Salesforce, desarrollando entre otras funcionalidades, Chat, Videoconferencia, Mensajería interna, Gestión de eventos, Formularios WebToLead dinámicos, Generación de encuestas, etc... Además, fui un miembro activo de CloudSpokes, una importante comunidad crowdsourcing de más de 70.000 desarrolladores de todo el mundo, en cuyo ranking estuve entre los 35 primeros. Cofundador de ticMind Consulting, empresa especializada en Consultoría Salesforce.com y Force.com, y formada por un equipo estable de profesionales altamente cualificados y con gran experiencia en entornos cloud.
Esta entrada fue publicada en APEX, Force.com, HTTP POST, HttpRequest, Salesforce.com y etiquetada , , , , , , . Guarda el enlace permanente.

10 respuestas a Post ‘multipart/form-data’ out of Salesforce.com with APEX

  1. Tejas dijo:

    Hi, thanks for the nice post. i m having problem with calling REST API; i hope you can help out. i’m getting error: 400 (SalesforceProxy-Endpoint not defined in header.) … Thanks in advance.
    here is my code:

    // Get a reference to jQuery that we can work with
    $j = jQuery.noConflict();
    // Get an instance of the REST API client and set the session ID
    var client = new forcetk.Client();
    client.setSessionToken(‘{!$Api.Session_ID}’);
    $j.ajax({
    url: «https://csX.salesforce.com/services/proxy/apexrest/Contact/v27.0/doGet/»,
    type: ‘GET’,
    dataType: ‘json’,
    error: function(data1) { alert(‘error’); alert(data1.errorCode); },
    beforeSend: function (xhr) {
    xhr.setRequestHeader(‘Authorization’, «OAuth » + client);
    xhr.setRequestHeader(‘Accept’, «application/json»);
    },
    success: function() { alert(‘hello!’); }
    });

  2. Tejas dijo:

    I have created REST API:
    @HttpGet
    global static List getContact() {
    List widgets = [SELECT Id, Name, Phone, sbscbr_num__c FROM Contact
    ];
    return widgets;
    }
    I am trying to call this api through VF Page using JQuery ajax. I am able to call this API using workbench and getting JSON result also. But just not working through VF Page.
    Hope i’m clear this time. Pls let me know if you have more questions. Thanks.

  3. Tejas dijo:

    I agree but we are performing some test; moving forward we are planning to use REST API from different org also.

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s