Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

A principal role of the SD&B component is to support an architecture that recognizes that services come and go, sometimes unexpectedly. To that end, it should be possible to decouple the lifecycle of a particular service instance from the lifecycle (i.e. deployment) of the API-X framework, including the SD&B component. Furthermore, it should be possible to deploy this component in a distribute distributed fashion across multiple machines, both to support high availability and high levels of concurrency. It should also be possible for services to be deployed on an arbitrary number of external hosts using any language or framework. With that structure, network partitions and service failure should not affect the overall operation of this component nor the overall operation of API-X.

In many ways, the SD&B component can be thought of as a management interface, distinct from individual service endpoints. While its role is not that of operating on specific repository resources, it can be viewed as a broker between clients, repository resources and external services.

The high level objectives of such a management interface are to support the following:

 

  • Service Discovery (i.e. client interaction):
    • list all available services
    • list all services that apply to a given fedora object
    • list all services that apply to a given rdf:type of fedora object
    • list service status (availability/non-availability)
    • provide some level of description of services (e.g. as RDF)
    • use REST semantics
  • Service Binding (i.e. service interaction)
    • Services should be able to register and deregister themselves from API-X
    • It should be possible for individual services to be available at N hosts (e.g. for high availability)
    • If a particular service instance fails or is removed, API-X should know about that (optional)
  • Deployment
    • the SB&D component should be capable of being deployed in a fully distributed environment, across multiple hosts, and such deployment should be entirely transparent to clients.
    • it should be possible for the SD&B interface to be deployed on separate hosts from the services themselves.

 

Reverse Proxy

A related concept to SD&B is that of a reverse proxy. The design details of that are out of scope for this document, but a possible outline is described in order to provide more context to the SD&B component. At a high level, a client using the API-X proxy could interact with a Fedora repository as if there were no proxy at all. The proxy may choose to add headers such as (e.g. for the resource /rest/resource):

...

These headers would be generated using the SD&B interface. Then, when a client interacts with a service, e.g. at /rest/resource/svc:validate the proxy mechanism will pass the request directly to an instance of that service, using the context of /rest/resource. In this way, clients should have no need to interact directly with the SD&B component.

...

There are two categories of endpoints: those used by clients and those used by services. In these examples, all data exchange uses JSON-LD. These examples refer to a JSON-LD context such as the following: 

Code Block
languagejs
titleapix.jsonld
{
    "@context": {
    "id" : "@id",
    "type" : "@type",

    "apix" : "http://fedora.info/definitions/v4/apix/",
    "rdfs" : "http://www.w3.org/2000/01/rdf-schema#",
    "dcterms" : "http://purl.org/dc/terms/",
    "fedora" : "http://fedora.info/definitions/v4/repository#",

    "Binding" : {"@id" : "apix:Binding", "@type" : "@id"},
    "Registry" : {"@id" : "apix:Registry", "@type" : "@id"},
    "Service" : {"@id" : "apix:Service", "@type" : "@id"},
    "ZooKeeperBinding" : {"@id" : "apix:ZooKeeperBinding", "@type" : "@id"},

    "hasEndpoint" : {"@id" : "apix:hasEndpoint", "@type" : "@id"},
    "hasParentZnode" : {"@id" : "apix:hasParentZnode"},
    "hasService" : {"@id" : "apix:hasService"},
    "hasZooKeeperEnsemble" : {"@id" : "apix:hasZooKeeperEnsemble", "@type": "@id"},
    "supportsType" : {"@id" : "apix:supportsType", "@type": "@id"},
    "seeAlso" : {"@id" : "rdfs:seeAlso", "@type" : "@id"},
    "label" : {"@id" : "rdfs:label"},
    "comment" : {"@id" : "rdfs:comment"},
    "identifier" : {"@id" : "dcterms:identifier"}
  }
}

...

id - a particular Fedora resource
type - a comma-delimited list of rdf:type URIs

Response:

Code Block
languagejs
Content-Type: application/json

...


Link:

...

 <http://fedora.info/definitions/v4/apix.

...

jsonld>; rel="describedby"; type="application/ld+json"

...


{

...


  "id" : "http://apix-host/apix/registry",

...


  "type" : "Registry",

...


  "hasService" : [

...


    {

...


      "type" : "Service",

...


      "label" : "a foo webservice",

...


      "seeAlso" : "http://example.org/foo",

...


      "identifier" : "foo",

...


      "supportsType" : ["fedora:Resource"],

...


      "hasEndpoint" : ["http://host-1/foo/rest", "http://host-2/foo/rest"]

...


    },

...


    {

...


      "type" : "Service",

...


      "label" : "a bar webservice",

...


      "seeAlso" : "http://example.org/bar",

...


      "identifier" : "bar",

...


      "supportsType" : ["fedora:Binary"],

...


      "hasEndpoint" : ["http://host-3/bar/rest", "http://host-4/bar/rest"]

...


    }

...


  ]

...


}

In a similar way, information about a particular service can be retrieved:

GET /apix/registry/foo

Response:

Code Block
Content-Type: application/json

...


Link:

...

 <http://fedora.info/definitions/v4/apix.

...

jsonld>; rel="describedby"; type="application/ld+json"

...


{

...


  "id" : "http://apix-host/apix/registry/foo",

...


  "type" : "Service",

...


  "label" : "a foo webservice",

...


  "seeAlso" : "http://example.org/foo",

...


  "identifier" : "foo",

...


  "supportsType" : ["fedora:Resource"],

...


  "hasEndpoint" : ["http://host-1/foo/rest", "http://host-2/foo/rest"]

...


}

Service Endpoints

Registering Services

Services can be registered by interacting with the service registry. This endpoint only registers the existence of a service but does not make any guarantees about any running instances of that service. Such a service must also first be registered before any service instances can be bound to it.

Code Block
PUT /apix/registry/foo

...



Content-Type: application/ld+json

...


{

...


  "@context" : "http://fedora.info/definitions/v4/apix.jsonld",

...


  "id" : "http://apix-host/apix/registry/foo",

...


  "type" : "Service",

...


  "label" : "a foo webservice",

...


  "seeAlso" : "http://example.org/foo",

...


  "identifier" : "foo",

...


  "supportsType" : ["fedora:Resource"]

...


}

Note: the hasEndpoint element is not included here, but is part of the /bind interface, described below.

...

Some services may not be able to use dynamic service binding, e.g. a PHP web-application. For these, a manual binding interface is available. This example binds a particular service instance to the already-registered foo service.

Code Block
POST /apix/bind/foo

...



Content-Type: text/plain

...


http://host-1/foo/rest

The response will contain a unique id of this service binding. That URI can be used to unbind the service at a later point.

...

GET /apix/bind/foo

Response:

Code Block
Content-Type: application/json

...


Link:

...

 <http://fedora.info/definitions/v4/apix.

...

jsonld>; rel="describedby"; type="application/ld+json"

...



{

...


  "id" : "http://apix-host/apix/bind/foo",

...


  "type" : ["Binding", "ZooKeeperBinding"],

...


  "hasZooKeeperEnsemble" : ["host-1:2181", "host-2:2181", "host-3:2181"],

...


  "hasParentZnode" : "/service/foo"

...


}

At this point (interacting directly with zookeeper), it would be the responsibility of the client to create an ephemeral, sequential znode under /service/foo, storing the value of the service's endpoint. For example:

...