Reasons to [Still] Love SharePoint’s SOAP Web Services

There are still reasons to love the SOAP Web Services (hopefully using SPServices!) even though they have been deprecated by Microsoft in SharePoint 2013 (and one can assume to upcoming SharePoint 2016) and SharePoint Online.

There are times when the REST API just doesn’t provide functionality we need, and the SOAP Web Services are a useful fallback when that’s the case.

I’ve run into two very specific instances where this was the case lately. Since Microsoft is actively trying to get REST up to snuff, I’ve added requests to the SharePoint User Voice for both of these. If you would like to see these fixed, please go to the User Voice links and vote them up. While we’re waiting, though, it’s SOAP to save the day.

Recurring Calendar Events

It’s extremely common to have recurring events in a SharePoint Calendar list. Usually this type of event is used for a recurring meeting, or it could just be a placeholder to remind a team to check something, etc.

If you’re building client-side functionality, you may want to do something like retrieving all of the occurrences of events to show in a widget like fullcalendar. Unfortunately, the REST API doesn’t know from recurrence.

There’s a sample at the OfficeDev/PnP repo, but if you run through it, you’ll see it’s pretty ugly. Ingenious, but ugly.

You can pass a CAML fragment into your REST call to augment the OData request, and here’s a different example of how that can work:

// Example from https://karinebosch.wordpress.com/my-articles/caml-designer-for-sharepoint-2013/
$.ajax({ 
  url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Tasks')/GetItems(query=@v1)?@v1={\"ViewXml\":\"<View><Query><Where><And><Neq><FieldRef Name='Status' /><Value Type='Choice'>Completed</Value></Neq><Membership Type='SPWeb.Groups'><FieldRef Name='AssignedTo' /></Membership></And></Where></Query></View>\"}", 
  type: "POST", 
  headers: { 
      "X-RequestDigest": $("#__REQUESTDIGEST").val(), 
      "Accept": "application/json;odata=verbose", 
      "Content-Type": "application/json; odata=verbose" 
  }, 
  success: function (data) { 
    if (data.d.results) { 
      // TODO: handle the data  
      alert('handle the data'); 
    } 
  }, 
  error: function (xhr) { 
     alert(xhr.status + ': ' + xhr.statusText); 
  } 
});

But if you need to do that, I don’t see why you wouldn’t just use SOAP.

User Voice: Add support for recurring events in the REST API

Lookup Site Columns in Other Webs

A good information architecture usually includes some list-based lookup columns. A simple example might be a list stored in the root site of a Site Collection to contain information about all of your organization’s offices. You might store things like:

  • Name of Office (using the Title column)
  • Address
  • City
  • State
  • Postal Code
  • Office Manager
  • Phone Number
  • Industry Focus
  • etc.

Then you might have a Site Column called Office Name that is a Lookup column into the Title column of that list. This enables you to offer a consistent list of options for Office Name to choose from throughout the Site Collection along with the other information (as needed), either for display purposes or for inclusion as data in other lists.

If you try to make a REST call which requests data in a column like this – when you aren’t in same site as the list – you’ll get an error like this:

{"error":{"code":"-1, Microsoft.SharePoint.SPException","message":{"lang":"en-US","value":"The field 'MyLookupColumn' is not supported in query. The lookup list is in another web."}}}

Uh-uh, it’s back to SOAP again.

User Voice: Enable support for lookup columns in other webs in the REST API

 

In case you were going to ask, I avoid CSOM/JSOM. I see it as a dead end – in this context, at least. More of Microsoft’s effort is going into REST, which is based on Web standards rather than a Microsoft-only approach.

What about you? Do you still see uses for SOAP where REST won’t do it? Respond in the comments if you know of other holes in the REST Swiss cheese.

Moving from SPServices to REST, Part 4: Converting GetListItems to REST

This entry is part 4 of 4 in the series Moving from SPServices to REST

Summary: Because of the significant inconsistencies in the SOAP Web Services, converting your calls to REST will be a different process for each of them. In this article, we’ll look at the real workhorse of SPServices: GetListItems.

When my mechanic works on my car, sometimes he tells me about some different tires or parts I might consider instead of what was on the car since I got it. It might be to improve performance or to give me a bit more life out of the car than I might get otherwise. (I have a good mechanic.)

Officina Meccanica by efilpera https://flic.kr/p/5vvSy9

Photo credit: Officina Meccanica by efilpera https://flic.kr/p/5vvSy9

As I’ve suggested in prior articles in the series, you can start moving individual calls from SOAP to REST anytime that you decide. If you’re still running an older version of SharePoint (no shame there), then it probably won’t be until you upgrade to SharePoint 2013. If you’re already on SharePoint 2010 or 2013, then you can start anytime.

When it comes time to converting some SOAP calls to REST calls, what will that process look like? In this article, we’re going to take a look at converting the workhorse of the SOAP Web Services: GetListItems.

GetListItems lets us read items from a list or library (virtually all content in SharePoint is stored in a list or library – a library is just a fancy list that is document-centric). Even basic information about users is stored in each Site Collection in the User Information List. GetListItems does a lot for us in SPServices-based development; it’s the most-commonly used function by just about every developer who uses SPServices and it sits underneath most of the value-added functions like SPCascadeDropdowns and SPDisplayRelatedItems.

The basic structure of the simplest GetListItems call is this:

$().SPServices({
  operation: "GetListItems",
  listName: "Tasks"
});

We make a call to SPServices, specify the GetListItems operation, and specify the list from which we want to get data. That’s about it. The results of this call will contain the items in the Tasks list (in the current site) as they are displayed in the Tasks list’s default view, which by default would be AllTasks.aspx.

Usually we’d have a bit more code wrapped around this call, maybe something like this:

var p = $().SPServices({
  operation: "GetListItems",
  listName: "Tasks"
});

p.done(function() {

  // Process the response

});

Note that I’m using a promise above so that I know when the call has completed rather than making a synchronous call. More on that in a later article.

So what does the analogous REST call look like? It would be something like this:

$.ajax({
  url: _spPageContextInfo.webAbsoluteUrl +
    "/_api/web/lists/getbytitle('Tasks')/items",
  method: "GET",
  headers: {
    "Accept": "application/json; odata=verbose"
  },
  success: function(data) {
    success(data); // If the call is successful, process the response
  },
  error: function(data) {
    failure(data); // Do something with the error
  }
});

Not so different when you get past the sides and trimming, right? The specifics of what we’re asking for in the REST call are all in the url object. The way REST works is that we pass information about what we want the server to do for us as parameters on the url. In this case, we have:

url: _spPageContextInfo.webAbsoluteUrl +
    "/_api/web/lists/getbytitle('Tasks')/items",

This means:

  • Go to the context of _spPageContextInfo.webAbsoluteUrl, which is the current site. In SPServices, I figure this out for you, or you can choose to specify a different site with the webURL parameter.
  • Call the lists service: /_api/web/lists
  • Select the Tasks list using its name: /getbytitle(‘Tasks’)
  • And finally, get the items: /items

The rest of the REST call is just packaging and what we want to do with the result.

Where the two methods start to diverge more is when we start to request things in more specific ways, for example all of the outstanding tasks for a particular user. But there’s an imperfect isomorphism here. For virtually everything we can do with the SOAP Web Services, we can do the same thing in REST just by adding the analogous parameters to the REST call.

Here’s how some of the most common parameters in the request payload map from SOAP to REST:

SOAP Option(SPServices synonym) REST Comments
ViewFields(CAMLViewFields) $select Choose the columns you would like to retrieve. With both SOAP and REST we get some data we don’t explicitly request, but by specifying only the columns we need we can reduce the payload sizes.
Query(CAMLQuery) $filter, $orderby Specify which items in the list we would like to return and how we would like them sorted.
RowLimit(CAMLRowLimit) $limit Say how many items matching the Query we would like to receive. In SOAP we can specify 0 to get all matching items; in REST we can omit the parameter to get all the matching items. Otherwise, we can specify any integer as the limit.
ViewName(CAMLViewName) NA ViewName lets you choose the view you would like to get in the response. There’s no REST equivalent here. I’ve always discouraged using this option in SOAP because it’s too easy to change the view settings and cause unintended consequences.
QueryOptions (CAMLQueryOptions) NA In SOAP, this lets us specify some options that change how the data is returned to us. For example, we can ask for all of the attachment URLs rather than just a Boolean which tells us that there are attachments.
NA $expand This option in REST has no direct equivalent in SOAP. $expand allows us to indicate that we would like the values for a relationship – rather than just the indices – using a projection. This is important with Lookup columns and Person or Group columns.

References:

As you can see, it’s really not that scary. It’s the equivalent of translating Spanish into French, but even easier since all of the words are in English (sorry rest of the world – I’m going to play American on this one).

Here’s a slightly more complicated example where I’m asking for items from a Workflow Tasks list.

First, the SOAP request:

SOAPRequest

And then the equivalent REST request:

REST request for items from a Workflow Tasks list

Here’s how the two calls break down based on the table I showed above:

SOAP REST
CAMLViewFields <Viewfields><FieldRef Name=’ID’/><FieldRef Name=’Title’/><FieldRef Name=’AssignedTo’/><FieldRef Name=’RelatedItems’/>

<FieldRef Name=’Priority’/>

<FieldRef Name=’Status’/>

<FieldRef Name=’DueDate’/>

<FieldRef Name=’Author’/>

</ViewFields>

$select $select=ID, Title, AssignedTo/Id, AssignedTo/Title, RelatedItems, Priority, Status, DueDate, Author/Id, Author/Title
CAMLQuery <OrderBy><FieldRef Name=’Created’ Ascending=’False’/></OrderBy> $filter, $orderby $orderby=Created Desc
NA $expand $expand=AssignedTo,Author

Note that in the SOAP call, I get the ID and Title (name) of each person or group column automatically when I request the column value. If I needed any more information about those people, I’d have to read it from another source, like the User Information List or User Profile. I also can specify a CAMLQueryOption that returns more of the basic information about users, like email address, SIP, etc.:

CAMLQueryOptions: "<QueryOptions><ExpandUserField>True</ExpandUserField></QueryOptions>"

In SOAP, most options that we pass go in the request payload. With REST, some of the options – for instance, what format we’d like the response to take – go in the request header.

If we don’t specify an accept parameter in the header, then we get XML in the response. If you’re used to parsing XML, then that might make you happy, but we usually want JSON these days.

To get JSON, we specify:

accept: application/json; odata=verbose

On premises in SharePoint 2013, this is the only option at the moment. In SharePoint Online (Office 365), if we don’t want all the metadata that comes along with the verbose option, we have a couple other options.

accept: application/json; odata=minimalmetadata
accept: application/json; odata=nometadata

The best way to understand the differences between these options is to try them out. When payload size matters (and it usually does), you should think about receiving less metadata to reduce the size of the responses.

References:

It’s the nuances that will trip us up. In SOAP, we can’t join lists together; we have to pull the data from each list and do the “join” on the client side. In REST we have what are called projections – using $expand – that let us do some lookups into other lists, for example to get information from a lookup list.

But back to GetListItems. Here are some examples of REST calls to get data back from a Tasks list showing some common parameter settings.

Get all tasks assigned to me

/_api/web/lists/getbytitle('Development Tasks')/items?$expand=AssignedTo&amp;$select=Title,AssignedTo/Title&amp;$filter=AssignedTo/Title eq 'Anderson, Marc'

Note that the format of your username will vary based on how you have things set up. Using an account may be a better choice, but I wanted to make the example clear.

Get all tasks that have not been completed, showing the status and the % complete

/_api/web/lists/getbytitle('Development Tasks')/items?$expand=AssignedTo&amp;$select=Title,AssignedTo/Title,Status,PercentComplete&amp;$filter=Status ne 'Completed'

Getting the data in these various ways is of course just the first step. Once you have the data, you’ll have to process it in some way in order to display it to the user, do calculations on it or whatever you’re trying to accomplish. That part of the exercise isn’t in the scope of this article, so you’ll have to look elsewhere for tricks for those pieces.

In the next article, we’ll look at how JavaScript promises come into play with SOAP and REST. I hope that you’ve been using promises with SPServices calls since I added support for them in version 2013.01, but if you haven’t, moving to REST is an excellent time to start doing so.

This article was first published on IT Unity on July 23, 2015. Visit the post there to read additional comments.

Retrieving Expanded Calendar Events with REST vs. SOAP

There is very little now in 2013 for which you need SPservices [sic]

from /r/sharepoint

It wouldn’t surprise you to hear that my answer to this is “it depends”. SPServices is nice in that it works the same way across SharePoint versions from 2007-2013, which might be enough reason to use it. But there are still cases where the SOAP services do something that REST doesn’t [yet] provide.

The other day I ran across an example of this. I wanted to pull events from a SharePoint calendar from today forward and I wanted to expand all of the recurring events. Since I was working on SharePoint 2013, I immediately tried to make this work using a REST call.

The first hurdle I faced was that it wasn’t possible to filter on a data like StartDate in a REST query. I know that sounds crazy, but if it’s possible I couldn’t find any way to do it.

The other challenge was the expansion of recurring events. It turned out that this was only possible using SOAP. REST doesn’t know anything about SharePoint calendar events, especially recurrence or all-day events.

I ended going back to an old thread in the SPServices discussions started by Jim Bob Howard (@jbhoward) which gives the CAML to make this work. The code I ended up with is below. In this case, I was using KnockoutJS to populate a customized view of multiple SharePoint calendars – the “rollup” idea. We’ve the various calendar locations stored in a list, and when we get to this code we have an array of calendars to work with.

// Calendar rollup
var calendars = [];
var events = [];
var calendarPromises = [];

// For each calendar, go and get the events
for (var i = 0; i < calendars.length; i++) {

  var thisCalendar = calendars[i];
  var today = moment().format();

  calendarPromises[i] = $().SPServices.SPGetListItemsJson({
      listName : thisCalendar.title,
      webURL : thisCalendar.listUrl,
      CAMLViewFields : "<ViewFields>" +
			  "<FieldRef Name='ID' />" +
			  "<FieldRef Name='Title' />" +
			  "<FieldRef Name='EventDate' />" +
			  "<FieldRef Name='EndDate' />" +
			  "<FieldRef Name='Location' />" +
			  "<FieldRef Name='Description' />" +
			  "<FieldRef Name='Category' />" +
			  "<FieldRef Name='fRecurrence' />" +
			  "<FieldRef Name='RecurrenceData' />" +
			  "<FieldRef Name='fAllDayEvent' />" +
		"</ViewFields>",
      CAMLQuery : "<Query>" +
			  "<Where>" +
				  "<And>" +
					  "<DateRangesOverlap>" +
						  "<FieldRef Name='EventDate' />" +
						  "<FieldRef Name='EndDate' />" +
						  "<FieldRef Name='RecurrenceID' />" +
							  "<Value Type='DateTime'>" +
							  "<Year />" +
						  "</Value>" +
					  "</DateRangesOverlap>" +
					  "<Or>" +
						  "<Eq>" +
							  "<FieldRef Name='HomePageHide' />" +
							  "<Value Type='Bool'>False</Value>" +
						  "</Eq>" +
						  "<IsNull>" +
							  "<FieldRef Name='HomePageHide' />" +
						  "</IsNull>" +
					  "</Or>" +
				  "</And>" +
			  "</Where>" +
			  "<OrderBy>" +
				  "<FieldRef Name='EventDate' />" +
			  "</OrderBy>" +
		"</Query>",
      CAMLQueryOptions : "<QueryOptions>" +
			  "<CalendarDate>" + today + "</CalendarDate>" +
			  "<ExpandRecurrence>TRUE</ExpandRecurrence>" +
			  "<RecurrenceOrderBy>TRUE</RecurrenceOrderBy>" +
			  "<ViewAttributes Scope='RecursiveAll'/>" +
		"</QueryOptions>",
      mappingOverrides : {
        "ows_fAllDayEvent" : {
          "mappedName" : "fAllDayEvent",
          "objectType" : "Boolean"
        },
        "ows_fRecurrence" : {
          "mappedName" : "fRecurrence",
          "objectType" : "Boolean"
        }
      }
    });

}

$.when.apply($, calendarPromises).then(function () {

  var calendarEvents = this;

  // For each calendar, go and get the items and push them into an array
  for (var i = 0; i < calendars.length; i++) {

    $(calendarEvents[i].data).each(function () {
      events.push({
        calendar : calendars[i].title,
        id : this.ID,
        title : this.Title,
        location : this.Location != null ? this.Location : "",
        category : this.Category,
        eventDate : moment(this.EventDate),
        endDate : this.EndDate,
        fAllDayEvent : this.fAllDayEvent,
        fRecurrence : this.fRecurrence,
        RecurrenceData : this.RecurrenceData
      });
    });

  }

  events.sort(function (a, b) {
    return a.eventDate.isAfter(b.eventDate) ? 1 : (a.eventDate.isBefore(b.eventDate) ? -1 : 0);
  });

  ko.applyBindings(new calendarViewModel(), document.getElementById("calendar-rollup"));

});

The code is written to handle a variable number of calendars (we started with four). Because I’m putting the promise for each call to GetListItems in the calendarPromises array, I can use

$.when.apply($, calendarPromises)

to ensure that all of the promises have been fulfilled before processing the results.

I’m also using the fantastic MomentJS library to work with dates and times. Don’t ever try to do that manually again.

I’d love to hear that I don’t need to use SOAP for this anymore, but this seems to be a case where SOAP still wins out. Maybe there’s a place for SPServices in 2013, after all.

SPTechCon Developer Days Follow Up

SPTechCon Dev DaysI got lucky on the scheduling for SPTechCon Developer Days and did both of my sessions on the first day. So today I get to attend sessions and just learn, learn, learn!

As is true of every conference the BZMedia folks put on, this one is well run and packed with excellent sessions. If you’d like to stay on top of what’s happening in the SharePoint world, sign up for their weekly SPTechReport newsletter.

Since this is a conference focused on developers, both my sessions were developer-focused. If you attended either session and have questions or feedback, feel free to get in touch.

Moving from SPServices to REST, Part 3: JSON vs. XML

This entry is part 3 of 4 in the series Moving from SPServices to REST

Summary: When you move from SOAP to REST, you’ll want to understand the differences between XML and JSON as well. Modern Web developers are most likely to use JSON, and this is a great time to switch.

Most auto mechanics understand that there are several different measurement systems – and therefore toolsets – that they have to use to fix up cars, whether under the hood or on the outside body. Where I sit here in the USA, it’s our unique system versus almost everyone else’s (metric). That’s sort of where we are if we’re still using SOAP and XML instead of REST and JSON.

2014 Fiat 500

Under the hood of a 1956 T-Bird by Mark Turnauckas https://flic.kr/p/f14uV8

The SOAP Web Services speak XML. That is, we send XML in our requests and we get XML in the responses. These days many developers feel those services are “chatty” and that “XML is bloated.” I’m not so sure that’s really the case, but I can go along with it.

When we receive XML in the response from a SOAP call to the server, we have to parse it apart so that we can use the data. The most common operation that people use in SPServices is GetListItems, which allows us to pull list data from the server to the client. With a call to GetListItems we get a packet back that looks something like this from a Tasks list:

call-to-getlistitems-returns-task-list-2

With the SOAP Web Services, XML is our only option. There’s no way to request anything else. REST, on the other hand, is usually used to request JSON.

To bring SPServices more into the modern way of doing things, I added a function in 0.7.1 called SPXmlToJson and then another in 2014.01 called SPGetListItemsJson. These two functions make it easy – really easy – to convert XML to JSON. You don’t have to know much about either method of storing data to get JSON back.

With REST we can still choose to get XML in the response, but we also have the option to request that the server send us JSON. Because JSON is a text representation of JavaScript objects, the conversion is much more straightforward, with just a call to $.parseJSON (assuming you’re using jQuery).

JSON is preferable because it doesn’t require much – if any – translation when we want to use it. You may already be converting the XML you get back with SPServices calls into JSON, either manually or with a call to SPXmlToJson or SPGetListItemsJson.

JSON stands for JavaScript Object Notation. It’s a way to store data in a complex, object-based JavaScript structure rather than what many of you may be used to doing with individual variables.

For example, when I get a task back from GetListItems, I could create a set of variables, like this:

var thisId = $(this).attr("ows_ID");
var thisTitle = $(this).attr("ows_Title");
var thisDueDate = $(this).attr("ows_DueDate");

When I answer questions in the SPServices Discussions, a lot of the code people post does something like this. It’s the way I used to do things, too.

With a call to REST, I get an object back that is all ready to go.

call-to-rest-gives-object-back-3

Taking it one step further, I can build a constructor function that takes the task as I get it back from a call to the server and converts it into a JSON structure of my own choosing, perhaps adding a few new properties I may need down the road:

function Task(data) {
  this.ID = data.ID;
  this.Title = data.Title;
  this.DueDate = moment(data.DueDate);
  this.Status = data.Status;
  // etc.

  this.Complete = this.Status === "Completed" ? true : false;

};

Note the conversion of the DueDate in the function above. In most of my applications these days, I use the MomentJSJavaScript library. It gives us a huge number of date- and time-oriented functions. Dealing with date/time conversions and arithmetic can be extremely messy, and MomentJS makes it easy. So rather than simply storing the text-based value of DueDate that I get back in the XML or JSON from a call, I store the DueDate converted into a “moment,” which is the lingua franca to use MomentJS’s helpful functions.

In the code examples above, I’ve gone from the rather brute force method I used to use where I used a lot of individual variables, to using a JSON representation, to using a constructor function to “build” each task from the results of a call. The first two of these methods require basically the same amount of code, but the second is far easier to work with when we pass the task back out to whatever code we want to work with it next. The third approach, while it introduces yet another level of abstraction, gives us even more flexibility, as we can decide to add a new element to any tasks inside the constructor function and it will be available in tasks everywhere.

Using SPXmlToJson and SPGetListItemsJson is another way to move your code forward without actually converting to the REST services right away, say if you are still on SharePoint 2007 or 2010. In fact, one of the main reasons I wrote these two functions was so that I could start working with JSON in a project on SharePoint 2007 using KnockoutJS. Yes, you can use the tools and frameworks all the cool kids are using even on ancient platforms.

In Part 2, I outlined a way for you to think about abstracting your CRUD calls using SPServices so that you could slide REST underneath at a later point. By using the two XML to JSON capabilities in SPServices, you can also start returning JSON to your applications from those abstractions, taking yourself one step closer to REST.

There are a few caveats here. I didn’t try to match the JSON formats that the SharePoint 2013 REST services return when I built my functions, though the way I hand you the data are similar. Similar doesn’t mean the same, of course.

Here’s an example. When you request list items using SPGetListItemsJson and don’t provide any custom mapping of your own, SPUser fields, which are also known as Person or Group columns, are returned in a JSON object that looks like this:

request-list-items-using-spgetlistitemsjson-returns-json-object-4

If you make a REST call to SharePoint 2013, SPUser fields are returned in a JSON object that looks like this, assuming you have requested the Id and Title using a projection (more on this in a future article in the series):

spuser-fields-returned-in-json-object-5

As you can see, there are some naming and formatting differences. I return “userId” and the REST call returns “Id”, for instance. In my opinion those differences are manageable, but it will take some work when you switch to REST because your application code will expect things in the format that SPGetListItemsJson provides. This is another reason why constructor functions can be helpful: they give us a place to do the isomorphic mapping from one data representation to another.

The upshot here is that you can:

  1. Abstract your CRUD operations as in Part 2, and
  2. Return JSON to your application rather than XML

As before, your application shouldn’t care where the data lives, how it’s stored or how we get it; it should only care about processing data that has a consistent format.

If you follow these suggestions, your code might go from something like this inline request:

var p = $().SPServices({
  operation: "GetListItems",
  ListName: "Tasks",
  CAMLViewFields: "<ViewFields>" +
                "<FieldRef Name='Title'/>" +
                "<FieldRef Name='AssignedTo'/>" +
                "<FieldRef Name='RelatedItems'/>" +
                "<FieldRef Name='Priority'/>" +
                "<FieldRef Name='Status'/>" +
                "<FieldRef Name='DueDate'/>" +
                "<FieldRef Name='Author'/>" +
                "</ViewFields>"
});

To this abstracted request:

// Get all the Tasks data
ProjectName.Promises.Tasks = $().ProjectName.Tasks.readAll();

// Read items from the Tasks list
$.fn.ProjectName.Tasks.readAll = function(options) {

  var opt = $.extend({}, {}, $.fn. ProjectName.defaults, options);
  var p = $().SPServices({
    operation: "GetListItems",
    ListName: "Tasks",
    CAMLViewFields: "<ViewFields>" +
        "<FieldRef Name='Title'/>" +
        "<FieldRef Name='AssignedTo'/>" +
        "<FieldRef Name='RelatedItems'/>" +
        "<FieldRef Name='Priority'/>" +
        "<FieldRef Name='Status'/>" +
        "<FieldRef Name='DueDate'/>" +
        "<FieldRef Name='Author'/>" +
      "</ViewFields>"
  });

  return p;

}; // End $.fn. ProjectName.Tasks.readAll

To this abstracted JSON-based request:

// Get all the Tasks data
ProjectName.Promises.Tasks = $().ProjectName.Tasks.readAll();

// Read items from the Tasks list
$.fn.ProjectName.Tasks.readAll = function(options) {

  var opt = $.extend({}, {}, $.fn. ProjectName.defaults, options);
  var p = $().SPServices.SPGetListItemsJson({
        listName: opt.TasksList,
        CAMLViewFields: opt.TasksListViewFields,
        CAMLQuery: camlQuery,
        CAMLQueryOptions: opt.TasksListQueryOptions,
        mappingOverrides: opt.TasksListMappingOverrides,
        changeToken: opt.changeToken
  });

  return p;

}; // End $.fn. ProjectName.Tasks.readAll

“Hold on here,” you might say. “That’s more code than I was writing before!” Absolutely true. And if you have a little snippet in a Content Editor Web Part (CEWP) that just reads a few items from a list and that’s it, then this effort might not be worth it. However, if you are building Single Page Applications (SPAs) or even little “portlets” for use throughout your Site Collection(s), it may make total sense.

For instance, if you have a customized Tasks or Announcements list in every Team Site that you are reading from and writing to, then abstracting those calls and storing them centrally may be a great idea. I do this sort of thing all the time. I load my data access operations into the master page in the Site Collection and then use them reliably from subsite to subsite. If you’re working on a larger team – which I tend not to do – it will require coordination, but it will also give you the ability to parse out atomic programming tasks across your team. Maybe one person is really good at data access and another is really good at HTML and CSS. This approach lets you parse out the work based on everyone’s skills and interests.

But I digress. The goal of this series is to help you move from SOAP to REST over time, not reorganize the roles on your team. Hopefully you can see that taking a few of these steps now or when you begin your next project, you’ll be putting yourself in a better position for the long run. These approaches may not help with everything you are using SOAP to accomplish – the SOAP services still cover more surface area than CSOM or REST, though that is changing – but it will put your most frequently-used sections of code in a good spot when it is time to move to REST.

Those auto mechanics know that there isn’t a huge difference between using a metric spanner and an Imperial wrench (other than getting everyone to agree on the terminology). XML and JSON are just dialects or different systems that accomplish basically the same thing: wrapping data up in packets that can be deciphered easily on the other end.

This article was first published on IT Unity on April 17, 2015. Visit the post there to read additional comments.