Proposed Web Service Clients module: Preparing the way for external fields

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

At the recent Data Architecture Design Sprint, participants outlined a development path in which fields can be local or external. A given entity instance (node, user, etc.) can be fully local, fully external, or a combination of the two. For example, a node can have several fields stored and handled in a local SQL database and other fields both loaded from and written to an external SOAP service.

As steps on this path, we outlined (a) short term changes to CCK, (b) a minimal patch to integrate CCK into core, and (c) some follow-up steps, like deciding on a consistent data structure for all entity types, to be followed by a unified set of methods for all entity types (e.g, drupal_save($entity_type, $entity)).

Are there short term steps we can (should?) take now toward external data source support? Here is a rough, conceptual attempt to sketch out such steps in the form of a proposed contrib module, Web Service Clients, taking the existing Services module as a model to work from.

Services module: a model for external data source support

In D5 contrib, a services module was developed to enable standardized development of Drupal as a web services platform. Documentation: http://drupal.org/node/109782, project: http://drupal.org/project/services. Services implements a pluggable architecture in which various types of servers (XMLRPC, SOAP) can be implemented, drawing on a common set of services. Services here are sets of available methods, e.g., node load and user save. Through services, a Drupal site can respond to external requests, providing read/write access to locally stored data.

Clients module: web service clients modelled on Services

Services provides external read/write access to locally stored data. We need the parallel set of implementations: local read/write access to external data sources (via web services).

Parallel to the Services module's pluggable server, we need a set of pluggable server types--but as clients rather than servers. In short, we need a Web Service Clients module (Clients for short).

A minimal initial target spec for this module might be:

  • Using XMLRPC (the one server plugin bundled with Services module; there are others in contrib), implement a client such that a Drupal site running Clients can meet the following use cases:
    1. User can create and update a node that has two fields from an external site running Services' XMLRPC server. On create and update, those fields are not saved locally but instead are saved to the remote service. On load, fields are loaded from the remote service.
    2. Whenever a user record is updated locally, a call is sent to a remote service notifying of the update operation. This enables a remote service to store/track a user's ID and associated email address on the Drupal instance.

Solution components:

  • Generic handlers (in clients.module): shared methods
  • Pluggable services: services supported, e.g., XMLRPC
  • Pluggable methods: local methods for handling data operations
  • Client instances: data unique to specific client instances

Generic handlers

Generic handlers and methods, including:

  • Connecting to external services.
  • UI for admin-defined client instances.

Pluggable services

Example: generic SOAP support.

Each service includes methods for:

  • authentication
  • deriving schema information about external data sources

Pluggable methods

Define in metadata form a common set of local methods and their expected data formats and return values. Examples:

  • entity_find: given an array of properties and values, return an array of matching entity IDs.
  • entity_load: given an entity id, return an entity instance
  • entity_save: given an entity instance, save to the remote service and return a result code
  • field_load: given an entity id and a field name, return the value of that field for the given entity
  • field_save: given an entity id, field name, and field value, save the field to that entity and return a result code

Alternately, we could implement the same set of methods as are available in Services module (see the services plugins), but these may tend to be too specific to the Drupal environment and so to map poorly to external web services.

Client instances

Example: SOAP client to a particular SOAP service.

A client instance may override generic methods for its service type.

Each client instance includes handling and methods for:

  • Mapping available external request methods to the set of local methods. For example, fed a field_load call, translate this into a call to save data to a remote SOAP service. (Each client instance will implement only a subset of the available local methods.)

Nodeapi and CCK integration

To locally present and edit data from external sources, we need the ability to represent and integrate those data locally.

CCK provides our richest set of applicable tools, and is in any case our proposed long term solution. How therefore can we leverage CCK fields in 5.x or 6.x to provide handling for external fields?

Proposed implementation:

One-to-one mapping between external data fields and local CCK fields, with the CCK field handling overridden for CRUD operations.

  • For each external field, site admin defines a CCK field and attaches it to one or more content types.
  • Clients module provides additional UI element in field definition to select external field to map this field to.
  • In hook_nodeapi() load op, Clients module overrides CCK field handling, inserting externally-derived data in place of local ones (which will be empty, as there are no locally stored data).
  • In hook_nodeapi() insert, update, and delete ops, Clients module dispatches calls to external web service for fields it is responsible for.

Actions

As well as field-level handling, we need methods to invoke actions based on given state changes. In the above use case #2, this included responding to a user save operation by sending a notification to an external service.

Here we can build off of Actions, particularly the hook operation support in D6.

  • Client method implementations (particular local methods, e.g., entity_save, that are implemented by a specific client, e.g., a Gazetteer SOAP service) may declare the 'hooks' operations they support, using the same format as used for actions metadata.
  • These methods are programmatically exposed as actions with associated hooks, to be called as appropriate, receiving in argument form the relevant data structure (e.g., a user object).

Summary

By developing genericized, fields-aware web service client support, we can both provide short term functionality for D5 and D6 and begin concretely to map out long term solutions for core.

After getting our minimal CCK fields into core, we could turn to minimally bringing the Services module and (assuming some solid development by then) accompanying Clients module into core as well.

Does this approach seem to make sense? What considerations are missing? Please comment on or edit up this Wiki page.

[Note: I'm hoping to be able to begin coding a draft Clients module within a week or two for an upcoming client contract.--Nedjo]

Comments

Comments now enabled

nedjo's picture

Comments are now enabled on this page (thanks Angie!).

Wow sounds great! I really

tjholowaychuk's picture

Wow sounds great! I really love the abstraction I think that is a great leap to take. The external fields sound really interesting too, could you post some use-case scenarios for this?

vision media
350designs

Have you seen what is going

Yes, interesting

nedjo's picture

I'm not sure as yet what the relationship is. I'll study the RDF work a bit more....

Services and Drupal 7

RobLoach's picture

Here are some things to think about when implementing Services in Drupal 7:

Data API
Abstract the way Drupal looks at data. This is related to web services as services would be responsible for displaying this data in any given way (JSON, REST, HTML, etc).
Registry
Having the registry only use parts of the Drupal bootstrap when using some loading is essential. A load of the complete bootstrap can hurt performance when only parts are required.
PHP 5
Now that Drupal 7 will only support PHP 5, what can it do for us? One example of a benefit is having the SOAP support in PHP5 (even though it would probably be part of contrib).

Do you have the list of

julma's picture

Do you have the list of current drupal modules that can be seen as kind of "web service client" ?

load a node from a web service

AlessMascherpa's picture

Hello to every body.

My name is Alessandro Mascherpa and I´m just starting to build a site with drupal 6 that will need to load data from a soap web service; and then administer the data backwards with rpc methods.

When I first find this information about clients module I thougt It was going to feet perfectly my needs and the job was going to be "easy". Then I found that clients module seems to be build directly for drupal 7, and I am steel searching for a solution to my problem.

The I saw a post from Robert Douglass in "http://www.mattfarina.com/2008/01/08/drupal-without-nodes" talking about the "proxy-node pattern where you generated nodes to represent the legacy data". It sounds like it could solve part of my problem.

I´ll be very pleased if somebody could give me more information about this topic (or give some orientation). Or if you now other ways to load data from a web service into a Drupal node.

Thanks in advance!

Not sure what you need to do

robertDouglass's picture

Please clarify a couple things you're trying to do:

  • "load data from a soap web service; and then administer the data backwards with rpc methods." What do you mean exactly? I'm having a hard time knowing what you're doing.
  • I don't know for sure if you really need nodes for your foreign objects. You'll have to really justify the overhead before you know it's worth it. Please provide more details.

Hi Robert, thanks for

AlessMascherpa's picture

Hi Robert,

thanks for replying so quickly.

To better explain my needs can be done wiyh the following phrase from the upper clients module specification "We need the parallel set of implementations: local read/write access to external data sources (via web services)."

We allready found how to contact the web service with the soap client module to retrieve data and invoque rpc. The problem now is to administer the web service data from the Drupal UI and load data from the web service into durpal nodes.

I'm not sure if we really need nodes, and with some data I'm sure that it's not going to be needed. But for the main data, which are hotels, we need to show them in page and in teaser mode, for that I thougt that this could be done easier using nodes, becouse their native functionality and that well made easier to administer this data.
For other data I found the lullabot scaffolding module which will do very well.

I other words, I don´t know the better way to load data in nodes. I know that it can be done by hook nodeapi. But, what if I don't have nid?

Besides my problem, I will be thankfull if you can explain something more about "proxy-node pattern where you generated nodes to represent the legacy data".

Thank you in advance, and forgive my english, I know it can be making it a bit tough.
Alessandro Mascherpa.

Creating nodes

robertDouglass's picture

Hi Alessandro,

read here for a guide for creating nodes programmatically: http://civicactions.com/blog/cck_import_and_update

The "proxy node" pattern simply means that you have a node for every foreign object. You might have to have an extra table to keep track of the foreign object's primary id. It would be possible to use CCK for this and fill it in using the node creation technique above. Then you can use hook_nodeapi to detect changes in the node and send them to the foreign database via SOAP.

You usually only make nodes if you need some of the things that nodes can do: comments, revision control, CCK fields, Views integration.

In the right way

AlessMascherpa's picture

Hi Robert,

I really think, and hope not being mistaken, that I'm in the rigth way to solve my problem.

I found your reference a bit difficult to understand, but I'll give it a bit of time get it better. Througt it I found the following article by Jeff Eaton: http://www.lullabot.com/articles/quick_and_dirty_cck_imports

With it and your last post I think to be able to solve my problem. I promise to come back when it's done (if everything went rigth) so my experience can serve to somebody else (if somebody else find himself in such a weird situation).

I'm so grateful for all your help, and I just would like to give it some day in return.

Regards,
Alessandro Mascherpa.

Services

Group organizers

Group categories

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: