Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIR 1451 #77

Merged
merged 2 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions app/controllers/AddressSearchController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import model._
import model.address.{AddressRecord, Postcode}
import model.internal.NonUKAddress
import model.request.{LookupByCountryRequest, LookupByPostTownRequest, LookupByPostcodeRequest, LookupByUprnRequest}
import model.response.SupportedCountryCodes
import model.response.{ErrorResponse, SupportedCountryCodes}
import play.api.libs.json.{JsError, JsSuccess, Json}
import play.api.mvc._
import repositories.{ABPAddressRepository, NonABPAddressRepository}
Expand All @@ -41,16 +41,22 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
scheduler: CheckAddressDataScheduler, val configHelper: ConfigHelper)(
implicit ec: ExecutionContext)
extends AddressController(cc) with AccessChecker {
import ErrorResponse.Implicits._

scheduler.enable()

def search(): Action[String] = accessCheckedAction(parse.tolerantText) {
request =>
Json.parse(request.body).validate[LookupByPostcodeRequest](LookupByPostcodeRequest.reads) match {
case JsSuccess(lookupByPostcodeRequest, _) =>
searchByPostcode(request, lookupByPostcodeRequest.postcode, lookupByPostcodeRequest.filter)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
val maybeJson = Try(Json.parse(request.body))
maybeJson match {
case Success(json) =>
json.validate[LookupByPostcodeRequest](LookupByPostcodeRequest.reads) match {
case JsSuccess(lookupByPostcodeRequest, _) =>
searchByPostcode(request, lookupByPostcodeRequest.postcode, lookupByPostcodeRequest.filter)
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
case Failure(_) => Future.successful(BadRequest(Json.toJson(ErrorResponse.invalidJson)))
}
}

Expand All @@ -64,7 +70,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
case Failure(exception) => Future.successful(BadRequest("""{"obj":[{"msg":["error.payload.missing"],"args":[]}]}"""))
case Failure(_) => Future.successful(BadRequest(Json.toJson(ErrorResponse.invalidJson)))
}
}

Expand All @@ -78,7 +84,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
case Failure(exception) => Future.successful(BadRequest("""{"obj":[{"msg":["error.payload.missing"],"args":[]}]}"""))
case Failure(_) => Future.successful(BadRequest(Json.toJson(ErrorResponse.invalidJson)))
}
}

Expand All @@ -100,7 +106,7 @@ class AddressSearchController @Inject()(addressSearch: ABPAddressRepository, non
case JsError(errors) =>
Future.successful(BadRequest(JsError.toJson(errors)))
}
case Failure(exception) => Future.successful(BadRequest("""{"obj":[{"msg":["error.payload.missing"],"args":[]}]}"""))
case Failure(_) => Future.successful(BadRequest(Json.toJson(ErrorResponse.invalidJson)))
}
}

Expand Down
20 changes: 20 additions & 0 deletions app/model/response.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,24 @@ object response {
implicit val writes: Writes[SupportedCountryCodes] = Json.writes[SupportedCountryCodes]
implicit val reads: Reads[SupportedCountryCodes] = Json.reads[SupportedCountryCodes]
}

case class ErrorMessage(msg: List[String], args: List[String])
object ErrorMessage {
val invalidJson: ErrorMessage = ErrorMessage(msg = List("error.payload.invalid"), args = List())

object Implicits {
implicit val errorMessageReads: Reads[ErrorMessage] = Json.reads[ErrorMessage]
implicit val errorMessageWrites: Writes[ErrorMessage] = Json.writes[ErrorMessage]
}
}
case class ErrorResponse(obj: List[ErrorMessage])
object ErrorResponse {
val invalidJson = ErrorResponse(obj = List(ErrorMessage.invalidJson))

object Implicits {
import ErrorMessage.Implicits._
implicit val errorResponseReads: Reads[ErrorResponse] = Json.reads[ErrorResponse]
implicit val errorResponseWrites: Writes[ErrorResponse] = Json.writes[ErrorResponse]
}
}
}
15 changes: 14 additions & 1 deletion it/test/suites/PostcodeLookupSuiteV2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package it.suites
import com.codahale.metrics.SharedMetricRegistries
import it.helper.AppServerTestApi
import model.address.{AddressRecord, Postcode}
import model.response.ErrorResponse
import org.mockito.ArgumentMatchers.{any, eq => meq}
import org.mockito.Mockito
import org.mockito.Mockito.{times, when}
Expand All @@ -27,7 +28,7 @@ import org.scalatestplus.mockito.MockitoSugar.mock
import org.scalatestplus.play.guice.GuiceOneServerPerSuite
import play.api.Application
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.libs.json.{JsArray, Json}
import play.api.libs.json.{JsArray, JsObject, JsString, JsValue, Json}
import play.api.libs.ws.WSClient
import play.api.test.Helpers.{await, defaultAwaitTimeout}
import play.inject.Bindings
Expand Down Expand Up @@ -260,6 +261,18 @@ class PostcodeLookupSuiteV2()
response.status shouldBe BAD_REQUEST
}

"give a bad request when the payload is invalid json" in {
import ErrorResponse.Implicits._
val response = post("/lookup", """{"foo":"FX1 4AC""")
response.status shouldBe BAD_REQUEST
val responseText = response.body
val errorResponse = Json.parse(responseText).validate[ErrorResponse].get

errorResponse.obj should have length(1)
errorResponse.obj.head.msg should have length(1)
errorResponse.obj.head.msg.head shouldBe "error.payload.invalid"
}

"give a not found when an unknown path is requested" in {
val response = post("/somethingElse", """{"foo":"FX1 4AD"}""")
response.status shouldBe NOT_FOUND
Expand Down
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ resolvers += Resolver.typesafeRepo("releases")
resolvers += MavenRepository("HMRC-open-artefacts-maven2", "https://open.artefacts.tax.service.gov.uk/maven2")
resolvers += Resolver.url("HMRC-open-artefacts-ivy", url("https://open.artefacts.tax.service.gov.uk/ivy2"))(Resolver.ivyStylePatterns)

addSbtPlugin("uk.gov.hmrc" % "sbt-auto-build" % "3.18.0")
addSbtPlugin("uk.gov.hmrc" % "sbt-distributables" % "2.4.0")
addSbtPlugin("uk.gov.hmrc" % "sbt-auto-build" % "3.20.0")
addSbtPlugin("uk.gov.hmrc" % "sbt-distributables" % "2.5.0")
addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.9")