Skip to content

Commit

Permalink
API-2532: Initial view of development: (#3)
Browse files Browse the repository at this point in the history
* API-2532: Initial view of development:

- hmrc library and SBT version upgrade
- added default Play Guice DI
- removed manual stubs
- added mocking via mocking library
- added scoverage plugin and `precheck.sh`
- service locator no longer used

* cleaning

* cleaning

* API-2532: cleaning README
googley42 authored and gokyo committed Oct 6, 2017

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 00e7f02 commit 8f5cbae
Showing 37 changed files with 1,452 additions and 287 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -7,12 +7,13 @@ TODO: This microservice BLA BLA BLA ...
### Tests
Some tests require MongoDB to run.
Thus, remember to start up MongoDB if you want to run the tests locally.
The tests include unit tests and integration tests.
There are unit tests, integration tests and acceptance tests.
In order to run them, use this command line:
```
sbt test it:test
sbt test it:test acceptance:test
```


### License

This code is open source software licensed under the [Apache 2.0 License]("http://www.apache.org/licenses/LICENSE-2.0.html")
Original file line number Diff line number Diff line change
@@ -14,36 +14,35 @@
* limitations under the License.
*/

package uk.gov.hmrc.apisubscriptionfields
package uk.gov.hmrc.apisubscriptionfields.config

import com.typesafe.config.Config
import play.api.{Application, Configuration, Play}
import uk.gov.hmrc.play.audit.filters.AuditFilter
import net.ceedubs.ficus.Ficus._
import play.api._
import uk.gov.hmrc.play.config.{AppName, ControllerConfig, RunMode}
import uk.gov.hmrc.play.http.logging.filters.LoggingFilter
import uk.gov.hmrc.play.microservice.bootstrap.DefaultMicroserviceGlobal
import net.ceedubs.ficus.Ficus._
import uk.gov.hmrc.play.filters.MicroserviceFilterSupport
import uk.gov.hmrc.play.microservice.filters.{AuditFilter, LoggingFilter, MicroserviceFilterSupport}


object ControllerConfiguration extends ControllerConfig {
lazy val controllerConfigs = Play.current.configuration.underlying.as[Config]("controllers")
}

object MicroserviceAuditFilter extends AuditFilter with AppName with MicroserviceFilterSupport {
override val auditConnector = MicroserviceAuditConnector
override lazy val auditConnector = MicroserviceAuditConnector
override def controllerNeedsAuditing(controllerName: String) = ControllerConfiguration.paramsForController(controllerName).needsAuditing
}

object MicroserviceLoggingFilter extends LoggingFilter with MicroserviceFilterSupport {
override def controllerNeedsLogging(controllerName: String) = ControllerConfiguration.paramsForController(controllerName).needsLogging
}

object MicroserviceGlobal extends DefaultMicroserviceGlobal with RunMode with MicroserviceFilterSupport {
override val auditConnector = MicroserviceAuditConnector
object MicroserviceGlobal extends DefaultMicroserviceGlobal with RunMode {
override lazy val auditConnector = MicroserviceAuditConnector

override def microserviceMetricsConfig(implicit app: Application): Option[Configuration] = app.configuration.getConfig(s"microservice.metrics")

override val loggingFilter = MicroserviceLoggingFilter
override val microserviceAuditFilter = MicroserviceAuditFilter
override lazy val loggingFilter = MicroserviceLoggingFilter
override lazy val microserviceAuditFilter = MicroserviceAuditFilter
override val authFilter = None
}
Original file line number Diff line number Diff line change
@@ -14,18 +14,11 @@
* limitations under the License.
*/

package uk.gov.hmrc.apisubscriptionfields
package uk.gov.hmrc.apisubscriptionfields.config

import uk.gov.hmrc.play.audit.http.config.LoadAuditingConfig
import uk.gov.hmrc.play.audit.http.connector.AuditConnector
import uk.gov.hmrc.play.config.{AppName, RunMode}
import uk.gov.hmrc.play.http.hooks.HttpHook
import uk.gov.hmrc.play.http.ws._
import uk.gov.hmrc.play.microservice.config.LoadAuditingConfig

object WSHttp extends WSGet with WSPut with WSPost with WSDelete with WSPatch with AppName {
override val hooks: Seq[HttpHook] = NoneRequired
}

object MicroserviceAuditConnector extends AuditConnector with RunMode {
object MicroserviceAuditConnector extends AuditConnector {
override lazy val auditingConfig = LoadAuditingConfig(s"auditing")
}
Original file line number Diff line number Diff line change
@@ -17,25 +17,59 @@
package uk.gov.hmrc.apisubscriptionfields.controller

import java.util.UUID
import javax.inject.{Inject, Singleton}

import play.api.mvc.Action
import uk.gov.hmrc.play.microservice.controller.BaseController
import play.api.libs.json.{JsValue, Json}
import play.api.mvc._
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode._
import uk.gov.hmrc.apisubscriptionfields.model._
import uk.gov.hmrc.apisubscriptionfields.service.SubscriptionFieldsService

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

trait ApiSubscriptionFieldsController extends BaseController {

def id() = Action.async { implicit request =>
/*
TODO:
parse `ApiSubscriptionRequest`
- [application_id]_[api_context]_[api_context] is the id of the mongo record, but decide good separators
- generate UUID (the header to be passed in the incoming requests)
- save record to mongo
*/
val subscriptionFieldsId = UUID.randomUUID()
Future.successful(Created(s"$subscriptionFieldsId"))
@Singleton
class ApiSubscriptionFieldsController @Inject() (service: SubscriptionFieldsService) extends CommonController {

import JsonFormatters._

private val NOT_FOUND_RESPONSE = NotFound(JsErrorResponse(SUBSCRIPTION_FIELDS_ID_NOT_FOUND, "Subscription Fields were not found"))

def getSubscriptionFields(rawAppId: UUID, rawApiContext: String, rawApiVersion: String): Action[AnyContent] = Action.async { implicit request =>
val eventualMaybeResponse = service.get(SubscriptionIdentifier(AppId(rawAppId), ApiContext(rawApiContext), ApiVersion(rawApiVersion)))
asActionResult(eventualMaybeResponse)
}

def getSubscriptionFieldsByFieldsId(rawFieldsId: UUID): Action[AnyContent] = Action.async { implicit request =>
val eventualMaybeResponse = service.get(SubscriptionFieldsId(rawFieldsId))
asActionResult(eventualMaybeResponse)
}
}

object ApiSubscriptionFieldsController extends ApiSubscriptionFieldsController
private def asActionResult(eventualMaybeResponse: Future[Option[SubscriptionFieldsResponse]]) = {
eventualMaybeResponse map {
case Some(subscriptionFields) => Ok(Json.toJson(subscriptionFields))
case None => NOT_FOUND_RESPONSE
} recover recovery
}

def upsertSubscriptionFields(rawAppId: UUID, rawApiContext: String, rawApiVersion: String): Action[JsValue] = Action.async(parse.json) { implicit request =>
withJsonBody[SubscriptionFieldsRequest] { payload =>
service.upsert(SubscriptionIdentifier(AppId(rawAppId), ApiContext(rawApiContext), ApiVersion(rawApiVersion)), payload.fields) map {
case (response, true) => Created(Json.toJson(response))
case (response, false) => Ok(Json.toJson(response))
} recover {
case e: Exception => BadRequest(e.getMessage)
}
} recover recovery
}

def deleteSubscriptionFields(rawAppId: UUID, rawApiContext: String, rawApiVersion: String): Action[AnyContent] = Action.async { implicit request =>
val identifier = SubscriptionIdentifier(AppId(rawAppId), ApiContext(rawApiContext), ApiVersion(rawApiVersion))
//TODO remove service.get
service.get(identifier) flatMap {
case None => Future.successful(NOT_FOUND_RESPONSE)
case Some(_) => service.delete(identifier).map(deleted => if (deleted) NoContent else NOT_FOUND_RESPONSE)
} recover recovery
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2017 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.apisubscriptionfields.controller

import play.api.Logger
import play.api.libs.json.{JsError, JsSuccess, JsValue, Reads}
import play.api.mvc.{Request, Result}
import uk.gov.hmrc.apisubscriptionfields.model.JsErrorResponse
import uk.gov.hmrc.play.microservice.controller.BaseController
import uk.gov.hmrc.apisubscriptionfields.model.ErrorCode._
import scala.concurrent.Future
import scala.util.{Failure, Success, Try}

trait CommonController extends BaseController {

override protected def withJsonBody[T]
(f: (T) => Future[Result])(implicit request: Request[JsValue], m: Manifest[T], reads: Reads[T]): Future[Result] = {
Try(request.body.validate[T]) match {
case Success(JsSuccess(payload, _)) => f(payload)
case Success(JsError(errs)) => Future.successful(UnprocessableEntity(JsErrorResponse(INVALID_REQUEST_PAYLOAD, JsError.toJson(errs))))
case Failure(e) => Future.successful(UnprocessableEntity(JsErrorResponse(INVALID_REQUEST_PAYLOAD, e.getMessage)))
}
}

def recovery: PartialFunction[Throwable, Result] = {
case e => handleException(e)
}

private[controller] def handleException(e: Throwable) = {
Logger.error(s"An unexpected error occurred: ${e.getMessage}", e)
InternalServerError(JsErrorResponse(UNKNOWN_ERROR, "An unexpected error occurred"))
}

}

This file was deleted.

27 changes: 22 additions & 5 deletions app/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatters.scala
Original file line number Diff line number Diff line change
@@ -16,12 +16,29 @@

package uk.gov.hmrc.apisubscriptionfields.model

import play.api.libs.json.Json
import java.util.UUID

object JsonFormatters {
implicit val formatApiSubscription = Json.format[ApiSubscription]
import play.api.libs.json._

trait SharedJsonFormatters {
implicit val SubscriptionFieldsIdJF = new Format[SubscriptionFieldsId] {
def writes(s: SubscriptionFieldsId) = JsString(s.value.toString)

def reads(json: JsValue) = json match {
case JsNull => JsError()
case _ => JsSuccess(SubscriptionFieldsId(json.as[UUID]))
}
}
}

object MongoFormatters {
implicit val formatApiSubscription = Json.format[ApiSubscription]
trait JsonFormatters extends SharedJsonFormatters {

implicit val SubscriptionFieldsResponseJF = Json.format[SubscriptionFieldsResponse]

implicit val SubscriptionFieldsIdResponseJF = Json.format[SubscriptionFieldsIdResponse]

implicit val SubscriptionFieldsRequestJF = Json.format[SubscriptionFieldsRequest]

}

object JsonFormatters extends JsonFormatters
62 changes: 62 additions & 0 deletions app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2017 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.apisubscriptionfields.model

import java.util.UUID

import scala.annotation.tailrec

case class AppId(value: UUID) extends AnyVal

case class ApiContext(value: String) extends AnyVal

case class ApiVersion(value: String) extends AnyVal

case class SubscriptionFieldsId(value: UUID) extends AnyVal

object SubscriptionIdentifier {
private val Separator = "##"
private type SeparatorType = String

def decode(text:String): Option[SubscriptionIdentifier] = {
def findSeparator(separatorToFind: SeparatorType) : SeparatorType = {
if (text.split(separatorToFind).length > 3)
findSeparator(separatorToFind+Separator)
else
separatorToFind
}

val parts = text.split(findSeparator(Separator))
Some(SubscriptionIdentifier(AppId(UUID.fromString(parts(0))), ApiContext(parts(1)), ApiVersion(parts(2))))
}
}

case class SubscriptionIdentifier(applicationId: AppId, apiContext: ApiContext, apiVersion: ApiVersion) {
import SubscriptionIdentifier._

def encode(): String = {
@tailrec
def findSeparator(text: String)(separatorToFind: SeparatorType): SeparatorType =
if (!text.contains(separatorToFind))
separatorToFind
else
findSeparator(text)(separatorToFind+Separator)

val longestSeparator: SeparatorType = findSeparator(apiVersion.value)(findSeparator(apiContext.value)(Separator))
s"${applicationId.value}$longestSeparator${apiContext.value}$longestSeparator${apiVersion.value}"
}
}
20 changes: 20 additions & 0 deletions app/uk/gov/hmrc/apisubscriptionfields/model/Requests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2017 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.apisubscriptionfields.model

case class SubscriptionFieldsRequest(fields: Fields)

Loading

0 comments on commit 8f5cbae

Please sign in to comment.