-
-
Notifications
You must be signed in to change notification settings - Fork 249
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
Move circe codecs to the core module #102
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package caliban | ||
|
||
import caliban.interop.circe._ | ||
|
||
import scala.language.higherKinds | ||
|
||
/** | ||
* Represents a GraphQL request, containing a query, an operation name and a map of variables. | ||
*/ | ||
case class GraphQLRequest( | ||
query: String, | ||
operationName: Option[String], | ||
variables: Option[Map[String, InputValue]] | ||
) | ||
|
||
object GraphQLRequest { | ||
implicit def circeDecoder[F[_]: IsCirceDecoder]: F[GraphQLRequest] = | ||
GraphQLRequestCirce.graphQLRequestDecoder.asInstanceOf[F[GraphQLRequest]] | ||
} | ||
|
||
private object GraphQLRequestCirce { | ||
import io.circe._ | ||
import io.circe.derivation._ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we are using circe-derivation only for this single (and simple) type, how about deriving it manually and only depend on circe-core? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think codecs created by circe-derivation macros depend on the circe core only, so people won't need circe-derivation as a dependency. Although, to be on the safe side I can indeed implement it manually. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yeah, you must be right! All good then. |
||
val graphQLRequestDecoder: Decoder[GraphQLRequest] = deriveDecoder[GraphQLRequest] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,28 @@ | ||
package caliban | ||
|
||
import caliban.interop.circe._ | ||
|
||
import scala.language.higherKinds | ||
|
||
/** | ||
* Represents the result of a GraphQL query, containing a data object and a list of errors. | ||
*/ | ||
case class GraphQLResponse[+E](data: ResponseValue, errors: List[E]) | ||
|
||
object GraphQLResponse { | ||
implicit def circeEncoder[F[_]: IsCirceEncoder, E]: F[GraphQLResponse[E]] = | ||
GraphQLResponceCirce.graphQLResponseEncoder.asInstanceOf[F[GraphQLResponse[E]]] | ||
} | ||
|
||
private object GraphQLResponceCirce { | ||
import io.circe._ | ||
import io.circe.syntax._ | ||
val graphQLResponseEncoder: Encoder[GraphQLResponse[CalibanError]] = Encoder | ||
.instance[GraphQLResponse[CalibanError]]( | ||
response => | ||
Json.obj( | ||
"data" -> response.data.asJson, | ||
"errors" -> Json.fromValues(response.errors.map(err => Json.fromString(err.toString))) | ||
) | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package caliban.interop.circe | ||
|
||
import io.circe._ | ||
|
||
import scala.language.higherKinds | ||
|
||
/** | ||
* This class is an implementation of the pattern described in https://blog.7mind.io/no-more-orphans.html | ||
* It makes it possible to mark circe dependency as optional and keep Encoders defined in the companion object. | ||
*/ | ||
private[caliban] trait IsCirceEncoder[F[_]] | ||
private[caliban] object IsCirceEncoder { | ||
implicit val isCirceEncoder: IsCirceEncoder[Encoder] = null | ||
} | ||
|
||
/** | ||
* This class is an implementation of the pattern described in https://blog.7mind.io/no-more-orphans.html | ||
* It makes it possible to mark circe dependency as optional and keep Decoders defined in the companion object. | ||
*/ | ||
private[caliban] trait IsCirceDecoder[F[_]] | ||
private[caliban] object IsCirceDecoder { | ||
implicit val isCirceDecoder: IsCirceDecoder[Decoder] = null | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package caliban | ||
|
||
import io.circe._ | ||
import zio.test.Assertion._ | ||
import zio.test._ | ||
|
||
object GraphQLRequestSpec | ||
extends DefaultRunnableSpec( | ||
suite("GraphQLRequestSpec")( | ||
test("can be parsed from JSON") { | ||
val request = Json | ||
.obj("query" -> Json.fromString("{}"), "operationName" -> Json.fromString("op"), "variables" -> Json.obj()) | ||
assert( | ||
request.as[GraphQLRequest], | ||
isRight( | ||
equalTo(GraphQLRequest(query = "{}", operationName = Some("op"), variables = Some(Map.empty))) | ||
) | ||
) | ||
} | ||
) | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package caliban | ||
|
||
import caliban.Value._ | ||
import io.circe._ | ||
import io.circe.syntax._ | ||
import zio.test.Assertion._ | ||
import zio.test._ | ||
|
||
object GraphQLResponseSpec | ||
extends DefaultRunnableSpec( | ||
suite("GraphQLResponseSpec")( | ||
test("can be converted to JSON") { | ||
val response = GraphQLResponse(StringValue("data"), Nil) | ||
assert( | ||
response.asJson, | ||
equalTo(Json.obj("data" -> Json.fromString("data"), "errors" -> Json.arr())) | ||
) | ||
} | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we reduce the dependency to circe-core as I suggested in the other comment, this is good. But otherwise, I think we should keep that one so that people who use caliban-http4s don't need to add the dependency to circe-derivation themselves.