In the previous post, we looked at the basics of calling an external HTTP endpoint using Apex. In this installment, we’ll dig a little deeper and look at how we can create request payloads in JSON and also figure out how to handle responses sent by remote servers in this same format. If you’re dealing with APIs that were built recently, it is probably expecting you to send it request details in the form of JSON and it is likely sending you JSON responses back. Older web API endpoints largely transacted in XML format but that practice has fallen out of favor for REST based APIs dealing in JSON.
For our experimentation, let’s use JSONPlaceholder, a free fake REST API for testing and prototyping. Like we learned in the last post, we just have to remember to add it to our list of websites in Remote Site Settings. Let’s start by creating a new post against their “posts” endpoint:
URL: https://jsonplaceholder.typicode.com/posts
Method: POST
If you look at their guide, you’ll see that this endpoint is expecting a JSON object like this:
{ title: 'foo', body: 'bar', userId: 1, }
There are a few different ways to create this JSON structure from within your Apex code. The simplest way to achieve this is to construct the string content, manually:
String title = 'This is my test title'; String body = 'This is my test body.'; Integer userId = 1; request.setBody('{"title":"' + title + '", "body":"' + body + '", "userId": ' + userId + '}');
But you can probably see the shortcomings with such an approach – this is going to get really ugly with a JSON structure that’s more complicated than this simple example. We’ll soon miss a single quote somewhere and have an invalid JSON blob in our hands.
A better approach is to use the JSONGenerator class that comes out of the box with Salesforce. Creating our “post” JSON looks something like this:
String title = 'This is my test title'; String body = 'This is my test body.'; Integer userId = 1; JSONGenerator jsonGen = JSON.createGenerator(true); // true = pretty print the output jsonGen.writeStartObject(); jsonGen.writeStringField('title', title); jsonGen.writeStringField('body', body); jsonGen.writeNumberField('userId', userId); jsonGen.writeEndObject(); String jsonData = jsonGen.getAsString(); System.debug('Json Data - ' + jsonData);
This approach gives you the most bit of control and you can even create nested structures with different and complex data types such as objects and arrays. It gets quite wordy but you avoid the pain of having to deal with runtime errors with the earlier string concatenation approach.
There is a third option that may work in some regards and that is to automatically serialize an object record:
Contact con = [SELECT Id, LastName, AccountId FROM Contact LIMIT 1]; // Set additional field con.FirstName = 'Joe'; String jsonstring = Json.serialize(con); System.debug(jsonstring);
Or hydrate one of your own classes and then serialize that into JSON, like so:
public class BlogPost { string Title; string Body; integer UserId; } public static void sendTestRequest() { BlogPost blogPost = new BlogPost(); blogPost.Title = 'This is a Test'; blogPost.Body = 'The quick brown fox jumped over the lazy dog.'; blogPost.UserId = 42; String jsonString = JSON.serialize(blogPost); System.debug(jsonString); }
I’ll end this post with a fully working example of sending this example JSON payload to the JSONPlaceholder posts endpoint:
public class HttpRequestsDemo { public class BlogPost { string Title; string Body; integer UserId; } public static void sendTestRequest() { BlogPost blogPost = new BlogPost(); blogPost.Title = 'This is a Test'; blogPost.Body = 'The quick brown fox jumped over the lazy dog.'; blogPost.UserId = 42; String jsonString = JSON.serialize(blogPost); System.debug(jsonString); HttpRequest request = new HttpRequest(); request.setMethod('POST'); request.setEndpoint('https://jsonplaceholder.typicode.com/posts'); request.setHeader('Content-Type', 'application/json; charset=UTF-8'); request.setBody(jsonString); HttpResponse response = new HttpResponse(); Http http = new Http(); response = http.send(request); System.debug(response.getBody()); } }
Parting Thoughts
In this episode we looked at a few ways of crafting JSON structures in Apex. In the next one, we’ll look at how we can handle JSON responses sent to us from remote systems.