Extending phpScheduleIt : Getting started with the API

One of the big features we introduced in 2.4 was a RESTful API for integrating with phpScheduleIt. This is disabled by default but can be flipped on just by changing the config setting $conf['settings']['api']['enabled'] to 'true'. Once you do that, navigate to the auto-generated documentation page at http://your_phpscheduleit_root/Web/Services/index.php (if you’ve got mod_rewrite set up with Apache, you won’t need ‘index.php’) and take a look at everything that’s available.

Each service description contains some important information. You’ll see if the method is invoked via GET, POST or DELETE. You’ll also see:

Name  – This is the name of the service endpoint and the URL segment to use.
Description – A brief description of what the service does and any optional parameters.
Route – The full route and variables needed to invoke this endpoint. Any portion that begins with a : denotes a variable that must be provided. Pay attention to any trailing slashes – those are required when specified.
Response – An example JSON response (if applicable).
Request – An example JSON request (if applicable).

You’ll notice that all requests/responses are in JSON. In this post we’ll use jQuery to authenticate, list our reservations, and update a reservation. It’s important to remember that you cannot POST JSON data cross domain with JavaScript. So if you want to use this method you’ll need to run it from the same domain as your phpScheduleIt instance.

Authenticating

Just like the web front end, most of the services that the API exposes require an authenticated session. The documentation will note whether or not a service is secure or not. So step one will be to get a session token to use for subsequent calls.

Here’s our authentication fragment. It’s pretty simple, really. We POST the username and password to the Authentication/Authenticate service, then store the sessionToken and userId that we get back. We’ll just pop up and alert if the authenticate call fails.

 $.ajax(
{
	type: "POST",
	url: self.baseUrl + "Authentication/Authenticate",
	data: JSON.stringify({username: self.username(), password: self.password()}),
	dataType: "json"
})
.done(function (data)
{
	if (data.isAuthenticated)
	{
		self.token(data.sessionToken);
		self.userId(data.userId);
		self.headers = {"X-phpScheduleIt-SessionToken": data.sessionToken, "X-phpScheduleIt-UserId": data.userId}
		self.authenticated(true);
	}
	else
	{
		alert(data.message);
	}
});

Finding Our Reservations

Now that we have a session established we have all the rights and privileges of that user. We’ll start off by getting a list of our reservations. By default, this will get all of the reservations for the authenticated user in the next two weeks. This is a simple GET request to Reservations/. The important part is that we attach the headers to this request.

$.ajax(
{
	type: "GET",
	url: parent.baseUrl + "Reservations/",
	headers: parent.headers,
	dataType: "json"
})
.done(function (data)
{
	self.reservations.removeAll();

	$.each(data.reservations, function (idx, val)
	{
		self.reservations.push(new ReservationItemViewModel(val, parent));
	});
});

Updating A Reservation

Alright, that was almost too easy so far – let’s get into the nitty gritty. Create and update calls require a full object to be posted. To do that, we’ll first need to load the reservation and map it into a request object. This one is a little more involved, so I’ll walk you through it.

First, we make a GET request to Reservations/:referenceNumber with the reference number of the reservation that we want to update. Next, we walk through the response object and convert it into a request object. Most of this is straightforward. You may be asking why we’re calling $.map for the array objects. This is because the request object needs a different object structure than what what we currently have. So we’re just looping through each one and converting the item into the format needed for the request.

$.ajax(
{
	type: "GET",
	url: parent.baseUrl + "Reservations/" + reservationItem.referenceNumber(),
	headers: parent.headers,
	dataType: "json"
})
.done(function (data)
{
	existingReservation = data;
})
.then(function ()
{
	var request = {		
		accessories: $.map(existingReservation.accessories, function (n)
		{
			return {accessoryId: n.id, quantityRequested: n.quantityReserved };
		}),
		customAttributes: $.map(existingReservation.customAttributes, function (n)
		{
			return {attributeId: n.id, attributeValue: n.value};
		}),
		endDateTime: existingReservation.endDateTime,
		invitees: $.map(existingReservation.invitees, function (n)
		{
			return n.userId;
		}),
		participants: $.map(existingReservation.participants, function (n)
		{
			return n.userId;
		}),
		recurrenceRule: existingReservation.recurrenceRule,
		resourceId: existingReservation.resourceId,
		resources: $.map(existingReservation.resources, function (n)
		{
			return n.id;
		}),

		startDateTime: existingReservation.startDateTime,
		title: existingReservation.title,
		userId: existingReservation.userId,
		startReminder: existingReservation.startReminder,
		endReminder: existingReservation.endReminder
	};
	self.UpdateReservation(request, reservationItem);
}
);

We then make any changes we want (in this case, just updating the description) and issue the update. If we get an error during the update call we’ll display it. The error messages will be the same ones we get when we have a problem saving a reservation from the web. Expect to see messages like missing required fields, invalid dates, or conflicting reservations.

request.description = reservationItem.description();
$.ajax(
{
	type: "POST",
	url: parent.baseUrl + "Reservations/" + reservationItem.referenceNumber(),
	headers: parent.headers,
	dataType: "json",
	data: JSON.stringify(request)
}
)
.done(function (data)
{
	console.log("Update response message: " + data.message);

	self.LoadReservations();

}).fail(function (data)
{
	reservationItem.saveErrors(data.responseJSON.errors);
})

Putting It Together

Here’s the full example. Full Example Code – You’ll need to View Source and save this file locally.

3 comments:

Leave a Reply

Your email address will not be published. Required fields are marked *