RADAR-base / RADAR-PushEndpoint

A gateway to expose endpoints for Push based services to POST data to RADAR-Base platform.
Apache License 2.0
2 stars 2 forks source link

RADAR-PushEndpoint

Build Status Docker Build

RADAR Push Endpoint that exposes REST interface for push subscription based APIs to the Apache Kafka.

Configuration

Currently, Garmin is integrated. For adding more services, see the Extending section.

   pushIntegration:
      # Push service specific config
      garmin: 
        enabled: true
        userRepositoryClass: "org.radarbase.push.integration.garmin.user.ServiceUserRepository"
      service-n:
        enabled: true
        property-xyz: "value"

For Garmin, you will need to configure the endpoints in the Garmin Developer Portal

If you are using the org.radarbase.push.integration.garmin.user.GarminServiceUserRepository make sure to create the oauth client in management portal with following properties -

client_id: your_client_id
client_secret: your_client_secret
grant_type: client_credentials
resources: res_restAuthorizer
scope: "SUBJECT.READ", "MEASUREMENT.READ", "SUBJECT.UPDATE", "MEASUREMENT.CREATE"

then configure the following properties-

    pushIntegration:
      garmin:
        enabled: true
        userRepositoryClass: org.radarbase.push.integration.garmin.user.GarminServiceUserRepository
        userRepositoryUrl: "http://radar-rest-sources-backend:8090/rest-sources/backend/"
        userRepositoryClientId: "your_client_id"
        userRepositoryClientSecret: "your_client_secret"
        userRepositoryTokenUrl: "http://managementportal-app:8080/oauth/token/"

Modify the URLs according to your deployment.

Usage

Start the Service with

docker-compose up -d --build

then once kafka-1 is ready, create topics with

TOPIC=test
docker-compose exec kafka-1 kafka-topics --create --topic $TOPIC --bootstrap-server kafka-1:9092

Now the service is accessible through http://localhost:8090/push/integrations/. Garmin endpoints are available at -

Extending

This section walks through add a new push service integration. These should be implemented in a new package org.radarbase.push.integration.<service-name>.

Resource

Create a new Resource and configure the endpoints required by the push service integration. For reference take a look at GarminPushEndpoint

User Repository

Create a new UserRepository to provide user specific info and authorization info. This should implement the interface UserRepository. For reference, take a look at ServiceUserRepository

Auth Validator

Create a new AuthValidator to check the requests and authorise with users provided by the User Repository. This can be done by implementing the AuthValidator interface provided by radar-jersey library. For reference, take a look at GarminAuthValidator

Converter

This is optional but will help keep the code consistent. Create Converters for converting data posted by the push service to Kafka records. This can be done by implementing the AvroConverter interface. For reference, take a look at converter implementations in garmin converter package.

Configuration

Firstly, create a Resource Enhancer to register all your required classes to Jersey Context. Remember to use named to distinguish your service implementation.

class ServiceXIntegrationResourceEnhancer(private val config: Config) :
    JerseyResourceEnhancer {

    override fun ResourceConfig.enhance() {
        packages(
            "org.radarbase.push.integration.servicex.resource",
            "org.radarbase.push.integration.servicex.filter"
        )
    }

    override fun AbstractBinder.enhance() {

        bind(config.pushIntegration.servicex.userRepository)
            .to(UserRepository::class.java)
            .named("servicex")
            .`in`(Singleton::class.java)

        bind(ServiceXAuthValidator::class.java)
            .to(AuthValidator::class.java)
            .named("servicex")
            .`in`(Singleton::class.java)
    }
}

Next, add your AuthValidator to the DelegatedAuthValidator so service specific Auth can be performed. Make sure the path to your service's resources contain the matching string (servicex in this case).

...

    fun delegate(): AuthValidator {
        return when {
            uriInfo.matches(GARMIN_QUALIFIER) -> namedValidators.named(GARMIN_QUALIFIER).get()
            uriInfo.matches("servicex") -> namedValidators.named("servicex").get()
            // Add support for more as integrations are added
            else -> throw IllegalStateException()
        }
    }

...

Next, add the configuration to the Config class.

...
data class PushIntegrationConfig(
    val garmin: GarminConfig = GarminConfig(),
    val servicex: ServiceXConfig
)

data class ServiceXConfig(
    val enabled: Boolean = false,
    val userRepositoryClass: String,
    val property1: String,
    val property2: List<String>
)

...

Finally, add your newly created Resource Enhancer to PushIntegrationEnhancerFactory

...
        // Push Service specific enhancers
        if (config.pushIntegration.garmin.enabled) {
            enhancersList.add(GarminPushIntegrationResourceEnhancer(config))
        }
        if(config.pushIntegration.servicex.enabled) {
            enhancersList.add(ServiceXIntegrationResourceEnhancer(config))
        }

...