/**
 * Generated by API Builder - https://www.apibuilder.io
 * Service version: 0.0.1
 * User agent: apibuilder app.apibuilder.io/apicollective/examples-graphql-users/0.0.1/play_2_5_client
 */
package io.apibuilder.examples.graphql.users.models {

  sealed trait UserPatchForm extends _root_.scala.Product with _root_.scala.Serializable {
    def userPatchFormDiscriminator: UserPatchFormDiscriminator

  }

  /**
   * Defines the valid discriminator values for the type UserPatchForm
   */
  sealed trait UserPatchFormDiscriminator extends _root_.scala.Product with _root_.scala.Serializable

  object UserPatchFormDiscriminator {

    case object UserStatusPatchForm extends UserPatchFormDiscriminator { override def toString = "status" }
    case object UserEmailPatchForm extends UserPatchFormDiscriminator { override def toString = "email" }

    final case class UNDEFINED(override val toString: String) extends UserPatchFormDiscriminator

    val all: scala.List[UserPatchFormDiscriminator] = scala.List(UserStatusPatchForm, UserEmailPatchForm)

    private val byName: Map[String, UserPatchFormDiscriminator] = all.map(x => x.toString.toLowerCase -> x).toMap

    def apply(value: String): UserPatchFormDiscriminator = fromString(value).getOrElse(UNDEFINED(value))

    def fromString(value: String): _root_.scala.Option[UserPatchFormDiscriminator] = byName.get(value.toLowerCase)

  }
  final case class User(
    id: _root_.java.util.UUID,
    status: io.apibuilder.examples.graphql.users.models.UserStatus,
    email: String,
    name: _root_.scala.Option[String] = None
  )

  final case class UserEmailPatchForm(
    email: String
  ) extends UserPatchForm {
    override val userPatchFormDiscriminator: UserPatchFormDiscriminator = UserPatchFormDiscriminator.UserEmailPatchForm
  }

  final case class UserForm(
    status: io.apibuilder.examples.graphql.users.models.UserStatus = io.apibuilder.examples.graphql.users.models.UserStatus.Active,
    email: String,
    name: _root_.scala.Option[String] = None
  )

  final case class UserStatusPatchForm(
    status: io.apibuilder.examples.graphql.users.models.UserStatus
  ) extends UserPatchForm {
    override val userPatchFormDiscriminator: UserPatchFormDiscriminator = UserPatchFormDiscriminator.UserStatusPatchForm
  }

  /**
   * Provides future compatibility in clients - in the future, when a type is added
   * to the union UserPatchForm, it will need to be handled in the client code. This
   * implementation will deserialize these future types as an instance of this class.
   *
   * @param description Information about the type that we received that is undefined in this version of
   *        the client.
   */

  final case class UserPatchFormUndefinedType(
    description: String
  ) extends UserPatchForm {
    override val userPatchFormDiscriminator: UserPatchFormDiscriminator = UserPatchFormDiscriminator.UNDEFINED(description)
  }
  sealed trait UserStatus extends _root_.scala.Product with _root_.scala.Serializable

  object UserStatus {

    case object Active extends UserStatus { override def toString = "active" }
    case object Inactive extends UserStatus { override def toString = "inactive" }
    /**
     * UNDEFINED captures values that are sent either in error or
     * that were added by the server after this library was
     * generated. We want to make it easy and obvious for users of
     * this library to handle this case gracefully.
     *
     * We use all CAPS for the variable name to avoid collisions
     * with the camel cased values above.
     */
    final case class UNDEFINED(override val toString: String) extends UserStatus

    /**
     * all returns a list of all the valid, known values. We use
     * lower case to avoid collisions with the camel cased values
     * above.
     */
    val all: scala.List[UserStatus] = scala.List(Active, Inactive)

    private
    val byName: Map[String, UserStatus] = all.map(x => x.toString.toLowerCase -> x).toMap

    def apply(value: String): UserStatus = fromString(value).getOrElse(UNDEFINED(value))

    def fromString(value: String): _root_.scala.Option[UserStatus] = byName.get(value.toLowerCase)

  }

}

package io.apibuilder.examples.graphql.users.models {

  package object json {
    import play.api.libs.json.__
    import play.api.libs.json.JsString
    import play.api.libs.json.Writes
    import play.api.libs.functional.syntax._
    import io.apibuilder.examples.graphql.users.models.json._

    private[users] implicit val jsonReadsUUID: play.api.libs.json.Reads[_root_.java.util.UUID] = __.read[String].map { str =>
      _root_.java.util.UUID.fromString(str)
    }

    private[users] implicit val jsonWritesUUID: play.api.libs.json.Writes[_root_.java.util.UUID] = (x: _root_.java.util.UUID) => play.api.libs.json.JsString(x.toString)

    private[users] implicit val jsonReadsJodaDateTime: play.api.libs.json.Reads[_root_.org.joda.time.DateTime] = __.read[String].map { str =>
      _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseDateTime(str)
    }

    private[users] implicit val jsonWritesJodaDateTime: play.api.libs.json.Writes[_root_.org.joda.time.DateTime] = (x: _root_.org.joda.time.DateTime) => {
      play.api.libs.json.JsString(_root_.org.joda.time.format.ISODateTimeFormat.dateTime.print(x))
    }

    private[users] implicit val jsonReadsJodaLocalDate: play.api.libs.json.Reads[_root_.org.joda.time.LocalDate] = __.read[String].map { str =>
      _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseLocalDate(str)
    }

    private[users] implicit val jsonWritesJodaLocalDate: play.api.libs.json.Writes[_root_.org.joda.time.LocalDate] = (x: _root_.org.joda.time.LocalDate) => {
      play.api.libs.json.JsString(_root_.org.joda.time.format.ISODateTimeFormat.date.print(x))
    }

    implicit val jsonReadsExamplesGraphqlUsersUserStatus: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserStatus] = new play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserStatus] {
      def reads(js: play.api.libs.json.JsValue): play.api.libs.json.JsResult[io.apibuilder.examples.graphql.users.models.UserStatus] = {
        js match {
          case v: play.api.libs.json.JsString => play.api.libs.json.JsSuccess(io.apibuilder.examples.graphql.users.models.UserStatus(v.value))
          case _ => {
            (js \ "value").validate[String] match {
              case play.api.libs.json.JsSuccess(v, _) => play.api.libs.json.JsSuccess(io.apibuilder.examples.graphql.users.models.UserStatus(v))
              case err: play.api.libs.json.JsError =>
                (js \ "user_status").validate[String] match {
                  case play.api.libs.json.JsSuccess(v, _) => play.api.libs.json.JsSuccess(io.apibuilder.examples.graphql.users.models.UserStatus(v))
                  case err: play.api.libs.json.JsError => err
                }
            }
          }
        }
      }
    }

    def jsonWritesExamplesGraphqlUsersUserStatus(obj: io.apibuilder.examples.graphql.users.models.UserStatus) = {
      play.api.libs.json.JsString(obj.toString)
    }

    def jsObjectUserStatus(obj: io.apibuilder.examples.graphql.users.models.UserStatus) = {
      play.api.libs.json.Json.obj("value" -> play.api.libs.json.JsString(obj.toString))
    }

    implicit def jsonWritesExamplesGraphqlUsersUserStatus: play.api.libs.json.Writes[UserStatus] = {
      (obj: io.apibuilder.examples.graphql.users.models.UserStatus) => {
        io.apibuilder.examples.graphql.users.models.json.jsonWritesExamplesGraphqlUsersUserStatus(obj)
      }
    }

    implicit def jsonReadsExamplesGraphqlUsersUser: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.User] = {
      for {
        id <- (__ \ "id").read[_root_.java.util.UUID]
        status <- (__ \ "status").read[io.apibuilder.examples.graphql.users.models.UserStatus]
        email <- (__ \ "email").read[String]
        name <- (__ \ "name").readNullable[String]
      } yield User(id, status, email, name)
    }

    def jsObjectUser(obj: io.apibuilder.examples.graphql.users.models.User): play.api.libs.json.JsObject = {
      play.api.libs.json.Json.obj(
        "id" -> play.api.libs.json.JsString(obj.id.toString),
        "status" -> play.api.libs.json.JsString(obj.status.toString),
        "email" -> play.api.libs.json.JsString(obj.email)
      ) ++ (obj.name match {
        case None => play.api.libs.json.Json.obj()
        case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x))
      })
    }

    implicit def jsonWritesExamplesGraphqlUsersUser: play.api.libs.json.Writes[User] = {
      (obj: io.apibuilder.examples.graphql.users.models.User) => {
        io.apibuilder.examples.graphql.users.models.json.jsObjectUser(obj)
      }
    }

    implicit def jsonReadsExamplesGraphqlUsersUserEmailPatchForm: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserEmailPatchForm] = {
      (__ \ "email").read[String].map { x => UserEmailPatchForm(email = x) }
    }

    def jsObjectUserEmailPatchForm(obj: io.apibuilder.examples.graphql.users.models.UserEmailPatchForm): play.api.libs.json.JsObject = {
      play.api.libs.json.Json.obj(
        "email" -> play.api.libs.json.JsString(obj.email)
      ) ++ play.api.libs.json.Json.obj("discriminator" -> "email")
    }

    implicit def jsonWritesExamplesGraphqlUsersUserEmailPatchForm: play.api.libs.json.Writes[UserEmailPatchForm] = {
      (obj: io.apibuilder.examples.graphql.users.models.UserEmailPatchForm) => {
        io.apibuilder.examples.graphql.users.models.json.jsObjectUserEmailPatchForm(obj)
      }
    }

    implicit def jsonReadsExamplesGraphqlUsersUserForm: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserForm] = {
      for {
        status <- (__ \ "status").read[io.apibuilder.examples.graphql.users.models.UserStatus]
        email <- (__ \ "email").read[String]
        name <- (__ \ "name").readNullable[String]
      } yield UserForm(status, email, name)
    }

    def jsObjectUserForm(obj: io.apibuilder.examples.graphql.users.models.UserForm): play.api.libs.json.JsObject = {
      play.api.libs.json.Json.obj(
        "status" -> play.api.libs.json.JsString(obj.status.toString),
        "email" -> play.api.libs.json.JsString(obj.email)
      ) ++ (obj.name match {
        case None => play.api.libs.json.Json.obj()
        case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x))
      })
    }

    implicit def jsonWritesExamplesGraphqlUsersUserForm: play.api.libs.json.Writes[UserForm] = {
      (obj: io.apibuilder.examples.graphql.users.models.UserForm) => {
        io.apibuilder.examples.graphql.users.models.json.jsObjectUserForm(obj)
      }
    }

    implicit def jsonReadsExamplesGraphqlUsersUserStatusPatchForm: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserStatusPatchForm] = {
      (__ \ "status").read[io.apibuilder.examples.graphql.users.models.UserStatus].map { x => UserStatusPatchForm(status = x) }
    }

    def jsObjectUserStatusPatchForm(obj: io.apibuilder.examples.graphql.users.models.UserStatusPatchForm): play.api.libs.json.JsObject = {
      play.api.libs.json.Json.obj(
        "status" -> play.api.libs.json.JsString(obj.status.toString)
      ) ++ play.api.libs.json.Json.obj("discriminator" -> "status")
    }

    implicit def jsonWritesExamplesGraphqlUsersUserStatusPatchForm: play.api.libs.json.Writes[UserStatusPatchForm] = {
      (obj: io.apibuilder.examples.graphql.users.models.UserStatusPatchForm) => {
        io.apibuilder.examples.graphql.users.models.json.jsObjectUserStatusPatchForm(obj)
      }
    }

    implicit def jsonReadsExamplesGraphqlUsersUserPatchForm: play.api.libs.json.Reads[io.apibuilder.examples.graphql.users.models.UserPatchForm] = (js: play.api.libs.json.JsValue) => {
      def readDiscriminator(discriminator: String) = {
        discriminator match {
          case "status" => io.apibuilder.examples.graphql.users.models.json.jsonReadsExamplesGraphqlUsersUserStatusPatchForm.reads(js)
          case "email" => io.apibuilder.examples.graphql.users.models.json.jsonReadsExamplesGraphqlUsersUserEmailPatchForm.reads(js)
          case other => play.api.libs.json.JsSuccess(io.apibuilder.examples.graphql.users.models.UserPatchFormUndefinedType(other))
        }
      }
      (js \ "discriminator").validate[String] match {
        case e: play.api.libs.json.JsError => e
        case s: play.api.libs.json.JsSuccess[String] => readDiscriminator(s.value)
      }
    }

    def jsObjectUserPatchForm(obj: io.apibuilder.examples.graphql.users.models.UserPatchForm): play.api.libs.json.JsObject = {
      obj match {
        case x: io.apibuilder.examples.graphql.users.models.UserStatusPatchForm => io.apibuilder.examples.graphql.users.models.json.jsObjectUserStatusPatchForm(x)
        case x: io.apibuilder.examples.graphql.users.models.UserEmailPatchForm => io.apibuilder.examples.graphql.users.models.json.jsObjectUserEmailPatchForm(x)
        case other => {
          sys.error(s"The type[${other.getClass.getName}] has no JSON writer")
        }
      }
    }
    implicit def jsonWritesExamplesGraphqlUsersUserPatchForm: play.api.libs.json.Writes[UserPatchForm] = {
      (obj: io.apibuilder.examples.graphql.users.models.UserPatchForm) => {
        io.apibuilder.examples.graphql.users.models.json.jsObjectUserPatchForm(obj)
      }
    }
  }
}

package io.apibuilder.examples.graphql.users {

  object Bindables {

    import play.api.mvc.{PathBindable, QueryStringBindable}

    // import models directly for backwards compatibility with prior versions of the generator
    import Core._
    import Models._

    object Core {
      implicit def pathBindableDateTimeIso8601(implicit stringBinder: QueryStringBindable[String]): PathBindable[_root_.org.joda.time.DateTime] = ApibuilderPathBindable(ApibuilderTypes.dateTimeIso8601)
      implicit def queryStringBindableDateTimeIso8601(implicit stringBinder: QueryStringBindable[String]): QueryStringBindable[_root_.org.joda.time.DateTime] = ApibuilderQueryStringBindable(ApibuilderTypes.dateTimeIso8601)

      implicit def pathBindableDateIso8601(implicit stringBinder: QueryStringBindable[String]): PathBindable[_root_.org.joda.time.LocalDate] = ApibuilderPathBindable(ApibuilderTypes.dateIso8601)
      implicit def queryStringBindableDateIso8601(implicit stringBinder: QueryStringBindable[String]): QueryStringBindable[_root_.org.joda.time.LocalDate] = ApibuilderQueryStringBindable(ApibuilderTypes.dateIso8601)
    }

    object Models {
      import io.apibuilder.examples.graphql.users.models._

      val userStatusConverter: ApibuilderTypeConverter[io.apibuilder.examples.graphql.users.models.UserStatus] = new ApibuilderTypeConverter[io.apibuilder.examples.graphql.users.models.UserStatus] {
        override def convert(value: String): io.apibuilder.examples.graphql.users.models.UserStatus = io.apibuilder.examples.graphql.users.models.UserStatus(value)
        override def convert(value: io.apibuilder.examples.graphql.users.models.UserStatus): String = value.toString
        override def example: io.apibuilder.examples.graphql.users.models.UserStatus = io.apibuilder.examples.graphql.users.models.UserStatus.Active
        override def validValues: Seq[io.apibuilder.examples.graphql.users.models.UserStatus] = io.apibuilder.examples.graphql.users.models.UserStatus.all
      }
      implicit def pathBindableUserStatus(implicit stringBinder: QueryStringBindable[String]): PathBindable[io.apibuilder.examples.graphql.users.models.UserStatus] = ApibuilderPathBindable(userStatusConverter)
      implicit def queryStringBindableUserStatus(implicit stringBinder: QueryStringBindable[String]): QueryStringBindable[io.apibuilder.examples.graphql.users.models.UserStatus] = ApibuilderQueryStringBindable(userStatusConverter)
    }

    trait ApibuilderTypeConverter[T] {

      def convert(value: String): T

      def convert(value: T): String

      def example: T

      def validValues: Seq[T] = Nil

      def errorMessage(key: String, value: String, ex: java.lang.Exception): String = {
        val base = s"Invalid value '$value' for parameter '$key'. "
        validValues.toList match {
          case Nil => base + "Ex: " + convert(example)
          case values => base + ". Valid values are: " + values.mkString("'", "', '", "'")
        }
      }
    }

    object ApibuilderTypes {
      val dateTimeIso8601: ApibuilderTypeConverter[_root_.org.joda.time.DateTime] = new ApibuilderTypeConverter[_root_.org.joda.time.DateTime] {
        override def convert(value: String): _root_.org.joda.time.DateTime = _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseDateTime(value)
        override def convert(value: _root_.org.joda.time.DateTime): String = _root_.org.joda.time.format.ISODateTimeFormat.dateTime.print(value)
        override def example: _root_.org.joda.time.DateTime = _root_.org.joda.time.DateTime.now
      }

      val dateIso8601: ApibuilderTypeConverter[_root_.org.joda.time.LocalDate] = new ApibuilderTypeConverter[_root_.org.joda.time.LocalDate] {
        override def convert(value: String): _root_.org.joda.time.LocalDate = _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseLocalDate(value)
        override def convert(value: _root_.org.joda.time.LocalDate): String = _root_.org.joda.time.format.ISODateTimeFormat.date.print(value)
        override def example: _root_.org.joda.time.LocalDate = _root_.org.joda.time.LocalDate.now
      }
    }

    final case class ApibuilderQueryStringBindable[T](
      converters: ApibuilderTypeConverter[T]
    ) extends QueryStringBindable[T] {

      override def bind(key: String, params: Map[String, Seq[String]]): _root_.scala.Option[_root_.scala.Either[String, T]] = {
        params.getOrElse(key, Nil).headOption.map { v =>
          try {
            Right(
              converters.convert(v)
            )
          } catch {
            case ex: java.lang.Exception => Left(
              converters.errorMessage(key, v, ex)
            )
          }
        }
      }

      override def unbind(key: String, value: T): String = {
        s"$key=${converters.convert(value)}"
      }
    }

    final case class ApibuilderPathBindable[T](
      converters: ApibuilderTypeConverter[T]
    ) extends PathBindable[T] {

      override def bind(key: String, value: String): _root_.scala.Either[String, T] = {
        try {
          Right(
            converters.convert(value)
          )
        } catch {
          case ex: java.lang.Exception => Left(
            converters.errorMessage(key, value, ex)
          )
        }
      }

      override def unbind(key: String, value: T): String = {
        converters.convert(value)
      }
    }

  }

}


package io.apibuilder.examples.graphql.users {

  object Constants {

    val Namespace = "io.apibuilder.examples.graphql.users"
    val UserAgent = "apibuilder app.apibuilder.io/apicollective/examples-graphql-users/0.0.1/play_2_5_client"
    val Version = "0.0.1"
    val VersionMajor = 0

  }

  class Client(
    ws: play.api.libs.ws.WSClient,
    val baseUrl: String,
    auth: scala.Option[io.apibuilder.examples.graphql.users.Authorization] = None,
    defaultHeaders: Seq[(String, String)] = Nil
  ) extends interfaces.Client {
    import io.apibuilder.examples.graphql.users.models.json._

    private val logger = play.api.Logger("io.apibuilder.examples.graphql.users.Client")

    logger.info(s"Initializing io.apibuilder.examples.graphql.users.Client for url $baseUrl")

    def users: Users = Users

    object Users extends Users {
      override def getById(
        id: _root_.java.util.UUID,
        requestHeaders: Seq[(String, String)] = Nil
      )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User] = {
        _executeRequest("GET", s"/users/${id}", requestHeaders = requestHeaders).map {
          case r if r.status == 200 => _root_.io.apibuilder.examples.graphql.users.Client.parseJson("io.apibuilder.examples.graphql.users.models.User", r, _.validate[io.apibuilder.examples.graphql.users.models.User])
          case r if r.status == 404 => throw io.apibuilder.examples.graphql.users.errors.UnitResponse(r.status)
          case r => throw io.apibuilder.examples.graphql.users.errors.FailedRequest(r.status, s"Unsupported response code[${r.status}]. Expected: 200, 404")
        }
      }

      override def post(
        userForm: io.apibuilder.examples.graphql.users.models.UserForm,
        requestHeaders: Seq[(String, String)] = Nil
      )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User] = {
        val payload = play.api.libs.json.Json.toJson(userForm)

        _executeRequest("POST", s"/users", body = Some(payload), requestHeaders = requestHeaders).map {
          case r if r.status == 201 => _root_.io.apibuilder.examples.graphql.users.Client.parseJson("io.apibuilder.examples.graphql.users.models.User", r, _.validate[io.apibuilder.examples.graphql.users.models.User])
          case r if r.status == 422 => throw io.apibuilder.examples.graphql.users.errors.ValuesResponse(r)
          case r => throw io.apibuilder.examples.graphql.users.errors.FailedRequest(r.status, s"Unsupported response code[${r.status}]. Expected: 201, 422")
        }
      }

      override def patch(
        userPatchForm: io.apibuilder.examples.graphql.users.models.UserPatchForm,
        requestHeaders: Seq[(String, String)] = Nil
      )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User] = {
        val payload = play.api.libs.json.Json.toJson(userPatchForm)

        _executeRequest("PATCH", s"/users", body = Some(payload), requestHeaders = requestHeaders).map {
          case r if r.status == 200 => _root_.io.apibuilder.examples.graphql.users.Client.parseJson("io.apibuilder.examples.graphql.users.models.User", r, _.validate[io.apibuilder.examples.graphql.users.models.User])
          case r if r.status == 422 => throw io.apibuilder.examples.graphql.users.errors.ValuesResponse(r)
          case r => throw io.apibuilder.examples.graphql.users.errors.FailedRequest(r.status, s"Unsupported response code[${r.status}]. Expected: 200, 422")
        }
      }

      override def deleteById(
        id: _root_.java.util.UUID,
        requestHeaders: Seq[(String, String)] = Nil
      )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[Unit] = {
        _executeRequest("DELETE", s"/users/${id}", requestHeaders = requestHeaders).map {
          case r if r.status == 204 => ()
          case r if r.status == 404 => throw io.apibuilder.examples.graphql.users.errors.UnitResponse(r.status)
          case r => throw io.apibuilder.examples.graphql.users.errors.FailedRequest(r.status, s"Unsupported response code[${r.status}]. Expected: 204, 404")
        }
      }
    }

    def _requestHolder(path: String): play.api.libs.ws.WSRequest = {

      val holder = ws.url(baseUrl + path).withHeaders(
        "User-Agent" -> Constants.UserAgent,
        "X-Apidoc-Version" -> Constants.Version,
        "X-Apidoc-Version-Major" -> Constants.VersionMajor.toString
      ).withHeaders(defaultHeaders: _*)
      auth.fold(holder) {
        case Authorization.Basic(username, password) => {
          holder.withAuth(username, password.getOrElse(""), play.api.libs.ws.WSAuthScheme.BASIC)
        }
      }
    }

    def _logRequest(method: String, req: play.api.libs.ws.WSRequest): play.api.libs.ws.WSRequest = {
      val queryComponents = for {
        (name, values) <- req.queryString
        value <- values
      } yield s"$name=$value"
      val url = s"${req.url}${queryComponents.mkString("?", "&", "")}"
      auth.fold(logger.info(s"curl -X $method '$url'")) { _ =>
        logger.info(s"curl -X $method -u '[REDACTED]:' '$url'")
      }
      req
    }

    def _executeRequest(
      method: String,
      path: String,
      queryParameters: Seq[(String, String)] = Nil,
      requestHeaders: Seq[(String, String)] = Nil,
      body: Option[play.api.libs.json.JsValue] = None
    ): scala.concurrent.Future[play.api.libs.ws.WSResponse] = {
      method.toUpperCase match {
        case "GET" => {
          _logRequest("GET", _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*)).get()
        }
        case "POST" => {
          _logRequest("POST", _requestHolder(path).withHeaders(_withJsonContentType(requestHeaders): _*).withQueryString(queryParameters: _*)).post(body.getOrElse(play.api.libs.json.Json.obj()))
        }
        case "PUT" => {
          _logRequest("PUT", _requestHolder(path).withHeaders(_withJsonContentType(requestHeaders): _*).withQueryString(queryParameters: _*)).put(body.getOrElse(play.api.libs.json.Json.obj()))
        }
        case "PATCH" => {
          _logRequest("PATCH", _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*)).patch(body.getOrElse(play.api.libs.json.Json.obj()))
        }
        case "DELETE" => {
          _logRequest("DELETE", _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*)).delete()
        }
         case "HEAD" => {
          _logRequest("HEAD", _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*)).head()
        }
         case "OPTIONS" => {
          _logRequest("OPTIONS", _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*)).options()
        }
        case _ => {
          _logRequest(method, _requestHolder(path).withHeaders(requestHeaders: _*).withQueryString(queryParameters: _*))
          sys.error("Unsupported method[%s]".format(method))
        }
      }
    }

    /**
     * Adds a Content-Type: application/json header unless the specified requestHeaders
     * already contain a Content-Type header
     */
    def _withJsonContentType(headers: Seq[(String, String)]): Seq[(String, String)] = {
      headers.find { _._1.toUpperCase == "CONTENT-TYPE" } match {
        case None => headers ++ Seq("Content-Type" -> "application/json; charset=UTF-8")
        case Some(_) => headers
      }
    }

  }

  object Client {

    def parseJson[T](
      className: String,
      r: play.api.libs.ws.WSResponse,
      f: (play.api.libs.json.JsValue => play.api.libs.json.JsResult[T])
    ): T = {
      f(play.api.libs.json.Json.parse(r.body)) match {
        case play.api.libs.json.JsSuccess(x, _) => x
        case play.api.libs.json.JsError(errors) => {
          throw io.apibuilder.examples.graphql.users.errors.FailedRequest(r.status, s"Invalid json for class[" + className + "]: " + errors.mkString(" "))
        }
      }
    }

  }

  sealed trait Authorization extends _root_.scala.Product with _root_.scala.Serializable
  object Authorization {
    final case class Basic(username: String, password: Option[String] = None) extends Authorization
  }

  package interfaces {

    trait Client {
      def baseUrl: String
      def users: io.apibuilder.examples.graphql.users.Users
    }

  }

  trait Users {
    def getById(
      id: _root_.java.util.UUID,
      requestHeaders: Seq[(String, String)] = Nil
    )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User]

    def post(
      userForm: io.apibuilder.examples.graphql.users.models.UserForm,
      requestHeaders: Seq[(String, String)] = Nil
    )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User]

    def patch(
      userPatchForm: io.apibuilder.examples.graphql.users.models.UserPatchForm,
      requestHeaders: Seq[(String, String)] = Nil
    )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[io.apibuilder.examples.graphql.users.models.User]

    def deleteById(
      id: _root_.java.util.UUID,
      requestHeaders: Seq[(String, String)] = Nil
    )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[Unit]
  }

  package errors {

    import io.apibuilder.examples.graphql.users.models.json._

    final case class UnitResponse(status: Int) extends Exception(s"HTTP $status")

    final case class ValuesResponse(
      response: play.api.libs.ws.WSResponse,
      message: Option[String] = None
    ) extends Exception(message.getOrElse(s"${response.status}: ${response.body}")) {
      lazy val values = _root_.io.apibuilder.examples.graphql.users.Client.parseJson("Seq[String]", response, _.validate[Seq[String]])
    }

    final case class FailedRequest(responseCode: Int, message: String, requestUri: Option[_root_.java.net.URI] = None) extends _root_.java.lang.Exception(s"HTTP $responseCode: $message")

  }

}