[commits] [Wiki] created: Project/HordeApiRewrite

Ralf Lang (B1 Systems GmbH) lang at b1-systems.de
Thu Oct 19 12:24:17 UTC 2017


rlang  Thu, 19 Oct 2017 12:24:17 +0000

Created page: https://wiki.horde.org/Project/HordeApiRewrite

[[toc]]

+ Project Name

Project to rewrite parts of Horde_Rpc and the Horde Core Registry  
inter-app API for a new major release

++ Bugs

List any tickets on http://bugs.horde.org/ that cover this issue or  
are relevant to it.

++ People

Ralf Lang

++ Description

Main Design Goals:

- Facilitate mapping of free form URIs to API calls (for REST)
- Facilitate customizing/amending APIs by administrator/downstream
- Allow passing PHP Objects when using the API internally -> Need a  
defined way to fold them to array/scalar representations on RPC
- Allow separate authentication mechanisms for external calls (REST,  
RPC) like using API keys, even limiting them.
- Allow unauthenticated usage of select RPC API calls.
- Ability for administrators to turn off remote access to some APIs
- Avoid boilerplate inside Api method implementation
- Little or no setup for default case
- Allow but don't require versioning
- keep code upgrade costs from H5 to H6 reasonable

Side Goal:
- Allow routing API calls to external horde instances


++ Current H5 API

API routing

An API is a named collection of methods

H5 registry allows to route an API to an app and to override this  
decision for certain methods
For example, ingo is the default target for "filter" api and the  
defined target for certain methods of the "mail" api, which defaults  
to imp

         'provides' => array(
             'filter',
             'mail/blacklistFrom',
             'mail/showBlacklist',
             'mail/whitelistFrom',
             'mail/showWhitelist',
             'mail/applyFilters',
             'mail/canApplyFilters',
             'mail/showFilters',
             'mail/newEmailFilter'
         ),

However, currently an App cannot provide separate implementations for  
the same method name in different APIs. Calling filter/newEmailFilter  
would yield the mail/newEmailFilter method due to all methods being  
part of one collective Api.php

The current API also does not allow named parameters, even if some RPC  
mechanisms would deal with it

If an API provides an evolving protocol, discerning versions and  
supporting older input and output formats would be the method  
implementation's task

The registry allows limited runtime introspection (hasMethod,  
listMethods, listApis) but no hints on input/output formats (parameter  
list and type)

++ Proposed H6 API changes

* Split $App_Api class into $Api_Api classes - Apis still need to be  
registered in registry. (MEDIUM)

* Implement parameter and return hints -- TBD -> maybe only needed for  
external interfaces? (Needed for REST, maybe SOAP)

* move DAV browsing/CRUD code to API methods -> Does this also make  
sense for ActiveSync? (OPTIONAL)

* Factor method routing out of Horde_Rpc_* into a loadable module to  
decouple Horde_Rpc from the Horde ecosystem (HIGH)

A simple boilerplate router should be part of Horde_Rpc to facilitate  
unit testing

A Horde-specific router Horde_Core_Rpc_Router should be part of  
Horde_Core and interact with registry:
Check if api exists (for RPC access / individual RPC type)
Check if method exists (for RPC access / individual RPC type)
List available apis (for RPC access / individual RPC type) - should be cached
List available methods (for RPC access / individual RPC type) - should  
be cached
Find right app to call a specific method
Find the right runner and configuration for a set of rpc type, api, method

Most RPC types have a fixed request pattern allowing to easily find  
out the API and method to look for - we can easily delegate this to  
the registry/internal API and then check if the found result is  
exposed by the app

Check for class $App_Api_$Api_$Type if it's explicitly allowed for  
this RPC type
Check for class $App_Api_$Api_Rpc (inherits from Horde_Core_Api_Rpc)  
if it's generally allowed for most RPC types

In Question:
First check for custom overrides $App_Api_$Api_$TypeLocal and  
$App_Api_$Api_RpcLocal ? Does this hit performance badly?

Don't expose this internal API via RPC at all if no such class exists

REST does not have a fixed request pattern. The Router needs to know  
all REST patterns of all APPs before it can even guess if some  
requested api method exists anywhere. Therefore, REST needs an own  
Horde_Core_Rpc_Router_Rest and the RPC Endpoint rpc.php needs to be  
aware of that fact

For each Api/Provider combination in registry
Check for class $App_Api_$Api_Rest
Don't expose this internal API via Rest at all if no such class exists

Each identified Rest request must be checked against this list of  
known REST patterns by Horde_Routes_Mapper.
Each identified Rest request must have a defined answer format to  
apply to the internal api result (let's check if there is a reasonable  
per-verb default for most cases when implementing)

Horde_Core_Api_Rpc (and descendants)
Call internal api $App_Api_$Api to actually run a command
should check what returns for PHP objects and reduce them to arrays  
(__sleep or Serializable)
allow plugging separate authentication, accounting ...
may have to be amended by specific classes or config to support some  
RPC types (REST)

In Question: Does it make sense to also wrap internal calls into a  
Runner_Internal ?

$registry->calendar->addEvent($args);
$registry->call('calendar/addEvent', $args);

The Internal runner simply moves setting up the execution environment  
and calling the actual class and method from the registry class.
As of now, no additional functionality is considered but it may be  
handy for debugging.

++ Accounting

Accounting is optional and will probably only be implemented if  
somebody is interested. Accounting defines a set of limits (value per  
timespan) and stores usage timestamps in a backend (user, timestamp,  
action). If the number of usages inside a sliding window hits the  
limit, the request is denied.
Asking for a past window (like first of month, first of next month)  
allows for billing/reporting, if this is of any interest.
Implementation could use horde_histories, horde_locks (no billing due  
to cleanup) or a text file backend (probably inefficient).

The accounting lib can probably be reused for other things.

++ CODE UPGRADE
For internal app calls, git mv $app/lib/Api.php to  
$app/lib/Api/$Api.php and change class name. Move overrides into a  
separate class. Done.
For most external calls, additionally extend to-be-written  
Horde_Core_Api_Rpc into $App_Api_$Api_Rpc - probably the defaults will  
be just fine for upgrade.

++ API Protection
Protection modules may be combined, probably at first we only want  
Horde Auth (like Login, for ActiveSync, DAV) and Extra Auth (API keys  
or SSL)

No Auth
Horde Default Auth
Admin Only
Need Permission (implies any auth)
Extra Auth (how to map to Horde Users for permissions?)

Per-User global accounting
Per-User Per-Api accounting
Per-User Per-Method accounting

++ CONFIG:
Horde Level:
Rpc
Decide which RPC Types are generally enabled. Default?
Decide which RPC Types use Horde Auth, Separate Auth or both

Accounting
Set up accounting system at all (yes/no)
Set up global per-user accounting (yes/no)
Set up anonymous accounting (yes/no)

App Level:
Upstream provides defaults on which RPC methods are available and how  
they are protected (multiple available).
Admin / Config may override, empty config uses defaults

++ Resources



----
Back to the ((Project|Project List))



More information about the commits mailing list