fromSeptember 2014
Feature:

Getting Started With Services Using Views

Two Ways to GET Your Views in JSON Via REST
0

Photo of people on bench With Views, we build structured components of our content that are placed on a page. HTML or formatters are applied at will, CSS classes are added as needed, and the component is most likely placed on a page somewhere and styled. And it’s gorgeous.

But you want more. You want that carefully crafted component to show up on that page with blazing speed, powered by the awesome Javascript flavor-of-the-year framework you’ve been using. You need that component in JSON. And you need it now.

Well, I have good news and better news. There are two ways to expose your Views as JSON (or XML, or other formats, but I’m going to focus on JSON in this article). One method allows you to retrieve your existing views through a REST server, and the other method lets you add a Services display in a View, which allows for finer-grained control of the JSON output. You may actually end up liking the second method better, even if you do have to add some new displays.

To start, let’s get some modules installed and a REST server up and running.

Huh? What Is A REST Server Again?

All you need to know here is that we’re going to allow someone (who knows, maybe you?) to access Views results as JSON data, by issuing a GET request. GET is the HTTP method that you can use with query strings in the URL. You know query strings, right? It starts with a question mark and then you string more than one query together with an ampersand, kinda like this:

http://local/api/v1/articles?term_id=7&type=article
  1. Download the Services module. This project requires Chaos Tools (CTools) and the Libraries module for the REST server. Enable Chaos Tools, Services, Libraries, and REST Server modules.
  2. Download the Services Views module. You will also need Views and the Views UI modules enabled; they are available in the Views project. Enable Views, Views UI, and Services Views.
  3. Download the Services Tools module and enable the Services Definitions module. This module adds the Definitions tab to the Services interface and provides essential documentation about how to access our Views resources.

Now let’s create an endpoint. You’re not going to point and click your way to this data, you’re going to GET it, in the HTTP sort of way, and you need a URL to GET. You’ll probably only need one endpoint for your site, so you’ll likely only need to do this once.

  1. Go to Structure, then click on Services.
  2. In Services, click Add + to enter a new endpoint.
  3. Enter a machine-readable name for the endpoint. For this example, I just used demoapi.
  4. Select REST as the Server.
  5. Enter a path to this endpoint. We’re entering a path that will prefix all your GET requests. We do this so that our API has a nice little namespace to play in and will be less likely to conflict with other paths in our Drupal site. Do your future self – and anyone else accessing this API – a favor and enter a version number in your path. That way you can change your resources later without confounding yourself and others. I’ll just call this path api/v1, but you can enter whatever makes sense for your situation.
  6. I skipped the Debug mode. (Don’t check it unless you need it.)
  7. I’m also skipping Authentication and leaving Session authentication (my only installed authentication method) unchecked. Look elsewhere for guidance in this realm. (See “Protecting Your Drupal 8 Resources.”)
  8. Save.

Add a new endpoint

Okay, that’s all we need for the moment from Services. Let’s head over to Views and create a view of Articles in a Block display. (If you want to play along on a Drupal 7 local install, go ahead and download Devel and generate some terms for the Tags vocabulary and generate some Articles and Basic Pages for the site. That way we’ll have some data to work with in Views.)

  1. Go to Structure, then click on Views.
  2. Click the link Add a new view.
  3. Enter a view name of “articles.” (The machine name will be important in a moment.)
  4. Show Content of type Articles (make sure Content and type: Articles are selected from the drop-down).
  5. Uncheck Create a page.
  6. Check Create a block. The defaults are fine here.
  7. Save and Exit.

With this view and its block display created, let’s move over to Services. Head to Structure in the admin menu, then click on Services. Next to your endpoint, click on Edit Resources. With the Views Services module enabled, we have a new potential resource to enable: views! Scroll all the way to the bottom of the Resources tab and click on views to reveal the available operations. There’s only one. Check retrieve which retrieves the data of a view, and click Save.

Yes, but how do we retrieve it? We’ve installed our handy Services Tools module and enabled the Services Definitions module. So now click on the Definitions tab and scroll to the bottom to view the documentation for how to retrieve this view. Under Views, the operation is listed along with the HTTP verb for actually performing the operation – in our case GET – and the URL for how to retrieve a view.

Views service URLs

GET : http://example.com/api/v1/views/{VIEW_NAME}

{VIEW_NAME} is a placeholder which we’ll replace with the machine name of the view we just created, articles. So the URL in this case would be:

GET : http://example.com/api/v1/views/articles

I’ve installed and enabled the Chrome extension Chrome REST Console (version 4.0.2) so that I can see my requests nicely formatted, and it’s a bit easier to peruse the data I get back.

In the Chrome REST Console, in the Target section, I’ll enter as the Request URI: http://example.com/api/v1/views/articles. Select GET as the Request Method. Under Accept, enter application/json so that we can get JSON in return. At the very bottom of the window, there’s a sticky footer with a line of submit buttons.

Request target

Click on GET and the Console will scroll you down to the Response section where you can see the returned JSON data from your Views block display. Notice the backslashes on the node titles. Could be messy to deal with.

Request response

Can we improve this with cleaner output? We can, with a Services display in Views.

Creating a Services Display in Views

The Services Views module enables us to to do two things: expose a view we already have as a web service resource, or create a new Services display of a view that provides us with some formatting options for both keys and values of the returned structured data. In this second method, we’re going to create a new view with just a Services display. (You can create a Services display in any existing View, but for now, I’m going to create a separate view to distinguish it from the other Views resource we’ve already enabled in Services.)

Alright, head back over to Structure » Views and add a new view. Give it the machine name of
services_articles and make sure both the create a page and create block options are unchecked. Click Continue and Edit.

Add a Services display: Next to the Master display, click the Add button to reveal a list of display options and select Services. The new display label will have a bold red border and a warning message until we add a path.

Adding a services display

Add a path in the Services settings in the middle column of the view by clicking the forward-slash next to Path. Enter a path fragment. This will be the part of the path after the server name and the endpoint path that we set up earlier. I’ve given this path a name of articles.
To demonstrate the field formatter that Services Views provides in a Services display, let’s add a Body field to this views fields. (Click add next to fields, search for “Body” and add Content: Body and click Apply (all displays).)

Instead of a label, we can “Set custom value key,” which is the array key in our structured JSON data. I’ll change “Body” to lowercase and underscore (not spaces or dashes) field_body. For the Formatter, I’ll select Services Raw instead of the default. With Services Raw selected as a formatter, I could also choose to skip safe values and skip empty values. I’ll leave it to you to decide if you want to enable those options.

Configure body field

Go ahead and save the view and let’s saunter back to Structure » Services. Now when you click Edit Resources and view this list, instead of scrolling down to the Views section, you’ll see the path name of the Services display listed alphabetically alongside the rest of the resources, which in our case is articles. Click on articles to reveal the CRUD operations and check the box next to index (View: services_articles).

Click Save.

With this new resource enabled, click on the Definitions tab and scroll down to find ARTICLES (again, not under “views” but under the name of the resource, which will be the name of the path entered in the Services display of the view).

It lists the operation (Index), the name of the view (services_articles), the HTTP method to access it (GET), and the URL. Copy and paste that URL into the Request URI field in the Chrome REST Console (keep all the same options you used previously, just update the URI) and click the GET button.

You can see that we have a clean value for node_title, and no <a> tags cluttering up the raw value of the title. Also, our custom key field_body has replaced the Body label that otherwise would have output as the key for the Body field that we added to the Services display.

Adding Exposed Filters

This is a great start, but we can take things a step further – by adding query strings to our GET request – and tap into any exposed filters we’ve added to our view. Again, there are two completely different ways to do this, depending on which method was used to expose the view as a resource in the first place.

The documentation for which query strings are meaningful for the first method, retrieving existing views, are located in the Definitions tab, when you Edit Resources of your endpoint. There are a number of query string parameters you may tack on to your URL, including args, offset, limit, format_output, and filters. To access an exposed filter on a view using the “retrieve” operation, we’ll use the filters parameter. First, let’s add an exposed filter to the Block display of the view we set up in the beginning. I’ll simply add a filter for Type of content.

In the Block display of the view, click on add next to Filter Criteria and search for Type. Add Content: Type and click Apply (all displays). Next, check the box to Expose this filter to visitors… What we’ll really be doing is exposing this filter to our GET request, allowing us to filter our view with the query string on the URL. Change the label from Type to lowercase type. Now, scroll down a bit and expand the More section. Ensure that your filter identifier is type. Click Apply (all displays) and save the view.

Over in the Definitions tab, under the Views section and the Retrieve operation, I can see that to access filters, I need to use the following format for my query string: Example call: /views/your_view?filters[nid]=12345

My filter identifier is type, so I would replace nid in the above example with type. I will also use the appropriate paths for my application, so that my call will be: <a href="http://local/api/v1/views/articles?filters[type]=article">http://local/api/v1/views/articles?filters[type]=article[/geshifilter-code]

In the Chrome REST Console, enter the URL with the query string into the Request URI field. You can experiment with changing the value of [type] to be page or article and note the difference in results.

For the view with the services display, the format of the query string will be different. Instead of an array of filters, like we have above, (filters[type]=article), we simply use filter identifier as the key. So, given that our resource name is articles and we added an exposed filter to the services display with the identifier type, the URI would be: <a href="http://local/api/v1/articles?type=article">http://local/api/v1/articles?type=article[/geshifilter-code]

The key to success with the exposed filters is checking in on that hidden More section in the exposed filter criterion. With exposed filters, we’re not using the label as the key in the query string; we have to use the filter identifier, which is hiding away in that hidden-by-default More section of the filter. If you’re having trouble getting your exposed filter to work, double check to make sure you’re not using the label, but the filter identifier.

Filter identifier

So, now you have two methods for getting your views components as JSON. With both methods, query strings may be added to the GET request URI, and any exposed filters added to the view can be accessed – albeit, in two different ways. The Chrome REST plugin was used to test the GET requests and by accepting application/json, we were able to get a response in JSON format.

One final tip: if you want to limit how your data is returned, click Edit Resources on your endpoint, and click on the Server tab. You can uncheck any response formatters you don’t want to enable.

Now, go on, and get yourself some views in JSON.

Image: "Couple on a Bench in front of The Huc Bridge on Hoan Kiem Lake - Hanoi, Vietnam" by ChrisGoldNY is licensed under CC BY-NC 2.0