Cuando necesitamos realizar integraciones de nuestras aplicaciones con nuestra plataforma de Force.com, y de esta forma poder acceder a los datos de Salesforce.com de la manera más sencilla posible, o necesitamos exponer nuestros métodos APEX de Force.com para poder desarrollar, por ejemplo, aplicaciones móviles, Force.com nos da la posibilidad de poder crear Servicios Web basados tanto en SOAP como en REST.
El acceso a estos Servicios Web desde nuestras aplicaciones externas se realiza mediante autenticación. La forma de autenticarnos con Salesforce es usando OAuth 2.0. Pero, ¿qué ocurre si nuestros Servicios Web los incluimos dentro de un Site público de Force.com? Pues que en este caso no es necesaria la autenticación. Por lo tanto centraré este post en explicar cómo podemos acceder a nuestros Servicios Web de Force.com de forma anónima, sin necesidad de autenticarnos.
Debemos tener muy presentes los permisos que concedemos al perfil del usuario invitado del Site en el que publicamos nuestros Servicios Web, ya que los datos serán accesibles de forma pública.
Antes de nada, daremos un pequeño repaso a la creación de Servicios Web basados en REST y en otro post posterior lo haré sobre los Servicios Web basados en SOAP. La forma de crear estos servicios en Force.com es mediante código APEX.
Servicios Web basados en REST
La API REST de Force.com permite integrar aplicaciones externas con Force.com utilizando métodos sencillos de HTTP, ya sea con formato XML o JSON, haciéndolo ideal para desarrollar aplicaciones móviles o clientes externos.
Force.com nos facilita seis anotaciones que nos permiten exponer una clase de Apex como un servicio REST:
- @RestResource(urlMapping=’/TuUrl‘). Se usa a nivel de clase y te permite exponer tu clase APEX como un recurso REST. El mapeo de la URL es case-sensitive, es decir, distingue mayúsculas y minúsculas. Para utilizar esta anotación tu clase APEX debe ser definida como global.
- @HttpDelete. Se usa a nivel de método. Este método es invocado cuando se envía una petición HTTP DELETE. Para utilizar esta anotación tu método APEX deber ser definido como global.
- @HttpGet. Se usa a nivel de método. Este método es invocado cuando se envía una petición HTTP GET. Para utilizar esta anotación tu método APEX deber ser definido como global.
- @HttpPatch. Se usa a nivel de método. Este método es invocado cuando se envía una petición HTTP PATCH. Para utilizar esta anotación tu método APEX deber ser definido como global.
- @HttpPost. Se usa a nivel de método. Este método es invocado cuando se envía una petición HTTP POST. Para utilizar esta anotación tu método APEX deber ser definido como global.
- @HttpPut. Se usa a nivel de método. Este método es invocado cuando se envía una petición HTTP PUT. Para utilizar esta anotación tu método APEX deber ser definido como global.
Sólo puede existir una anotación de cada tipo en la clase APEX. Es decir, sólo podremos tener una anotación del tipo @HttPost, por ejemplo.
APEX REST soporta dos formatos: JSON y XML, y se debe indicar el tipo utilizado en la propiedad Content-Type de la cabecera HTTP. El formato JSON es el que se utiliza por defecto en el cuerpo de una petición (HttpRequest) o respuesta (HttpResponse). A modo de resumen debemos tener en cuenta las siguientes consideraciones:
- Los objetos RestRequest (HttpRequest) y RestResponse (HttpResponse) están disponibles por defecto en los métodos APEX a través del objeto estático RestContext. Este ejemplo muestra cómo podemos acceder a estos objetos:
RestRequest req = RestContext.request; RestResponse res = RestContext.response;
- Si el método APEX utilizado no tiene parámetros, APEX REST copia el cuerpo de la petición HTTP en la propiedad RestRequest.requestBody, de tipo Blob.
- Si se han definido parámetros en el método APEX utilizado, APEX REST intenta deserializar los datos y convertirlos en los parámetros.
- APEX REST usa una lógica similar de serialización para las respuestas. Si el método APEX está definido para devolver un tipo determinado, APEX REST serializa el valor correspondiente y lo devuelve dentro de la propiedad RestResponse.responseBody.
- Los métodos con anotaciones @HttpGet o @HttpDelete no deberían tener parámetros. Esto es debido a que las peticiones HTTP GET y DELETE carecen de cuerpo, por lo que no habría nada que deserializar.
- APEX REST actualmente no soporta peticiones con el Content-Type del tipo multipart/form-data.
A continuación puedes ver un ejemplo de una clase APEX expuesta como servicio REST obtenido de aquí:
@RestResource(urlMapping='/Account/*') global with sharing class MyRestResource { @HttpDelete global static void doDelete() { RestRequest req = RestContext.request; String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1); Account account = [SELECT Id FROM Account WHERE Id = :accountId]; delete account; } @HttpGet global static Account doGet() { RestRequest req = RestContext.request; String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1); Account result = [SELECT Id, Name, Phone, Website FROM Account WHERE Id = :accountId]; return result; } @HttpPost global static String doPost(String name, String phone, String website) { Account account = new Account(); account.Name = name; account.phone = phone; account.website = website; insert account; return account.Id; } }
La url de acceso a nuestra clase APEX expuesta como servicio REST, utilizando autenticación OAuth 2.0, sería de la siguiente forma:
https://instance.salesforce.com/services/apexrest/urlMapping
Donde:
- instance. Es el nombre de la instancia de nuestra organización.
- urlMapping. Es la URL relativa de mapeo de nuestro servicio APEX REST.
Siguiendo este mismo ejemplo, si quisiéramos crear una cuenta nueva utilizando nuestro servicio REST, tendríamos que realizar una petición HTTP POST, con el Content-Type: application/json, a la url:
https://instance.salesforce.com/services/apexrest/Account
Y como cuerpo de la petición tendríamos que pasar el siguiente JSON:
{ "name" : "José Luis ALmazán", "phone" : "690968879", "website" : "http://www.ticMind.es" }
Como estamos realizando una petición POST, se ejecutaría el método APEX doPost() y Salesforce devolvería una cadena de texto con el Id de la cuenta que se acaba de crear:
"accountId"
Y básicamente ésta sería una pequeña introducción a los servicios APEX REST.
Todo esto está muy bien, pero como ya he dicho antes, resulta que en este ejemplo debemos utilizar autenticación OAuth 2.0 para poder acceder al servicio REST. Ahora pasaré a explicar qué debemos hacer para poder utilizar este mismo servicio REST de forma pública, sin necesidad de autenticación. Para ello, lo primero que debemos hacer es crearnos un Site o utilizar un Site que ya tengamos. Es muy importante indicar que Force.com Sites sólo está disponible para las ediciones: Developer, Enterprise y Unlimited.
Para crear un Site, siga los siguientes paso:
- Haga clic en Su nombre | Configuración | Desarrollos | Sitios -> Botón Nuevo.
- Cumplimente los campos necesarios y haga clic en el botón Guardar.
Ya tendríamos el Site creado. Para poder hacer público nuestro servicio REST en este Site, lo primero que necesitamos es conceder acceso al perfil del Site a la clase APEX de nuestro servicio REST, en el ejemplo anterior MyRestResource. Además, debemos conceder los permisos necesarios de lectura y/o escritura sobre los objetos implicados en nuestros métodos APEX REST. Para ello:
- Haga clic en Su nombre | Configuración | Desarrollos | Sitios.
- Haga clic en el nombre del sitio que desea controlar.
- Haga clic en Configuración de acceso público para abrir la página del perfil del sitio.
- Vaya hasta Acceso a clase de Apex activado y pulse sobre el botón Modificar para poder Activar la clase APEX correspondiente a nuestro servicio REST. Para aceptar los cambios pulse el botón Guardar.
- Si necesita conceder permisos a algún objeto (en el ejemplo anterior necesitaríamos conceder permisos de lectura/escritura sobre el objeto Cuentas), pulse sobre el botón Modificar (seguimos dentro de la Configuración de acceso público), vaya hasta los Permisos de objetos y seleccione los permisos necesarios. Para finalizar pulse sobre el botón Guardar.
Ya tendríamos publicado nuestro servicio APEX REST en nuestro Site, por lo que ya sería accesible de forma pública. En este caso, debemos es muy importante indicar que la url de acceso a nuestro servicio REST es diferente a la que indicábamos anteriormente, cuando el servicio REST requería autenticació. Al estar publicado dentro del Site, la url sería de la siguiente forma:
https://dominioForceCom/site/services/apexrest/urlMapping
Donde:
- dominioForceCom. Es el nombre de nuestro dominio de Force.com en nuestra organización. En mi entorno de desarrollo, sería jlalmazan-developer-edition.na14.force.com.
- site. Es el nombre de nuestro Site.
- urlMapping. Es la URL relativa de mapeo de nuestro servicio APEX REST.
Y ya tendríamos nuestro servicio APEX REST accesible de forma pública.
Espero que os sirva de ayuda este post. Si os ha gustado, podéis seguir mi blog o seguirme en twitter.
Very informative Post.
Could you please explain with example how to call the REST API from an outside application which is built on javascript.
Hi @arjun.
You can view more info about this here: https://developer.salesforce.com/page/JavaScript.
Remember that if you use a REST API with authentication, this is done through OAuth2.0.
I hope this helps.
Very Helpful Sir. Really Appreciated
Thank you very much @Piyush!
Saludos, gracias por hacer publicaciones de este tipo en español.
Ahora por favor necesito de tu apoyo para aclarar un punto que no se mencionan en este «how to».
Cuando creas un Site uno de los campos obligatorios es contar con una visualforce que vaya ligada al site.
¿Hay que tener alguna visualforce?
¿o simplemente puedo seleccionar cualquiera de las opciones que muestra el campo?
Gracias por el apoyo!
Hola Alejandro.
Lo primero, gracias a ti por interesarte por mi blog, y lo segundo, pedirte disculpas por el retraso en mi respuesta.
Cuando creas un site que sólo lo vas a usar para alojar tu Web Service, realmente no será un sitio visitable desde la web, es decir, es un sitio que carece de interfaz de usuario. Lo único obligatorio al crear un site, a nivel de páginas Visualforce, es el campo «Página de inicio de sitio Web activa». Como no va a ser un sitio visitable, yo seleccionaría la página Visualforce «UnderConstruction» por defecto, pero puede ser cualquiera de las que viene por defecto.
Espero haberte ayudado.
Un saludo.
Muchisimas gracias por esta publicacion, a sido de gran ventaja. Quiero preguntarte, ahi alguna forma de pasar todo el JSON por el metodo, en lugar de parametro por parametro, mejor dicho algo asi?
global static String doPost(String myWebInfo) {
en lugar de
global static String doPost( String name, String phone, String website) {
pregunto esto por 2 razones, la primera si estoy recolectando mucha informacion se vuelve un poco tedioso poner muchas variable. Y la segunda aun no me queda claro como asi el metodo para saber la relacion con los parametros, asumo que es algo que salesforce tiene uno no se tiene q preocupar, pero me llama bastante la atencion que el orden de los parametros y es lo mismo poner
global static String doPost( String name, String phone, String website) {
que algo asi
global static String doPost( String phone, String website, String name) {
Gracias
Hola Fabián.
Respondiendo a tu pregunta, puedes recoger el JSON completo en tu método POST, definiendo como parámetro de entrada la propia clase que hace de wrapper del JSON. Otra opción es no poner parámetro de entrada en tu método POST y recoger el valor del JSON del cuerpo de la petición y deserializarlo en la clase wrapper del JSON.
He encontrado esta página que lo explica muy buen: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest_methods.htm
Espero haberte ayudado.
Saludos.