3. Implementing the API
3.1 Choose a dispatching approach
A dispatching approach refers to where remote callers will send their invocation messages (endpoint URLs), and how the method invocation is routed to the final object that implements the method.
See the Third Party Clients section for specifics on the endpoint URLs.
Regarding dispatching, there are three approaches to choose from.
Direct
This approach attaches the API definition class directly to a controller, and defines the API method implementations in the controller as public instance methods. This is the default approach.
This approach can only implement one API per controller, and thus, only one API for a unique endpoint URL.
Overview of Direct dispatching

Delegated
This approach defines the API method implementations in an ActionWebService::Base derived class, connected to a service name in a controller.
This approach also requires that the controller be configured to run in Delegated dispatching mode.
It allows multiple APIs to be handled by a single controller, but still uses a unique endpoint URL per attached service.
In the overview below, /api/blog and /api/person are the unique endpoint URLs.
Overview of Delegated dispatching

Layered
This approach resembles Delegated in that multiple APIs are implemented by one controller.
There is one important difference with this approach:
All attached services are callable via a single endpoint URL, and a protocol-specific mechanism is used to route to the appropriate service.
Overview of Layered dispatching

The protocol specific mechanisms clients will use are as follows:
| SOAP | The SOAPAction HTTP header will contain the relevant service name |
| XML-RPC | The method name is prefixed with a name that should match the service name declared with #web_service in the controller |
For example, an XML-RPC method with a name in the XML-RPC message of blogger.newPost would be sent to the :blogger service in the controller as newPost.
3.2 Direct dispatching
If you decide on the Direct dispatching approach, this is what you have to do:
- Attach the API definition to the controller using
#web_service_api - Define all API methods as public instance methods of the controller
Example
class PersonAPI < ActionWebService::API::Base
api_method :new_person, :expects => [{:firstname=>:string}, {:lastname=>:string}], :returns => [Person]
end
class PersonController < ApplicationController
web_service_api PersonAPI
def new_person(firstname, lastname)
person = Person.new('firstname' => firstname, 'lastname' => lastname)
person.save
person
end
end
With this example, remote callers can now call a NewPerson web services method on the PersonController using either SOAP or XML-RPC. The return value received by the caller will be a protocol structured type containing the same fields as the Person ActiveRecord model object.
In the above example, the #web_service_api call could also have been omitted if the PersonAPI definition was moved to a file named app/apis/person_api.rb in the Rails project, as each direct mode controller can have a default associated API.
Both Direct and Delegated dispatching use the same API definition class.
3.3 Delegated dispatching
For the Delegated dispatching approach, this is what you have to do:
- Create an API service class for each API. This class must be derived from
ActionWebService::Base. - Attach the API definition to the service class using
#web_service_api - Define all API methods as public instance methods of the service class
- Switch the controller to Delegated dispatching mode using
#web_service_dispatching_mode - Attach the service class to a controller using
#web_service
Example
class PersonAPI < ActionWebService::API::Base
api_method :new_person, :expects => [{:firstname=>:string}, {:lastname=>:string}], :returns => [Person]
end
class PersonService < ActionWebService::Base
web_service_api PersonAPI
def new_person(firstname, lastname)
person = Person.new('firstname' => firstname, 'lastname' => lastname)
person.save
person
end
end
class ApiController < ApplicationController
web_service_dispatching_mode :delegated
web_service :person, PersonService.new
end
With this example, remote callers can now call a NewPerson web services method on the ApiController using either SOAP or XML-RPC, and the request will be forwarded on to the service object.
If instantiating the service class at class definition time does not suit your needs, instantiation can be deferred to request time by passing a block as the second parameter. The return value of the block will be used as the service class instance.
Example
class ApiController < ApplicationController
web_service_dispatching_mode :delegated
web_service(:person) { PersonService.new }
end
The block will have access to the instance variables of the controller (so you could, for example, set some instance variables using an Action Controller before_filter for the :person action).
3.4 Layered dispatching
For the Layered dispatching approach, this is what you have to do:
- Create an API service class for each API. This class must be derived from
ActionWebService::Base. - Attach the API definition to the service class using
#web_service_api - Define all API methods as public instance methods of the service class
- Switch the controller to Layered dispatching mode using
#web_service_dispatching_mode - Attach the service class to a controller using
#web_service
Each method invocation request received will be expected to contain a prefix identifying the service object it is destined for, in the format prefix.methodname.
Example
class PersonAPI < ActionWebService::API::Base
api_method :new_person, :expects => [{:firstname=>:string}, {:lastname=>:string}], :returns => [Person]
end
class PersonService < ActionWebService::Base
web_service_api PersonAPI
def new_person(firstname, lastname)
person = Person.new('firstname' => firstname, 'lastname' => lastname)
person.save
person
end
end
class ApiController < ApplicationController
web_service_dispatching_mode :layered
web_service :person, PersonService.new
end
With this example, remote callers can now call a person.NewPerson web services method on the ApiController using either XML-RPC, and the request will be forwarded on to the :person service object.
As with Delegated dispatching mode, service object instantiation can be deferred to request time.