Browse Source

server: Add GET /transactions/:txid

scalafmt-draft
Alexis Hernandez 7 years ago
parent
commit
0f3d674368
  1. 16
      server/app/controllers/TransactionsController.scala
  2. 16
      server/app/controllers/common/MyAuthenticatorService.scala
  3. 25
      server/app/controllers/common/MyJsonController.scala
  4. 15
      server/app/controllers/common/MyJsonControllerComponents.scala
  5. 2
      server/conf/routes
  6. 121
      server/test/controllers/TransactionsControllerSpec.scala
  7. 18
      server/test/controllers/common/MyAPISpec.scala

16
server/app/controllers/TransactionsController.scala

@ -0,0 +1,16 @@
package controllers
import javax.inject.Inject
import com.xsn.explorer.services.TransactionService
import controllers.common.{MyJsonController, MyJsonControllerComponents}
class TransactionsController @Inject() (
transactionService: TransactionService,
cc: MyJsonControllerComponents)
extends MyJsonController(cc) {
def getTransaction(txid: String) = publicNoInput { _ =>
transactionService.getTransaction(txid)
}
}

16
server/app/controllers/common/MyAuthenticatorService.scala

@ -0,0 +1,16 @@
package controllers.common
import com.alexitc.playsonify.AbstractAuthenticatorService
import com.alexitc.playsonify.core.FutureApplicationResult
import org.scalactic.Good
import play.api.libs.json.JsValue
import play.api.mvc.Request
import scala.concurrent.Future
class MyAuthenticatorService extends AbstractAuthenticatorService[Nothing] {
override def authenticate(request: Request[JsValue]): FutureApplicationResult[Nothing] = {
Future.successful(Good(???))
}
}

25
server/app/controllers/common/MyJsonController.scala

@ -0,0 +1,25 @@
package controllers.common
import com.alexitc.playsonify.AbstractJsonController
import com.alexitc.playsonify.models.{ErrorId, ServerError}
import org.slf4j.LoggerFactory
abstract class MyJsonController(cc: MyJsonControllerComponents) extends AbstractJsonController[Nothing](cc) {
protected val logger = LoggerFactory.getLogger(this.getClass)
override def onServerError(error: ServerError, errorId: ErrorId): Unit = {
val message = s"Unexpected server error, id = ${errorId.string}, error = $error"
error
.cause
.orElse {
logger.warn(message)
None
}
.foreach { cause =>
// we'll log as error when there is an exception involved
logger.error(message, cause)
}
}
}

15
server/app/controllers/common/MyJsonControllerComponents.scala

@ -0,0 +1,15 @@
package controllers.common
import javax.inject.Inject
import com.alexitc.playsonify.{JsonControllerComponents, PublicErrorRenderer}
import play.api.mvc.MessagesControllerComponents
import scala.concurrent.ExecutionContext
class MyJsonControllerComponents @Inject() (
override val messagesControllerComponents: MessagesControllerComponents,
override val executionContext: ExecutionContext,
override val publicErrorRenderer: PublicErrorRenderer,
override val authenticatorService: MyAuthenticatorService)
extends JsonControllerComponents[Nothing]

2
server/conf/routes

@ -2,3 +2,5 @@
# This file defines all application routes (Higher priority routes first) # This file defines all application routes (Higher priority routes first)
# https://www.playframework.com/documentation/latest/ScalaRouting # https://www.playframework.com/documentation/latest/ScalaRouting
# ~~~~ # ~~~~
GET /transactions/:txid controllers.TransactionsController.getTransaction(txid: String)

121
server/test/controllers/TransactionsControllerSpec.scala

@ -0,0 +1,121 @@
package controllers
import com.alexitc.playsonify.PublicErrorRenderer
import com.alexitc.playsonify.core.FutureApplicationResult
import com.xsn.explorer.errors.TransactionNotFoundError
import com.xsn.explorer.models.TransactionId
import com.xsn.explorer.services.XSNService
import controllers.common.MyAPISpec
import org.scalactic.{Bad, Good}
import play.api.inject.bind
import play.api.libs.json.{JsValue, Json}
import play.api.test.Helpers._
import scala.concurrent.Future
class TransactionsControllerSpec extends MyAPISpec {
val customXSNService = new XSNService {
val map = Map(
TransactionId.from("024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c").get ->
s"""
|{
| "blockhash": "000003fb382f6892ae96594b81aa916a8923c70701de4e7054aac556c7271ef7",
| "blocktime": 1520276270,
| "confirmations": 5347,
| "height": 1,
| "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff010000000000000000232103e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029ac00000000",
| "locktime": 0,
| "size": 98,
| "time": 1520276270,
| "txid": "024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c",
| "version": 1,
| "vin": [
| {
| "coinbase": "510101",
| "sequence": 4294967295
| }
| ],
| "vout": [
| {
| "n": 0,
| "scriptPubKey": {
| "addresses": [
| "XdJnCKYNwzCz8ATv8Eu75gonaHyfr9qXg9"
| ],
| "asm": "03e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029 OP_CHECKSIG",
| "hex": "2103e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029ac",
| "reqSigs": 1,
| "type": "pubkey"
| },
| "value": 0,
| "valueSat": 0
| }
| ]
|}
""".stripMargin.trim
)
override def getTransaction(txid: TransactionId): FutureApplicationResult[JsValue] = {
val result = map.get(txid)
.map(s => Json.toJson(s))
.map(Good(_))
.getOrElse {
Bad(TransactionNotFoundError).accumulating
}
Future.successful(result)
}
}
override val application = guiceApplicationBuilder
.overrides(bind[XSNService].to(customXSNService))
.build()
"GET /transactions/:txid" should {
def url(txid: String) = s"/transactions/$txid"
"return an existing transaction" in {
val txid = "024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c"
val response = GET(url(txid))
status(response) mustEqual OK
// TODO: Match result
//val json = contentAsJson(response)
//(json \ "txid").as[String] mustEqual txid
}
"fail on wrong transaction format" in {
// 63 characters
val txid = "000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c"
val response = GET(url(txid))
status(response) mustEqual BAD_REQUEST
val json = contentAsJson(response)
val errorList = (json \ "errors").as[List[JsValue]]
errorList.size mustEqual 1
val error = errorList.head
(error \ "type").as[String] mustEqual PublicErrorRenderer.FieldValidationErrorType
(error \ "field").as[String] mustEqual "transactionId"
(error \ "message").as[String].nonEmpty mustEqual true
}
"fail on unknown transaction" in {
val txid = "0000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c"
val response = GET(url(txid))
status(response) mustEqual BAD_REQUEST
val json = contentAsJson(response)
val errorList = (json \ "errors").as[List[JsValue]]
errorList.size mustEqual 1
val error = errorList.head
(error \ "type").as[String] mustEqual PublicErrorRenderer.FieldValidationErrorType
(error \ "field").as[String] mustEqual "transactionId"
(error \ "message").as[String].nonEmpty mustEqual true
}
}
}

18
server/test/controllers/common/MyAPISpec.scala

@ -0,0 +1,18 @@
package controllers.common
import com.alexitc.playsonify.test.PlayAPISpec
import org.slf4j.LoggerFactory
import play.api.mvc.Result
import play.api.test.FakeRequest
import play.api.test.Helpers._
import scala.concurrent.Future
trait MyAPISpec extends PlayAPISpec {
protected val logger = LoggerFactory.getLogger(this.getClass)
override protected def log[T](request: FakeRequest[T], response: Future[Result]): Unit = {
logger.info(s"> REQUEST, $request; < RESPONSE, status = ${status(response)}, body = ${contentAsString(response)}")
}
}
Loading…
Cancel
Save