All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.solarmosaic.client.utilityApi.UtilityApiClient.scala Maven / Gradle / Ivy

/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Solar Mosaic, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.solarmosaic.client.utilityApi

import akka.actor.ActorSystem
import akka.util.Timeout
import com.solarmosaic.client.utilityApi.json.IsoDateTimeConversions
import com.solarmosaic.client.utilityApi.model.FormatTypes
import com.solarmosaic.client.utilityApi.model.FormatTypes.FormatType
import com.solarmosaic.client.utilityApi.model.request.{AccountModifyRequest, ServiceModifyRequest}
import com.solarmosaic.client.utilityApi.model.response._
import org.joda.time.DateTime
import spray.client.pipelining._
import spray.http.HttpHeaders.{Accept, Authorization}
import spray.http.Uri.Path
import spray.http.Uri.Path.Slash
import spray.http.{GenericHttpCredentials, HttpRequest, Uri}
import spray.httpx.unmarshalling.FromResponseUnmarshaller
import spray.httpx.{SprayJsonSupport, UnsuccessfulResponseException}

import scala.concurrent.Future
import scala.concurrent.duration._

/**
 * UtilityAPI client.
 *
 * @param token API token
 * @param timeoutDuration Request timeout duration, defaults to 10 seconds.
 *
 * @see https://utilityapi.com/api/tokens/new.html
 */
case class UtilityApiClient(
  token: String,
  timeoutDuration: FiniteDuration = 10.seconds
) extends SprayJsonSupport with IsoDateTimeConversions {
  implicit val system = ActorSystem("utility-api-client")
  implicit val timeout = Timeout(timeoutDuration)
  import system.dispatcher

  val baseUri = UtilityApiClient.uri
  val basePath = baseUri.path

  /** The client URI. */
  def getUri: Uri = baseUri

  /** The client URI with the given String segments appended to the base Path. */
  def getUri(segments: Any*): Uri = getUri.withPath(basePath / segments.mkString("/"))

  /** The client URI with the given Path appended to the base Path. */
  def getUri(path: Path): Uri = getUri.withPath(basePath ++ Slash(path))

  /**
   * Gets a future response for the given request, unmarshalling it to the given type.
   *
   * @param request The HTTP request.
   * @param format Which format to deliver the response in.
   * @tparam T The type to unmarshal the response to.
   * @return A Future containing the unmarshalled response object.
   */
  protected[utilityApi] def pipeline[T: FromResponseUnmarshaller](request: HttpRequest)
      (implicit format: FormatType = FormatTypes.json): Future[T] = (
      addHeader(Authorization(GenericHttpCredentials("Token", token)))
      ~> addHeader(Accept(format.mediaType))
      ~> sendReceive
      ~> unmarshal[T]
    ).apply(request)

  /**
   * Get an account by account uid.
   * @see https://utilityapi.com/api/docs/api.html#accounts-uid
   *
   * @param accountUid The unique identifier for the account.
   * @param format The response format.
   * @return A Future containing Some account, or None if the account was not found.
   */
  def getAccount(accountUid: String)
      (implicit format: FormatType = FormatTypes.json): Future[Option[AccountResponse]] =
    pipeline[Option[AccountResponse]](Get(getUri("accounts", accountUid))) recover {
      case e: UnsuccessfulResponseException => None
    }

  /**
   * Get all accounts.
   * @see https://utilityapi.com/api/docs/api.html#accounts
   *
   * @param format The response format.
   * @return A Future containing a list of accounts.
   */
  def getAccounts()
      (implicit format: FormatType = FormatTypes.json): Future[List[AccountResponse]] =
    pipeline[List[AccountResponse]](Get(getUri("accounts"))) recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Get accounts by referral ids.
   * @see https://utilityapi.com/api/docs/api.html#accounts
   *
   * @param referralIds List of referral ids.
   * @param format The response format.
   * @return A Future containing a list of accounts.
   */
  def getAccountsByReferralIds(referralIds: List[String])
      (implicit format: FormatType = FormatTypes.json): Future[List[AccountResponse]] =
    pipeline[List[AccountResponse]](Get(
      getUri("accounts").withQuery("referrals" -> referralIds.mkString(","))
    )) recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Get bills by service uid.
   * @see https://utilityapi.com/api/docs/api.html#bills
   *
   * @param serviceUid The unique identifier for the service.
   * @param format The response format.
   * @return A Future containing a list of bills.
   */
  def getBillsByServiceUid(serviceUid: String)
      (implicit format: FormatType = FormatTypes.json): Future[List[BillResponse]] =
    pipeline[List[BillResponse]](Get(getUri("services", serviceUid, "bills"))) recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Get meter intervals by service uid.
   * @see https://utilityapi.com/api/docs/api.html#intervals
   *
   * @param serviceUid The unique identifier for the service.
   * @param format The response format.
   * @return A Future containing a list of meter intervals.
   */
  def getIntervalsByServiceUid(serviceUid: String, start: Option[DateTime] = None, end: Option[DateTime] = None)
      (implicit format: FormatType = FormatTypes.json): Future[List[IntervalResponse]] =
    pipeline[List[IntervalResponse]] {
      val uri = getUri("services", serviceUid, "intervals")
      val query = Seq(
        start.map(s => "start" -> dateTimeToIsoFormat(s)),
        end.map(e => "end" -> dateTimeToIsoFormat(e))
      ).flatten
      Get(uri.withQuery(query: _*))
    } recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Get a service by service uid.
   * @see https://utilityapi.com/api/docs/api.html#services-uid
   *
   * @param serviceUid The unique identifier for the service.
   * @param format The response format.
   * @return A Future containing Some service, or None if the service was not found.
   */
  def getService(serviceUid: String)
      (implicit format: FormatType = FormatTypes.json): Future[Option[ServiceResponse]] =
    pipeline[Option[ServiceResponse]](Get(getUri("services", serviceUid))) recover {
      case e: UnsuccessfulResponseException => None
    }

  /**
   * Get all services.
   * @see https://utilityapi.com/api/docs/api.html#services
   *
   * @param format The response format.
   * @return A Future containing a list of services.
   */
  def getServices()
      (implicit format: FormatType = FormatTypes.json): Future[List[ServiceResponse]] =
    pipeline[List[ServiceResponse]](Get(getUri("services"))) recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Get services by account uids.
   * @see https://utilityapi.com/api/docs/api.html#services
   *
   * @param accountUids The unique identifier for the account.
   * @param format The response format.
   * @return A Future containing a list of account services.
   */
  def getServicesByAccountUids(accountUids: List[String])
      (implicit format: FormatType = FormatTypes.json): Future[List[ServiceResponse]] =
    pipeline[List[ServiceResponse]](Get(
      getUri("services").withQuery("accounts" -> accountUids.mkString(","))
    )) recover {
      case e: UnsuccessfulResponseException => Nil
    }

  /**
   * Modify an account by account uid.
   * @see https://utilityapi.com/docs#accounts-modify
   *
   * @param accountUid The unique identifier for the account.
   * @param request The request model.
   * @param format The request/response format.
   * @return A Future containing Some account, or None if the account was not found.
   */
  def modifyAccount(accountUid: String, request: AccountModifyRequest)
      (implicit format: FormatType = FormatTypes.json): Future[Option[AccountResponse]] =
    pipeline[Option[AccountResponse]](Post(getUri("accounts", accountUid, "modify"), request)) recover {
      case e: UnsuccessfulResponseException => None
    }

  /**
   * Modify a service by service uid.
   * @see https://utilityapi.com/docs#services-modify
   *
   * @param serviceUid The unique identifier for the service.
   * @param request The request model.
   * @param format The request/response format.
   * @return A Future containing Some service, or None if the service was not found.
   */
  def modifyService(serviceUid: String, request: ServiceModifyRequest)
      (implicit format: FormatType = FormatTypes.json): Future[Option[ServiceResponse]] =
    pipeline[Option[ServiceResponse]](Post(getUri("services", serviceUid, "modify"), request)) recover {
      case e: UnsuccessfulResponseException => None
    }
}

object UtilityApiClient {
  val uri = Uri("https://utilityapi.com/api")
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy