diff --git a/docs/404.html b/docs/404.html index c3f243ac09..7ea8201067 100644 --- a/docs/404.html +++ b/docs/404.html @@ -8,13 +8,13 @@ - + -

404

Looks like we've got some broken links.
+ - + diff --git a/docs/about/index.html b/docs/about/index.html index d3e942ffa0..e5b7ff9be2 100644 --- a/docs/about/index.html +++ b/docs/about/index.html @@ -8,7 +8,7 @@ - + @@ -37,6 +37,6 @@ (opens new window)

# About

Caliban is a project developed by Pierre Ricadat aka @ghostdogpr (opens new window).

The name is inspired by the SF novel and tv series The Expanse (opens new window).

Thanks:

- + diff --git a/docs/assets/js/11.6f1922be.js b/docs/assets/js/11.0f539c02.js similarity index 98% rename from docs/assets/js/11.6f1922be.js rename to docs/assets/js/11.0f539c02.js index c80a7d974d..2dc8a09afa 100644 --- a/docs/assets/js/11.6f1922be.js +++ b/docs/assets/js/11.0f539c02.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{396:function(e,t,a){"use strict";a.r(t);var r=a(54),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[e._v("#")]),e._v(" Examples")]),e._v(" "),a("p",[e._v("The "),a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/",target:"_blank",rel:"noopener noreferrer"}},[e._v("examples"),a("OutboundLink")],1),e._v(" project in Github contains various examples:")]),e._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/http4s",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with http4s"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/akkahttp",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with Akka HTTP"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/play",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with play"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/rlavolee/caliban-play-with-route-file",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with play's route file"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/ziohttp",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with zio-http"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/client",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL Client usage"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/client-laminext/src/test/scala/caliban/client/laminext",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL Client integration with Laminext"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/optimizations",target:"_blank",rel:"noopener noreferrer"}},[e._v("Optimization with ZQuery"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/interop/cats",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Cats Effect"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/tapir",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Tapir"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/federation",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apollo Federation usage"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/stitching",target:"_blank",rel:"noopener noreferrer"}},[e._v("Schema Stitching usage"),a("OutboundLink")],1)])]),e._v(" "),a("h4",{attrs:{id:"available-only-with-cats-effect-2-x"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#available-only-with-cats-effect-2-x"}},[e._v("#")]),e._v(" Available only with cats-effect 2.x")]),e._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/interop/monix",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Monix"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/finch",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with finch"),a("OutboundLink")],1)])]),e._v(" "),a("p",[e._v("You may also check out "),a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban-blog-series",target:"_blank",rel:"noopener noreferrer"}},[e._v("the repository"),a("OutboundLink")],1),e._v(" accompanying my "),a("a",{attrs:{href:"https://medium.com/@ghostdogpr/graphql-in-scala-with-caliban-part-1-8ceb6099c3c2",target:"_blank",rel:"noopener noreferrer"}},[e._v("blog series"),a("OutboundLink")],1),e._v(" on Caliban.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{393:function(e,t,a){"use strict";a.r(t);var r=a(54),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"examples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[e._v("#")]),e._v(" Examples")]),e._v(" "),a("p",[e._v("The "),a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/",target:"_blank",rel:"noopener noreferrer"}},[e._v("examples"),a("OutboundLink")],1),e._v(" project in Github contains various examples:")]),e._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/http4s",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with http4s"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/akkahttp",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with Akka HTTP"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/play",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with play"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/rlavolee/caliban-play-with-route-file",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with play's route file"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/ziohttp",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with zio-http"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/client",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL Client usage"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/client-laminext/src/test/scala/caliban/client/laminext",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL Client integration with Laminext"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/optimizations",target:"_blank",rel:"noopener noreferrer"}},[e._v("Optimization with ZQuery"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/interop/cats",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Cats Effect"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/tapir",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Tapir"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/federation",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apollo Federation usage"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/stitching",target:"_blank",rel:"noopener noreferrer"}},[e._v("Schema Stitching usage"),a("OutboundLink")],1)])]),e._v(" "),a("h4",{attrs:{id:"available-only-with-cats-effect-2-x"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#available-only-with-cats-effect-2-x"}},[e._v("#")]),e._v(" Available only with cats-effect 2.x")]),e._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/interop/monix",target:"_blank",rel:"noopener noreferrer"}},[e._v("Interop with Monix"),a("OutboundLink")],1)]),e._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/finch",target:"_blank",rel:"noopener noreferrer"}},[e._v("GraphQL API exposed with finch"),a("OutboundLink")],1)])]),e._v(" "),a("p",[e._v("You may also check out "),a("a",{attrs:{href:"https://github.com/ghostdogpr/caliban-blog-series",target:"_blank",rel:"noopener noreferrer"}},[e._v("the repository"),a("OutboundLink")],1),e._v(" accompanying my "),a("a",{attrs:{href:"https://medium.com/@ghostdogpr/graphql-in-scala-with-caliban-part-1-8ceb6099c3c2",target:"_blank",rel:"noopener noreferrer"}},[e._v("blog series"),a("OutboundLink")],1),e._v(" on Caliban.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/12.7e1943de.js b/docs/assets/js/12.1b632383.js similarity index 99% rename from docs/assets/js/12.7e1943de.js rename to docs/assets/js/12.1b632383.js index 9e1756e5a3..e3fef0e60b 100644 --- a/docs/assets/js/12.7e1943de.js +++ b/docs/assets/js/12.1b632383.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{397:function(t,a,e){"use strict";e.r(a);var s=e(54),n=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"federation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#federation"}},[t._v("#")]),t._v(" Federation")]),t._v(" "),e("p",[e("strong",[t._v("Federation")]),t._v(" is an optional module which can be included in your configuration to enroll with a federated schema.")]),t._v(" "),e("h2",{attrs:{id:"dependencies"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#dependencies"}},[t._v("#")]),t._v(" Dependencies")]),t._v(" "),e("p",[e("code",[t._v("caliban-federation")]),t._v(" only depends on "),e("code",[t._v("caliban-core")]),t._v(" and is very unobtrusive.")]),t._v(" "),e("p",[t._v("To use, add the following line to your "),e("code",[t._v("build.sbt")]),t._v(" file:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban-federation" % "1.2.2"\n')])])]),e("h2",{attrs:{id:"federating"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#federating"}},[t._v("#")]),t._v(" Federating")]),t._v(" "),e("p",[t._v("Federation allows graphs to become part of a larger graph without having to share models or create brittle\nschema stitching code at the gateway level.")]),t._v(" "),e("p",[t._v("You can read more about federation and why it may be useful "),e("a",{attrs:{href:"https://www.apollographql.com/docs/apollo-server/federation/introduction/",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[t._v("Federation creates a wrapper over your existing schema so that it can add the necessary hooks to support\ninteraction with the gateway.")]),t._v(" "),e("p",[t._v("If you already have a graph you can add federation simply by calling the wrapper function "),e("code",[t._v("federate")])]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("federation"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("_\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" schema"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Queries"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n characters "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" List"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Amos"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" federatedSchema"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("This will wrap the bare minimum schema additions around your API so that the gateway will recognize your schema.\nTo actually enable entity resolution you will need to do a bit of leg work.")]),t._v(" "),e("p",[t._v('First, any types that will be "resolvable" need to be annotated with a '),e("code",[t._v("@key")]),t._v(" directive. You can use a helper function found\nin the "),e("code",[t._v("federation")]),t._v(" package to help with that.")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Key"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("The "),e("code",[t._v('"name"')]),t._v(" field is a field selector minus the outer braces.")]),t._v(" "),e("p",[t._v("If you need to extend a type from another service, you will need to define a stub version of it in the current service\nand annotate it with the "),e("code",[t._v("@extends")]),t._v(" annotation")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Key"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"season episode"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Extend"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Episode"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("External"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" season"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("External"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" episode"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cast"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("Note the additional annotations we needed in this case. "),e("code",[t._v("Extend")]),t._v(" is needed to tell the gateway that this type is defined within\nanother service, while the "),e("code",[t._v("External")]),t._v(" flags these fields as being owned by the other service (there are several other annotations\navailable that you are encouraged to read about).")]),t._v(" "),e("p",[t._v("Once you have annotated your types, you need to tell "),e("code",[t._v("Federation")]),t._v(" how to resolve those types. Federation uses a slightly\ndifferent mechanism in resolving types from a standard GraphQL query, so for each type that you wish to support, you will\nneed to add an "),e("code",[t._v("EntityResolver")]),t._v(":")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("EntityResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CharacterService"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CharacterArgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" \n ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromEffect"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getCharacter"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n")])])]),e("p",[e("code",[t._v("EntityResolvers")]),t._v(' like normal field resolvers also supports a "metadata" variant which can be used to inspect the requested\nfields and potentially optimize the resulting query. You can use the provided helper method if you need to access the metadata field:')]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("EntityResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromMetadata"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CharacterArgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("field "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" args "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("field"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fields"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forall"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("succeed"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Nil"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" None"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromEffect"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getCharacter"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("In the above we need to define an resolver which takes an "),e("code",[t._v("R")]),t._v(" environment type,\nan "),e("code",[t._v("A")]),t._v(" which has an implicit "),e("code",[t._v("ArgBuilder")]),t._v(" and an "),e("code",[t._v("Option[Out]")]),t._v(" where "),e("code",[t._v("Out")]),t._v(" has an implicit\n"),e("code",[t._v("Schema[R, Out]")]),t._v(" available. Creating the above we can now add these resolvers to our federated schema like so:")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" aResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" additionalResolvers"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("_"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("You can now use the resulting "),e("code",[t._v("GraphQL[R]")]),t._v(" to start querying. You can also see the full code example "),e("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/federation",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),e("OutboundLink")],1)]),t._v(" "),e("h2",{attrs:{id:"tracing"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#tracing"}},[t._v("#")]),t._v(" Tracing")]),t._v(" "),e("p",[t._v("Federated tracing is slightly different from standard apollo-tracing thus it comes with its own wrapper defined in the "),e("code",[t._v("caliban-federation")]),t._v(" module.")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("federation"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tracing"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("ApolloFederatedTracing\n\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" resolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" additionalResolvers"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" _"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@ ApolloFederatedTracing"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wrapper\n")])])]),e("p",[t._v("In federated tracing the gateway communicates with the implementing service via a header "),e("code",[t._v("apollo-federation-include-trace")]),t._v(",\nfor now the only value it can send is "),e("code",[t._v("ftv1")]),t._v(". Thus if you detect this header then you should enable tracing otherwise you can disable it.")]),t._v(" "),e("p",[t._v("If you are using one of the wrappers you are done, they will automatically detect when the gateway\nenables tracing on a request. However, if you are calling the "),e("code",[t._v("interpreter.execute")]),t._v(" independently or you have some other custom\nset up you will need to add one more step to enable tracing.")]),t._v(" "),e("p",[t._v("If you wish to enable it manually (after detecting the header with your preferred framework) you can call: "),e("code",[t._v("request.withFederatedTracing")]),t._v(" which will return a new "),e("code",[t._v("GraphQLRequest")]),t._v(" that informs the wrapper\nthat it should include tracing data as part of the response extensions.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{396:function(t,a,e){"use strict";e.r(a);var s=e(54),n=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"federation"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#federation"}},[t._v("#")]),t._v(" Federation")]),t._v(" "),e("p",[e("strong",[t._v("Federation")]),t._v(" is an optional module which can be included in your configuration to enroll with a federated schema.")]),t._v(" "),e("h2",{attrs:{id:"dependencies"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#dependencies"}},[t._v("#")]),t._v(" Dependencies")]),t._v(" "),e("p",[e("code",[t._v("caliban-federation")]),t._v(" only depends on "),e("code",[t._v("caliban-core")]),t._v(" and is very unobtrusive.")]),t._v(" "),e("p",[t._v("To use, add the following line to your "),e("code",[t._v("build.sbt")]),t._v(" file:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban-federation" % "1.2.2"\n')])])]),e("h2",{attrs:{id:"federating"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#federating"}},[t._v("#")]),t._v(" Federating")]),t._v(" "),e("p",[t._v("Federation allows graphs to become part of a larger graph without having to share models or create brittle\nschema stitching code at the gateway level.")]),t._v(" "),e("p",[t._v("You can read more about federation and why it may be useful "),e("a",{attrs:{href:"https://www.apollographql.com/docs/apollo-server/federation/introduction/",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),e("OutboundLink")],1),t._v(".")]),t._v(" "),e("p",[t._v("Federation creates a wrapper over your existing schema so that it can add the necessary hooks to support\ninteraction with the gateway.")]),t._v(" "),e("p",[t._v("If you already have a graph you can add federation simply by calling the wrapper function "),e("code",[t._v("federate")])]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("federation"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("_\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" schema"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Queries"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n characters "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" List"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Amos"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" federatedSchema"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("This will wrap the bare minimum schema additions around your API so that the gateway will recognize your schema.\nTo actually enable entity resolution you will need to do a bit of leg work.")]),t._v(" "),e("p",[t._v('First, any types that will be "resolvable" need to be annotated with a '),e("code",[t._v("@key")]),t._v(" directive. You can use a helper function found\nin the "),e("code",[t._v("federation")]),t._v(" package to help with that.")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Key"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("The "),e("code",[t._v('"name"')]),t._v(" field is a field selector minus the outer braces.")]),t._v(" "),e("p",[t._v("If you need to extend a type from another service, you will need to define a stub version of it in the current service\nand annotate it with the "),e("code",[t._v("@extends")]),t._v(" annotation")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Key"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"season episode"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n"),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Extend"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Episode"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("External"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" season"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@GQLDirective")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("External"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" episode"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" cast"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("Note the additional annotations we needed in this case. "),e("code",[t._v("Extend")]),t._v(" is needed to tell the gateway that this type is defined within\nanother service, while the "),e("code",[t._v("External")]),t._v(" flags these fields as being owned by the other service (there are several other annotations\navailable that you are encouraged to read about).")]),t._v(" "),e("p",[t._v("Once you have annotated your types, you need to tell "),e("code",[t._v("Federation")]),t._v(" how to resolve those types. Federation uses a slightly\ndifferent mechanism in resolving types from a standard GraphQL query, so for each type that you wish to support, you will\nneed to add an "),e("code",[t._v("EntityResolver")]),t._v(":")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("EntityResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CharacterService"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CharacterArgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" \n ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromEffect"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getCharacter"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n")])])]),e("p",[e("code",[t._v("EntityResolvers")]),t._v(' like normal field resolvers also supports a "metadata" variant which can be used to inspect the requested\nfields and potentially optimize the resulting query. You can use the provided helper method if you need to access the metadata field:')]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("EntityResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromMetadata"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CharacterArgs"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("field "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" args "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("field"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fields"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("forall"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"name"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("succeed"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Character"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Nil"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" None"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" ZQuery"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("fromEffect"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getCharacter"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("In the above we need to define an resolver which takes an "),e("code",[t._v("R")]),t._v(" environment type,\nan "),e("code",[t._v("A")]),t._v(" which has an implicit "),e("code",[t._v("ArgBuilder")]),t._v(" and an "),e("code",[t._v("Option[Out]")]),t._v(" where "),e("code",[t._v("Out")]),t._v(" has an implicit\n"),e("code",[t._v("Schema[R, Out]")]),t._v(" available. Creating the above we can now add these resolvers to our federated schema like so:")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[t._v("federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" aResolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" additionalResolvers"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v("_"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),e("p",[t._v("You can now use the resulting "),e("code",[t._v("GraphQL[R]")]),t._v(" to start querying. You can also see the full code example "),e("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/examples/src/main/scala/example/federation",target:"_blank",rel:"noopener noreferrer"}},[t._v("here"),e("OutboundLink")],1)]),t._v(" "),e("h2",{attrs:{id:"tracing"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#tracing"}},[t._v("#")]),t._v(" Tracing")]),t._v(" "),e("p",[t._v("Federated tracing is slightly different from standard apollo-tracing thus it comes with its own wrapper defined in the "),e("code",[t._v("caliban-federation")]),t._v(" module.")]),t._v(" "),e("div",{staticClass:"language-scala extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scala"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("federation"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tracing"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("ApolloFederatedTracing\n\n\n"),e("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" federate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("schema"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" resolver"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" additionalResolvers"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" _"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@ ApolloFederatedTracing"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wrapper\n")])])]),e("p",[t._v("In federated tracing the gateway communicates with the implementing service via a header "),e("code",[t._v("apollo-federation-include-trace")]),t._v(",\nfor now the only value it can send is "),e("code",[t._v("ftv1")]),t._v(". Thus if you detect this header then you should enable tracing otherwise you can disable it.")]),t._v(" "),e("p",[t._v("If you are using one of the wrappers you are done, they will automatically detect when the gateway\nenables tracing on a request. However, if you are calling the "),e("code",[t._v("interpreter.execute")]),t._v(" independently or you have some other custom\nset up you will need to add one more step to enable tracing.")]),t._v(" "),e("p",[t._v("If you wish to enable it manually (after detecting the header with your preferred framework) you can call: "),e("code",[t._v("request.withFederatedTracing")]),t._v(" which will return a new "),e("code",[t._v("GraphQLRequest")]),t._v(" that informs the wrapper\nthat it should include tracing data as part of the response extensions.")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/15.1b9de682.js b/docs/assets/js/15.baaf003f.js similarity index 82% rename from docs/assets/js/15.1b9de682.js rename to docs/assets/js/15.baaf003f.js index b8e25d445b..5af11ae32f 100644 --- a/docs/assets/js/15.1b9de682.js +++ b/docs/assets/js/15.baaf003f.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{400:function(t,a,s){"use strict";s.r(a);var n=s(54),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"middleware"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),s("p",[t._v("Caliban allows you to perform additional actions at various levels of a query processing, via the concept of "),s("code",[t._v("Wrapper")]),t._v(". Using wrappers, you can:")]),t._v(" "),s("ul",[s("li",[t._v("verify that a query doesn't reach some limit (e.g. depth, complexity)")]),t._v(" "),s("li",[t._v("modify a query before it's executed")]),t._v(" "),s("li",[t._v("add timeouts to queries or fields")]),t._v(" "),s("li",[t._v("log each field execution time")]),t._v(" "),s("li",[t._v("support "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-cache-control",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Caching"),s("OutboundLink")],1),t._v(" or anything similar")]),t._v(" "),s("li",[t._v("etc.")])]),t._v(" "),s("h2",{attrs:{id:"wrapper-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#wrapper-types"}},[t._v("#")]),t._v(" Wrapper types")]),t._v(" "),s("p",[t._v("There are 6 basic types of wrappers:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("OverallWrapper")]),t._v(" to wrap the whole query processing")]),t._v(" "),s("li",[s("code",[t._v("ParsingWrapper")]),t._v(" to wrap the query parsing only")]),t._v(" "),s("li",[s("code",[t._v("ValidationWrapper")]),t._v(" to wrap the query validation only")]),t._v(" "),s("li",[s("code",[t._v("ExecutionWrapper")]),t._v(" to wrap the query execution only")]),t._v(" "),s("li",[s("code",[t._v("FieldWrapper")]),t._v(" to wrap each field execution")]),t._v(" "),s("li",[s("code",[t._v("IntrospectionWrapper")]),t._v(" to wrap the introspection query only")])]),t._v(" "),s("p",[t._v("Each one requires a function that takes a "),s("code",[t._v("ZIO")]),t._v(" or "),s("code",[t._v("ZQuery")]),t._v(" computation together with some contextual information (e.g. the query string) and should return another computation.")]),t._v(" "),s("p",[t._v("Let's see how to implement a wrapper that times out the whole query if its processing takes longer than 1 minute.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" wrapper "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" OverallWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" wrap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n process"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" ZIO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" ZIO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n process"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" minute"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("map"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getOrElse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n NullValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("s"),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Query was interrupted after 1 minute:\\n${request.query}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("You can also combine wrappers using "),s("code",[t._v("|+|")]),t._v(" and create a wrapper that requires an effect to be run at each query using "),s("code",[t._v("EffectfulWrapper")]),t._v(".")]),t._v(" "),s("p",[t._v("To use your wrapper, call "),s("code",[t._v("GraphQL#withWrapper")]),t._v(" or its alias "),s("code",[t._v("@@")]),t._v(".")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("withWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("wrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// or")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@ wrapper\n")])])]),s("h2",{attrs:{id:"pre-defined-wrappers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#pre-defined-wrappers"}},[t._v("#")]),t._v(" Pre-defined wrappers")]),t._v(" "),s("p",[t._v("Caliban comes with a few pre-made wrappers in "),s("code",[t._v("caliban.wrappers.Wrappers")]),t._v(":")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("maxDepth")]),t._v(" returns a wrapper that fails queries whose depth is higher than a given value")]),t._v(" "),s("li",[s("code",[t._v("maxFields")]),t._v(" returns a wrapper that fails queries whose number of fields is higher than a given value")]),t._v(" "),s("li",[s("code",[t._v("timeout")]),t._v(" returns a wrapper that fails queries taking more than a specified time")]),t._v(" "),s("li",[s("code",[t._v("printErrors")]),t._v(" returns a wrapper that prints errors")]),t._v(" "),s("li",[s("code",[t._v("printSlowQueries")]),t._v(" returns a wrapper that prints slow queries")]),t._v(" "),s("li",[s("code",[t._v("onSlowQueries")]),t._v(" returns a wrapper that can run a given function on slow queries")])]),t._v(" "),s("p",[t._v("In addition to those, Caliban also ships with some non-spec but standard wrappers")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("caliban.wrappers.ApolloTracing.apolloTracing")]),t._v(" returns a wrapper that adds tracing data into the "),s("code",[t._v("extensions")]),t._v(" field of each response following "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(" format.")]),t._v(" "),s("li",[s("code",[t._v("caliban.wrappers.ApolloCaching.apolloCaching")]),t._v(" returns a wrapper that adds caching hints to properly annotated fields using the "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-cache-control",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Caching"),s("OutboundLink")],1),t._v(" format.")]),t._v(" "),s("li",[s("code",[t._v("caliban.wrappers.ApolloPersistedQueries.apolloPersistedQueries")]),t._v(" returns a wrapper that caches and retrieves query using a hash using the "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-link-persisted-queries",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Persisted Queries"),s("OutboundLink")],1),t._v(" format.")])]),t._v(" "),s("p",[t._v("They can be used like this:")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n maxDepth"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" seconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n printSlowQueries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v(" millis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n apolloTracing @@\n apolloCaching\n")])])]),s("h2",{attrs:{id:"wrapping-the-interpreter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#wrapping-the-interpreter"}},[t._v("#")]),t._v(" Wrapping the interpreter")]),t._v(" "),s("p",[t._v("All the wrappers mentioned above require that you don't modify the environment "),s("code",[t._v("R")]),t._v(" and the error type which is always a "),s("code",[t._v("CalibanError")]),t._v(". It is also possible to wrap your "),s("code",[t._v("GraphQLInterpreter")]),t._v(" by calling "),s("code",[t._v("wrapExecutionWith")]),t._v(" on it. This method takes in a function "),s("code",[t._v("f")]),t._v(" and returns a new "),s("code",[t._v("GraphQLInterpreter")]),t._v(" that will wrap the "),s("code",[t._v("execute")]),t._v(" method with this function "),s("code",[t._v("f")]),t._v(".")]),t._v(" "),s("p",[t._v("It is used internally to implement "),s("code",[t._v("mapError")]),t._v(" (customize errors) and "),s("code",[t._v("provide")]),t._v(" (eliminate the environment), but you can use it for other purposes such as adding a general timeout, logging response times, etc.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// change error type to String")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i2"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mapError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("toString"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// provide the environment")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i3"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("provide"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// add a timeout on every query execution")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i4"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wrapExecutionWith"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),t._v(" seconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("map"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getOrElse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NullValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Timeout!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("h2",{attrs:{id:"customizing-error-responses"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-error-responses"}},[t._v("#")]),t._v(" Customizing error responses")]),t._v(" "),s("p",[t._v("During various phases of executing a query, an error may occur. Caliban renders the different instances of "),s("code",[t._v("CalibanError")]),t._v(" to a GraphQL spec compliant response. As a user, you will most likely encounter "),s("code",[t._v("ExecutionError")]),t._v(" at some point because this will encapsulate the errors in the error channel of your effects. For Caliban to be able to render some basic message about the error that occured during query execution, it is important that your error extends "),s("code",[t._v("Throwable")]),t._v(".")]),t._v(" "),s("p",[t._v("For more meaningful error handling, GraphQL spec allows for an "),s("a",{attrs:{href:"http://spec.graphql.org/June2018/#example-fce18",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("extension")]),s("OutboundLink")],1),t._v(" object in the error response. This object may include, for instance, "),s("code",[t._v("code")]),t._v(" information to model enum-like error codes that can be handled by a front-end. In order to generate this information, one can use the "),s("code",[t._v("mapError")]),t._v(" function on a "),s("code",[t._v("GraphQLInterpreter")]),t._v(". An example is provided below in which we map a custom domain error within an "),s("code",[t._v("ExecutionError")]),t._v(" to a meaningful error code.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("sealed")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("trait")]),t._v(" ExampleAppEncodableError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" Throwable "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" errorCode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" UnauthorizedError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" ExampleAppEncodableError "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" errorCode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"UNAUTHORIZED"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" withErrorCodeExtensions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n interpreter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" interpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mapError "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err @ ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exampleError"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ExampleAppEncodableError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exampleError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("errorCode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ExecutionError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EXECUTION_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ValidationError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"VALIDATION_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ParsingError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"PARSING_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{400:function(t,a,s){"use strict";s.r(a);var n=s(54),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"middleware"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#middleware"}},[t._v("#")]),t._v(" Middleware")]),t._v(" "),s("p",[t._v("Caliban allows you to perform additional actions at various levels of a query processing, via the concept of "),s("code",[t._v("Wrapper")]),t._v(". Using wrappers, you can:")]),t._v(" "),s("ul",[s("li",[t._v("verify that a query doesn't reach some limit (e.g. depth, complexity)")]),t._v(" "),s("li",[t._v("modify a query before it's executed")]),t._v(" "),s("li",[t._v("add timeouts to queries or fields")]),t._v(" "),s("li",[t._v("log each field execution time")]),t._v(" "),s("li",[t._v("support "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-cache-control",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Caching"),s("OutboundLink")],1),t._v(" or anything similar")]),t._v(" "),s("li",[t._v("etc.")])]),t._v(" "),s("h2",{attrs:{id:"wrapper-types"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#wrapper-types"}},[t._v("#")]),t._v(" Wrapper types")]),t._v(" "),s("p",[t._v("There are 6 basic types of wrappers:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("OverallWrapper")]),t._v(" to wrap the whole query processing")]),t._v(" "),s("li",[s("code",[t._v("ParsingWrapper")]),t._v(" to wrap the query parsing only")]),t._v(" "),s("li",[s("code",[t._v("ValidationWrapper")]),t._v(" to wrap the query validation only")]),t._v(" "),s("li",[s("code",[t._v("ExecutionWrapper")]),t._v(" to wrap the query execution only")]),t._v(" "),s("li",[s("code",[t._v("FieldWrapper")]),t._v(" to wrap each field execution")]),t._v(" "),s("li",[s("code",[t._v("IntrospectionWrapper")]),t._v(" to wrap the introspection query only")])]),t._v(" "),s("p",[t._v("Each one requires a function that takes a "),s("code",[t._v("ZIO")]),t._v(" or "),s("code",[t._v("ZQuery")]),t._v(" computation together with some contextual information (e.g. the query string) and should return another computation.")]),t._v(" "),s("p",[t._v("Let's see how to implement a wrapper that times out the whole query if its processing takes longer than 1 minute.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" wrapper "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" OverallWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" wrap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n process"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" ZIO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" ZIO"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLRequest"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n process"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" minute"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("map"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getOrElse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n NullValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("s"),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Query was interrupted after 1 minute:\\n${request.query}"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("You can also combine wrappers using "),s("code",[t._v("|+|")]),t._v(" and create a wrapper that requires an effect to be run at each query using "),s("code",[t._v("EffectfulWrapper")]),t._v(".")]),t._v(" "),s("p",[t._v("To use your wrapper, call "),s("code",[t._v("GraphQL#withWrapper")]),t._v(" or its alias "),s("code",[t._v("@@")]),t._v(".")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("withWrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("wrapper"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// or")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@ wrapper\n")])])]),s("h2",{attrs:{id:"pre-defined-wrappers"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#pre-defined-wrappers"}},[t._v("#")]),t._v(" Pre-defined wrappers")]),t._v(" "),s("p",[t._v("Caliban comes with a few pre-made wrappers in "),s("code",[t._v("caliban.wrappers.Wrappers")]),t._v(":")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("maxDepth")]),t._v(" returns a wrapper that fails queries whose depth is higher than a given value")]),t._v(" "),s("li",[s("code",[t._v("maxFields")]),t._v(" returns a wrapper that fails queries whose number of fields is higher than a given value")]),t._v(" "),s("li",[s("code",[t._v("timeout")]),t._v(" returns a wrapper that fails queries taking more than a specified time")]),t._v(" "),s("li",[s("code",[t._v("printErrors")]),t._v(" returns a wrapper that prints errors")]),t._v(" "),s("li",[s("code",[t._v("printSlowQueries")]),t._v(" returns a wrapper that prints slow queries")]),t._v(" "),s("li",[s("code",[t._v("onSlowQueries")]),t._v(" returns a wrapper that can run a given function on slow queries")])]),t._v(" "),s("p",[t._v("In addition to those, Caliban also ships with some non-spec but standard wrappers")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("caliban.wrappers.ApolloTracing.apolloTracing")]),t._v(" returns a wrapper that adds tracing data into the "),s("code",[t._v("extensions")]),t._v(" field of each response following "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(" format.")]),t._v(" "),s("li",[s("code",[t._v("caliban.wrappers.ApolloCaching.apolloCaching")]),t._v(" returns a wrapper that adds caching hints to properly annotated fields using the "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-cache-control",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Caching"),s("OutboundLink")],1),t._v(" format.")]),t._v(" "),s("li",[s("code",[t._v("caliban.wrappers.ApolloPersistedQueries.apolloPersistedQueries")]),t._v(" returns a wrapper that caches and retrieves query using a hash using the "),s("a",{attrs:{href:"https://github.com/apollographql/apollo-link-persisted-queries",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Persisted Queries"),s("OutboundLink")],1),t._v(" format.")])]),t._v(" "),s("p",[t._v("They can be used like this:")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n maxDepth"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" seconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n printSlowQueries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v(" millis"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" @@\n apolloTracing @@\n apolloCaching\n")])])]),s("h2",{attrs:{id:"wrapping-the-interpreter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#wrapping-the-interpreter"}},[t._v("#")]),t._v(" Wrapping the interpreter")]),t._v(" "),s("p",[t._v("All the wrappers mentioned above require that you don't modify the environment "),s("code",[t._v("R")]),t._v(" and the error type which is always a "),s("code",[t._v("CalibanError")]),t._v(". It is also possible to wrap your "),s("code",[t._v("GraphQLInterpreter")]),t._v(" by calling "),s("code",[t._v("wrapExecutionWith")]),t._v(" on it. This method takes in a function "),s("code",[t._v("f")]),t._v(" and returns a new "),s("code",[t._v("GraphQLInterpreter")]),t._v(" that will wrap the "),s("code",[t._v("execute")]),t._v(" method with this function "),s("code",[t._v("f")]),t._v(".")]),t._v(" "),s("p",[t._v("It is used internally to implement "),s("code",[t._v("mapError")]),t._v(" (customize errors) and "),s("code",[t._v("provide")]),t._v(" (eliminate the environment), but you can use it for other purposes such as adding a general timeout, logging response times, etc.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// change error type to String")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i2"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mapError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("toString"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// provide the environment")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i3"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("provide"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("myEnv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// add a timeout on every query execution")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" i4"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MyEnv "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("with")]),t._v(" Clock"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("wrapExecutionWith"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("timeout"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("30")]),t._v(" seconds"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("map"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("getOrElse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("NullValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Timeout!"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("h2",{attrs:{id:"customizing-error-responses"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#customizing-error-responses"}},[t._v("#")]),t._v(" Customizing error responses")]),t._v(" "),s("p",[t._v("During various phases of executing a query, an error may occur. Caliban renders the different instances of "),s("code",[t._v("CalibanError")]),t._v(" to a GraphQL spec compliant response. As a user, you will most likely encounter "),s("code",[t._v("ExecutionError")]),t._v(" at some point because this will encapsulate the errors in the error channel of your effects. For Caliban to be able to render some basic message about the error that occured during query execution, it is important that your error extends "),s("code",[t._v("Throwable")]),t._v(".")]),t._v(" "),s("p",[t._v("For more meaningful error handling, GraphQL spec allows for an "),s("a",{attrs:{href:"http://spec.graphql.org/June2018/#example-fce18",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("extension")]),s("OutboundLink")],1),t._v(" object in the error response. This object may include, for instance, "),s("code",[t._v("code")]),t._v(" information to model enum-like error codes that can be handled by a front-end. In order to generate this information, one can use the "),s("code",[t._v("mapError")]),t._v(" function on a "),s("code",[t._v("GraphQLInterpreter")]),t._v(". An example is provided below in which we map a custom domain error within an "),s("code",[t._v("ExecutionError")]),t._v(" to a meaningful error code.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("sealed")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("trait")]),t._v(" ExampleAppEncodableError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" Throwable "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" errorCode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("object")]),t._v(" UnauthorizedError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" ExampleAppEncodableError "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("override")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" errorCode"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"UNAUTHORIZED"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" withErrorCodeExtensions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n interpreter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLInterpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" CalibanError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" interpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mapError "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err @ ExecutionError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exampleError"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ExampleAppEncodableError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" _"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exampleError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("errorCode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ExecutionError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"EXECUTION_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ValidationError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"VALIDATION_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" err"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ParsingError "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v("\n err"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("copy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("extensions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Some"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ObjectValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"errorCode"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" StringValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"PARSING_ERROR"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"wrapping-the-graphql"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#wrapping-the-graphql"}},[t._v("#")]),t._v(" Wrapping the GraphQL")]),t._v(" "),s("p",[t._v("If you need to implement new functionality that involves not just changes to execution but also to the underlying\nschema you can use the higher-level "),s("code",[t._v("GraphQLAspect")]),t._v(" which allows full control of the resulting "),s("code",[t._v("GraphQL")]),t._v(" that it wraps.")]),t._v(" "),s("p",[t._v("Here is such an example that is part of the "),s("code",[t._v("federation")]),t._v(" package which makes a schema available to be used as a sub-graph in\na federated graph:")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" federate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("original"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Schema"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("_\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Query"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _service"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" _Service"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n _fieldSet"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" FieldSet "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" FieldSet"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Query"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("_service "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" _Service"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("original"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("render"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" federationDirectives"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" original\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("lazy")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" federated"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQLAspect"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" \n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" GraphQLAspect"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" apply"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("original"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("R1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n federate"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("original"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/8.709919e3.js b/docs/assets/js/8.a27dc52c.js similarity index 97% rename from docs/assets/js/8.709919e3.js rename to docs/assets/js/8.a27dc52c.js index a501763838..356175f1a0 100644 --- a/docs/assets/js/8.709919e3.js +++ b/docs/assets/js/8.a27dc52c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{393:function(e,r,t){"use strict";t.r(r);var n=t(54),a=Object(n.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"about"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#about"}},[e._v("#")]),e._v(" About")]),e._v(" "),t("p",[e._v("Caliban is a project developed by Pierre Ricadat aka "),t("a",{attrs:{href:"https://github.com/ghostdogpr",target:"_blank",rel:"noopener noreferrer"}},[e._v("@ghostdogpr"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("The name is inspired by the SF novel and tv series "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Caliban%27s_War",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Expanse"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[t("strong",[e._v("Thanks")]),e._v(":")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/deckerst",target:"_blank",rel:"noopener noreferrer"}},[e._v("@deckerst"),t("OutboundLink")],1),e._v(" for the logo")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/yoohaemin",target:"_blank",rel:"noopener noreferrer"}},[e._v("@yoohaemin"),t("OutboundLink")],1),e._v(", "),t("a",{attrs:{href:"https://github.com/adamgfraser",target:"_blank",rel:"noopener noreferrer"}},[e._v("@adamgfraser"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://github.com/jdegoes",target:"_blank",rel:"noopener noreferrer"}},[e._v("@jdegoes"),t("OutboundLink")],1),e._v(" for the early feedback")]),e._v(" "),t("li",[e._v("the "),t("a",{attrs:{href:"https://morpheusgraphql.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Morpheus"),t("OutboundLink")],1),e._v(" library in Haskell for the inspiration leading to the GraphQL backend implementation")]),e._v(" "),t("li",[e._v("the "),t("a",{attrs:{href:"https://github.com/dillonkearns/elm-graphql",target:"_blank",rel:"noopener noreferrer"}},[e._v("elm-graphql"),t("OutboundLink")],1),e._v(" library for the inspiration leading to the GraphQL client implementation")]),e._v(" "),t("li",[e._v("all Caliban's "),t("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/graphs/contributors",target:"_blank",rel:"noopener noreferrer"}},[e._v("contributors"),t("OutboundLink")],1),e._v("!")])])])}),[],!1,null,null,null);r.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{394:function(e,r,t){"use strict";t.r(r);var n=t(54),a=Object(n.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"about"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#about"}},[e._v("#")]),e._v(" About")]),e._v(" "),t("p",[e._v("Caliban is a project developed by Pierre Ricadat aka "),t("a",{attrs:{href:"https://github.com/ghostdogpr",target:"_blank",rel:"noopener noreferrer"}},[e._v("@ghostdogpr"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[e._v("The name is inspired by the SF novel and tv series "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Caliban%27s_War",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Expanse"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("p",[t("strong",[e._v("Thanks")]),e._v(":")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/deckerst",target:"_blank",rel:"noopener noreferrer"}},[e._v("@deckerst"),t("OutboundLink")],1),e._v(" for the logo")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/yoohaemin",target:"_blank",rel:"noopener noreferrer"}},[e._v("@yoohaemin"),t("OutboundLink")],1),e._v(", "),t("a",{attrs:{href:"https://github.com/adamgfraser",target:"_blank",rel:"noopener noreferrer"}},[e._v("@adamgfraser"),t("OutboundLink")],1),e._v(" and "),t("a",{attrs:{href:"https://github.com/jdegoes",target:"_blank",rel:"noopener noreferrer"}},[e._v("@jdegoes"),t("OutboundLink")],1),e._v(" for the early feedback")]),e._v(" "),t("li",[e._v("the "),t("a",{attrs:{href:"https://morpheusgraphql.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Morpheus"),t("OutboundLink")],1),e._v(" library in Haskell for the inspiration leading to the GraphQL backend implementation")]),e._v(" "),t("li",[e._v("the "),t("a",{attrs:{href:"https://github.com/dillonkearns/elm-graphql",target:"_blank",rel:"noopener noreferrer"}},[e._v("elm-graphql"),t("OutboundLink")],1),e._v(" library for the inspiration leading to the GraphQL client implementation")]),e._v(" "),t("li",[e._v("all Caliban's "),t("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/graphs/contributors",target:"_blank",rel:"noopener noreferrer"}},[e._v("contributors"),t("OutboundLink")],1),e._v("!")])])])}),[],!1,null,null,null);r.default=a.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/9.5a114f0d.js b/docs/assets/js/9.d4175935.js similarity index 99% rename from docs/assets/js/9.5a114f0d.js rename to docs/assets/js/9.d4175935.js index 40ac1fa35b..4afa4b3b15 100644 --- a/docs/assets/js/9.5a114f0d.js +++ b/docs/assets/js/9.d4175935.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{394:function(t,a,s){"use strict";s.r(a);var e=s(54),r=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"getting-started"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting Started")]),t._v(" "),s("p",[s("strong",[t._v("Caliban")]),t._v(" is a purely functional library for creating GraphQL servers and clients in Scala.")]),t._v(" "),s("p",[t._v("For more details on Caliban Client, see the "),s("RouterLink",{attrs:{to:"/docs/client.html"}},[t._v("dedicated section")]),t._v(". The rest of this page is about the backend part of the library.")],1),t._v(" "),s("p",[t._v("The design principles of Caliban are the following:")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("pure interface")]),t._v(": errors and effects are returned explicitly (no exceptions thrown), all returned types are referentially transparent (no usage of "),s("code",[t._v("Future")]),t._v(").")]),t._v(" "),s("li",[s("strong",[t._v("minimal amount of boilerplate")]),t._v(": no need to manually define a schema for every type in your API. Let the compiler do the boring work.")]),t._v(" "),s("li",[s("strong",[t._v("excellent interoperability")]),t._v(": out-of-the-box support for major HTTP server libraries ("),s("a",{attrs:{href:"https://http4s.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http4s"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://doc.akka.io/docs/akka-http/current/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Akka HTTP"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.playframework.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Play"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/finagle/finch",target:"_blank",rel:"noopener noreferrer"}},[t._v("Finch"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/dream11/zio-http",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO HTTP"),s("OutboundLink")],1),t._v("), effect types (Future, "),s("a",{attrs:{href:"https://zio.dev/",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://typelevel.org/cats-effect/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Cats Effect"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://monix.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Monix"),s("OutboundLink")],1),t._v("), Json libraries ("),s("a",{attrs:{href:"https://circe.github.io/circe/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Circe"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/playframework/play-json",target:"_blank",rel:"noopener noreferrer"}},[t._v("Play Json"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/zio/zio-json",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO Json"),s("OutboundLink")],1),t._v("), various integrations ("),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.apollographql.com/docs/federation/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Federation"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://tapir.softwaremill.com/en/latest/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tapir"),s("OutboundLink")],1),t._v(", etc.) and more.")])]),t._v(" "),s("h2",{attrs:{id:"dependencies"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dependencies"}},[t._v("#")]),t._v(" Dependencies")]),t._v(" "),s("p",[t._v("To use "),s("code",[t._v("caliban")]),t._v(", add the following line in your "),s("code",[t._v("build.sbt")]),t._v(" file:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban" % "1.2.2"\n')])])]),s("p",[t._v("The following modules are optional:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban-http4s" % "1.2.2" // routes for http4s\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-akka-http" % "1.2.2" // routes for akka-http\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-play" % "1.2.2" // routes for play\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-finch" % "1.2.2" // routes for finch\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-zio-http" % "1.2.2" // routes for zio-http\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-cats" % "1.2.2" // interop with cats effect\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-monix" % "1.2.2" // interop with monix\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-tapir" % "1.2.2" // interop with tapir\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-federation" % "1.2.2" // interop with apollo federation\n')])])]),s("h2",{attrs:{id:"a-simple-example"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#a-simple-example"}},[t._v("#")]),t._v(" A simple example")]),t._v(" "),s("p",[t._v("Creating a GraphQL API with Caliban is as simple as creating a case class. Indeed, the whole GraphQL schema will be derived from a case class structure (its fields and the other types it references), and the resolver is just an instance of that case class.")]),t._v(" "),s("p",[t._v("Let's say we have a class "),s("code",[t._v("Character")]),t._v(" and 2 functions: "),s("code",[t._v("getCharacters")]),t._v(" and "),s("code",[t._v("getCharacter")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" age"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" getCharacters"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" getCharacter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Option"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n")])])]),s("p",[t._v("Let's create a case class named "),s("code",[t._v("Queries")]),t._v(" that will represent our API, with 2 fields named and modeled after the functions we want to expose (a "),s("em",[t._v("record of functions")]),t._v("). We then create a value of this class that calls our actual functions. This is our resolver.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// schema")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" CharacterName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n character"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" CharacterName "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" Option"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// resolver")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" queries "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("getCharacters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" args "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" getCharacter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("The next step is creating our GraphQL API definition. First, we wrap our query resolver inside a "),s("code",[t._v("RootResolver")]),t._v(", the root object that contains queries, mutations and subscriptions. Only queries are mandatory.\nThen we can call the "),s("code",[t._v("graphQL")]),t._v(" function which will turn our simple resolver value into a GraphQL API definition.\nThe whole schema will be derived at compile time, meaning that if it compiles, it will be able to serve it.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("graphQL\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("RootResolver\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("You can use "),s("code",[t._v("api.render")]),t._v(" to visualize the schema generated, in this case:")]),t._v(" "),s("div",{staticClass:"language-graphql extra-class"},[s("pre",{pre:!0,attrs:{class:"language-graphql"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("age")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("Int")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Queries")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("characters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("character")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("In order to process requests, you need to turn your API into an interpreter, which can be done easily by calling "),s("code",[t._v(".interpreter")]),t._v(".\nAn interpreter is a light wrapper around the API definition that allows plugging in some middleware and possibly modifying the environment and error types (see "),s("RouterLink",{attrs:{to:"/docs/middleware.html"}},[t._v("Middleware")]),t._v(" for more info).\nCreating the interpreter may fail with a "),s("code",[t._v("ValidationError")]),t._v(" if some type is found invalid.")],1),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n interpreter "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" api"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("interpreter\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("yield")]),t._v(" interpreter\n")])])]),s("p",[t._v("Now you can call "),s("code",[t._v("interpreter.execute")]),t._v(" with a given GraphQL query, and you will get an "),s("code",[t._v("ZIO[R, Nothing, GraphQLResponse[CalibanError]]")]),t._v(" as a response, with "),s("code",[t._v("GraphQLResponse")]),t._v(" defined as follows:")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v("E"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ResponseValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" errors"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("E"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("Use "),s("code",[t._v("ResponseValue#toString")]),t._v(" to get the JSON representation of the result.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" query "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\n {\n characters {\n name\n }\n }"""')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n result "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" interpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("query"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n _ "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" zio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("putStrLn"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("toString"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("yield")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("A "),s("code",[t._v("CalibanError")]),t._v(" can be:")]),t._v(" "),s("ul",[s("li",[t._v("a "),s("code",[t._v("ParsingError")]),t._v(": the query has invalid syntax")]),t._v(" "),s("li",[t._v("a "),s("code",[t._v("ValidationError")]),t._v(": the query was parsed but does not match the schema")]),t._v(" "),s("li",[t._v("an "),s("code",[t._v("ExecutionError")]),t._v(": an error happened while executing the query")])]),t._v(" "),s("p",[t._v("Caliban itself is not tied to any web framework, you are free to expose this function using the protocol and library of your choice. The "),s("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/adapters/http4s",target:"_blank",rel:"noopener noreferrer"}},[t._v("caliban-http4s"),s("OutboundLink")],1),t._v(" module provides an "),s("code",[t._v("Http4sAdapter")]),t._v(" that exposes an interpreter over HTTP and WebSocket using http4s. There are also similar adapters for Akka HTTP, Play, Finch and zio-http.")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Combining GraphQL APIs")]),t._v(" "),s("p",[t._v("You don't have to define all your root fields into a single case class: you can use smaller case classes and combine "),s("code",[t._v("GraphQL")]),t._v(" objects using the "),s("code",[t._v("|+|")]),t._v(" operator.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" api1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" api2\n")])])]),s("p",[t._v("You can use "),s("code",[t._v(".rename")]),t._v(" to change the names of the generated root types.")])]),t._v(" "),s("h2",{attrs:{id:"mutations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#mutations"}},[t._v("#")]),t._v(" Mutations")]),t._v(" "),s("p",[t._v("Creating mutations is the same as queries, except you pass them as the second argument to "),s("code",[t._v("RootResolver")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" CharacterArgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("deleteCharacter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" CharacterArgs "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" Task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Boolean")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" mutations "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("h2",{attrs:{id:"subscriptions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#subscriptions"}},[t._v("#")]),t._v(" Subscriptions")]),t._v(" "),s("p",[t._v("Similarly, subscriptions are passed as the third argument to "),s("code",[t._v("RootResolver")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("deletedCharacter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ZStream"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" subscriptions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("All the fields of the subscription root case class MUST return "),s("code",[t._v("ZStream")]),t._v(" or "),s("code",[t._v("? => ZStream")]),t._v(" objects. When a subscription request is received, an output stream of "),s("code",[t._v("ResponseValue")]),t._v(" (a "),s("code",[t._v("StreamValue")]),t._v(") will be returned wrapped inside an "),s("code",[t._v("ObjectValue")]),t._v(".")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{397:function(t,a,s){"use strict";s.r(a);var e=s(54),r=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"getting-started"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#getting-started"}},[t._v("#")]),t._v(" Getting Started")]),t._v(" "),s("p",[s("strong",[t._v("Caliban")]),t._v(" is a purely functional library for creating GraphQL servers and clients in Scala.")]),t._v(" "),s("p",[t._v("For more details on Caliban Client, see the "),s("RouterLink",{attrs:{to:"/docs/client.html"}},[t._v("dedicated section")]),t._v(". The rest of this page is about the backend part of the library.")],1),t._v(" "),s("p",[t._v("The design principles of Caliban are the following:")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("pure interface")]),t._v(": errors and effects are returned explicitly (no exceptions thrown), all returned types are referentially transparent (no usage of "),s("code",[t._v("Future")]),t._v(").")]),t._v(" "),s("li",[s("strong",[t._v("minimal amount of boilerplate")]),t._v(": no need to manually define a schema for every type in your API. Let the compiler do the boring work.")]),t._v(" "),s("li",[s("strong",[t._v("excellent interoperability")]),t._v(": out-of-the-box support for major HTTP server libraries ("),s("a",{attrs:{href:"https://http4s.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http4s"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://doc.akka.io/docs/akka-http/current/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Akka HTTP"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.playframework.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Play"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/finagle/finch",target:"_blank",rel:"noopener noreferrer"}},[t._v("Finch"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/dream11/zio-http",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO HTTP"),s("OutboundLink")],1),t._v("), effect types (Future, "),s("a",{attrs:{href:"https://zio.dev/",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://typelevel.org/cats-effect/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Cats Effect"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://monix.io/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Monix"),s("OutboundLink")],1),t._v("), Json libraries ("),s("a",{attrs:{href:"https://circe.github.io/circe/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Circe"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/playframework/play-json",target:"_blank",rel:"noopener noreferrer"}},[t._v("Play Json"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://github.com/zio/zio-json",target:"_blank",rel:"noopener noreferrer"}},[t._v("ZIO Json"),s("OutboundLink")],1),t._v("), various integrations ("),s("a",{attrs:{href:"https://github.com/apollographql/apollo-tracing",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Tracing"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.apollographql.com/docs/federation/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apollo Federation"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://tapir.softwaremill.com/en/latest/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tapir"),s("OutboundLink")],1),t._v(", etc.) and more.")])]),t._v(" "),s("h2",{attrs:{id:"dependencies"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dependencies"}},[t._v("#")]),t._v(" Dependencies")]),t._v(" "),s("p",[t._v("To use "),s("code",[t._v("caliban")]),t._v(", add the following line in your "),s("code",[t._v("build.sbt")]),t._v(" file:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban" % "1.2.2"\n')])])]),s("p",[t._v("The following modules are optional:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('libraryDependencies += "com.github.ghostdogpr" %% "caliban-http4s" % "1.2.2" // routes for http4s\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-akka-http" % "1.2.2" // routes for akka-http\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-play" % "1.2.2" // routes for play\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-finch" % "1.2.2" // routes for finch\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-zio-http" % "1.2.2" // routes for zio-http\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-cats" % "1.2.2" // interop with cats effect\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-monix" % "1.2.2" // interop with monix\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-tapir" % "1.2.2" // interop with tapir\nlibraryDependencies += "com.github.ghostdogpr" %% "caliban-federation" % "1.2.2" // interop with apollo federation\n')])])]),s("h2",{attrs:{id:"a-simple-example"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#a-simple-example"}},[t._v("#")]),t._v(" A simple example")]),t._v(" "),s("p",[t._v("Creating a GraphQL API with Caliban is as simple as creating a case class. Indeed, the whole GraphQL schema will be derived from a case class structure (its fields and the other types it references), and the resolver is just an instance of that case class.")]),t._v(" "),s("p",[t._v("Let's say we have a class "),s("code",[t._v("Character")]),t._v(" and 2 functions: "),s("code",[t._v("getCharacters")]),t._v(" and "),s("code",[t._v("getCharacter")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" age"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" getCharacters"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" getCharacter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Option"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v("\n")])])]),s("p",[t._v("Let's create a case class named "),s("code",[t._v("Queries")]),t._v(" that will represent our API, with 2 fields named and modeled after the functions we want to expose (a "),s("em",[t._v("record of functions")]),t._v("). We then create a value of this class that calls our actual functions. This is our resolver.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// schema")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" CharacterName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("characters"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n character"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" CharacterName "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" Option"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// resolver")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" queries "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("getCharacters"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" args "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" getCharacter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("The next step is creating our GraphQL API definition. First, we wrap our query resolver inside a "),s("code",[t._v("RootResolver")]),t._v(", the root object that contains queries, mutations and subscriptions. Only queries are mandatory.\nThen we can call the "),s("code",[t._v("graphQL")]),t._v(" function which will turn our simple resolver value into a GraphQL API definition.\nThe whole schema will be derived at compile time, meaning that if it compiles, it will be able to serve it.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("GraphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("graphQL\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("caliban"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("RootResolver\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("You can use "),s("code",[t._v("api.render")]),t._v(" to visualize the schema generated, in this case:")]),t._v(" "),s("div",{staticClass:"language-graphql extra-class"},[s("pre",{pre:!0,attrs:{class:"language-graphql"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("age")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("Int")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Queries")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("characters")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("character")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token scalar"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Character")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("In order to process requests, you need to turn your API into an interpreter, which can be done easily by calling "),s("code",[t._v(".interpreter")]),t._v(".\nAn interpreter is a light wrapper around the API definition that allows plugging in some middleware and possibly modifying the environment and error types (see "),s("RouterLink",{attrs:{to:"/docs/middleware.html"}},[t._v("Middleware")]),t._v(" for more info).\nCreating the interpreter may fail with a "),s("code",[t._v("ValidationError")]),t._v(" if some type is found invalid.")],1),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n interpreter "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" api"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("interpreter\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("yield")]),t._v(" interpreter\n")])])]),s("p",[t._v("Now you can call "),s("code",[t._v("interpreter.execute")]),t._v(" with a given GraphQL query, and you will get an "),s("code",[t._v("ZIO[R, Nothing, GraphQLResponse[CalibanError]]")]),t._v(" as a response, with "),s("code",[t._v("GraphQLResponse")]),t._v(" defined as follows:")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" GraphQLResponse"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v("E"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ResponseValue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" errors"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" List"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("E"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("Use "),s("code",[t._v("ResponseValue#toString")]),t._v(" to get the JSON representation of the result.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" query "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token triple-quoted-string string"}},[t._v('"""\n {\n characters {\n name\n }\n }"""')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n result "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" interpreter"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("execute"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("query"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n _ "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("<-")]),t._v(" zio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("console"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("putStrLn"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("toString"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("yield")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("A "),s("code",[t._v("CalibanError")]),t._v(" can be:")]),t._v(" "),s("ul",[s("li",[t._v("a "),s("code",[t._v("ParsingError")]),t._v(": the query has invalid syntax")]),t._v(" "),s("li",[t._v("a "),s("code",[t._v("ValidationError")]),t._v(": the query was parsed but does not match the schema")]),t._v(" "),s("li",[t._v("an "),s("code",[t._v("ExecutionError")]),t._v(": an error happened while executing the query")])]),t._v(" "),s("p",[t._v("Caliban itself is not tied to any web framework, you are free to expose this function using the protocol and library of your choice. The "),s("a",{attrs:{href:"https://github.com/ghostdogpr/caliban/tree/master/adapters/http4s",target:"_blank",rel:"noopener noreferrer"}},[t._v("caliban-http4s"),s("OutboundLink")],1),t._v(" module provides an "),s("code",[t._v("Http4sAdapter")]),t._v(" that exposes an interpreter over HTTP and WebSocket using http4s. There are also similar adapters for Akka HTTP, Play, Finch and zio-http.")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("Combining GraphQL APIs")]),t._v(" "),s("p",[t._v("You don't have to define all your root fields into a single case class: you can use smaller case classes and combine "),s("code",[t._v("GraphQL")]),t._v(" objects using the "),s("code",[t._v("|+|")]),t._v(" operator.")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" api1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" api2\n")])])]),s("p",[t._v("You can use "),s("code",[t._v(".rename")]),t._v(" to change the names of the generated root types.")])]),t._v(" "),s("h2",{attrs:{id:"mutations"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#mutations"}},[t._v("#")]),t._v(" Mutations")]),t._v(" "),s("p",[t._v("Creating mutations is the same as queries, except you pass them as the second argument to "),s("code",[t._v("RootResolver")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" CharacterArgs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("name"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("deleteCharacter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" CharacterArgs "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("=>")]),t._v(" Task"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Boolean")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" mutations "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("h2",{attrs:{id:"subscriptions"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#subscriptions"}},[t._v("#")]),t._v(" Subscriptions")]),t._v(" "),s("p",[t._v("Similarly, subscriptions are passed as the third argument to "),s("code",[t._v("RootResolver")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-scala extra-class"},[s("pre",{pre:!0,attrs:{class:"language-scala"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("case")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" Subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("deletedCharacter"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" ZStream"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Any")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Nothing")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" Character"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" subscriptions "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("val")]),t._v(" api "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" graphQL"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("RootResolver"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("queries"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mutations"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" subscriptions"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("All the fields of the subscription root case class MUST return "),s("code",[t._v("ZStream")]),t._v(" or "),s("code",[t._v("? => ZStream")]),t._v(" objects. When a subscription request is received, an output stream of "),s("code",[t._v("ResponseValue")]),t._v(" (a "),s("code",[t._v("StreamValue")]),t._v(") will be returned wrapped inside an "),s("code",[t._v("ObjectValue")]),t._v(".")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/app.a3c220af.js b/docs/assets/js/app.f34fe59e.js similarity index 90% rename from docs/assets/js/app.a3c220af.js rename to docs/assets/js/app.f34fe59e.js index de74e587e4..9e791d5354 100644 --- a/docs/assets/js/app.a3c220af.js +++ b/docs/assets/js/app.f34fe59e.js @@ -1,8 +1,8 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,c=e[0],u=e[1],s=e[2],l=0,p=[];l=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(0),o=n(5),i=n(10),a=n(24),c=n(88),u=n(66),s=n(31),f=n(84).CONFIGURABLE,l=s.get,p=s.enforce,h=String(String).split("String");(t.exports=function(t,e,n,u){var s,l=!!u&&!!u.unsafe,d=!!u&&!!u.enumerable,v=!!u&&!!u.noTargetGet,y=u&&void 0!==u.name?u.name:e;o(n)&&("Symbol("===String(y).slice(0,7)&&(y="["+String(y).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),(!i(n,"name")||f&&n.name!==y)&&a(n,"name",y),(s=p(n)).source||(s.source=h.join("string"==typeof y?y:""))),t!==r?(l?!v&&t[e]&&(d=!0):delete t[e],d?t[e]=n:a(t,e,n)):d?t[e]=n:c(e,n)})(Function.prototype,"toString",(function(){return o(this)&&l(this).source||u(this)}))},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(0),o=n(142),i=n(143),a=n(119),c=n(24),u=n(4),s=u("iterator"),f=u("toStringTag"),l=a.values,p=function(t,e){if(t){if(t[s]!==l)try{c(t,s,l)}catch(e){t[s]=l}if(t[f]||c(t,f,e),o[e])for(var n in a)if(t[n]!==a[n])try{c(t,n,a[n])}catch(e){t[n]=a[n]}}};for(var h in o)p(r[h]&&r[h].prototype,h);p(i,"DOMTokenList")},function(t,e,n){var r=n(154),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(0),o=n(67),i=r.String;t.exports=function(t){if("Symbol"===o(t))throw TypeError("Cannot convert a Symbol value to a string");return i(t)}},function(t,e,n){var r=n(2),o=r({}.toString),i=r("".slice);t.exports=function(t){return i(o(t),8,-1)}},function(t,e){t.exports=!1},function(t,e,n){var r=n(11),o=n(12),i=n(44);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r,o=n(8),i=n(199),a=n(92),c=n(42),u=n(124),s=n(60),f=n(65),l=f("IE_PROTO"),p=function(){},h=function(t){return" + diff --git a/docs/docs/examples.html b/docs/docs/examples.html index 1206084433..ede032f1d9 100644 --- a/docs/docs/examples.html +++ b/docs/docs/examples.html @@ -8,7 +8,7 @@ - + @@ -41,6 +41,6 @@

- + diff --git a/docs/docs/federation.html b/docs/docs/federation.html index 6e3864e609..c0cb64da9e 100644 --- a/docs/docs/federation.html +++ b/docs/docs/federation.html @@ -8,7 +8,7 @@ - + @@ -86,6 +86,6 @@ →

- + diff --git a/docs/docs/index.html b/docs/docs/index.html index 7a02d66545..e36650de9b 100644 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -8,7 +8,7 @@ - + @@ -104,6 +104,6 @@ →

- + diff --git a/docs/docs/interop.html b/docs/docs/interop.html index 68b2323337..0653f9683b 100644 --- a/docs/docs/interop.html +++ b/docs/docs/interop.html @@ -8,7 +8,7 @@ - + @@ -127,6 +127,6 @@ →

- + diff --git a/docs/docs/introspection.html b/docs/docs/introspection.html index b2cfb9099b..c59a5f9e98 100644 --- a/docs/docs/introspection.html +++ b/docs/docs/introspection.html @@ -8,7 +8,7 @@ - + @@ -45,6 +45,6 @@ →

- + diff --git a/docs/docs/middleware.html b/docs/docs/middleware.html index ef9e6fc775..1ca23ca421 100644 --- a/docs/docs/middleware.html +++ b/docs/docs/middleware.html @@ -8,7 +8,7 @@ - + @@ -36,7 +36,7 @@ Github (opens new window)

# Middleware

Caliban allows you to perform additional actions at various levels of a query processing, via the concept of Wrapper. Using wrappers, you can:

# Wrapper types

There are 6 basic types of wrappers:

  • OverallWrapper to wrap the whole query processing
  • ParsingWrapper to wrap the query parsing only
  • ValidationWrapper to wrap the query validation only
  • ExecutionWrapper to wrap the query execution only
  • FieldWrapper to wrap each field execution
  • IntrospectionWrapper to wrap the introspection query only

Each one requires a function that takes a ZIO or ZQuery computation together with some contextual information (e.g. the query string) and should return another computation.

Let's see how to implement a wrapper that times out the whole query if its processing takes longer than 1 minute.

val wrapper = new OverallWrapper[Clock] {
+   (opens new window)

# Middleware

Caliban allows you to perform additional actions at various levels of a query processing, via the concept of Wrapper. Using wrappers, you can:

# Wrapper types

There are 6 basic types of wrappers:

  • OverallWrapper to wrap the whole query processing
  • ParsingWrapper to wrap the query parsing only
  • ValidationWrapper to wrap the query validation only
  • ExecutionWrapper to wrap the query execution only
  • FieldWrapper to wrap each field execution
  • IntrospectionWrapper to wrap the introspection query only

Each one requires a function that takes a ZIO or ZQuery computation together with some contextual information (e.g. the query string) and should return another computation.

Let's see how to implement a wrapper that times out the whole query if its processing takes longer than 1 minute.

val wrapper = new OverallWrapper[Clock] {
   def wrap[R <: Clock](
     process: GraphQLRequest => ZIO[R, Nothing, GraphQLResponse[CalibanError]]
   ): GraphQLRequest => ZIO[R, Nothing, GraphQLResponse[CalibanError]] =
@@ -96,6 +96,24 @@
   case err: ParsingError =>
     err.copy(extensions = Some(ObjectValue(List(("errorCode", StringValue("PARSING_ERROR"))))))
 }
+

# Wrapping the GraphQL

If you need to implement new functionality that involves not just changes to execution but also to the underlying +schema you can use the higher-level GraphQLAspect which allows full control of the resulting GraphQL that it wraps.

Here is such an example that is part of the federation package which makes a schema available to be used as a sub-graph in +a federated graph:

  def federate[R](original: GraphQL[R]): GraphQL[R] = {
+    import Schema._
+
+    case class Query(
+      _service: _Service,
+      _fieldSet: FieldSet = FieldSet("")
+    )
+
+    GraphQL.graphQL(RootResolver(Query(_service = _Service(original.render))), federationDirectives) |+| original
+  }
+
+  lazy val federated: GraphQLAspect[Nothing, Any] = 
+    new GraphQLAspect[Nothing, Any] {
+      def apply[R1](original: GraphQL[R1]): GraphQL[R1] =
+        federate(original)
+    }
 
- + diff --git a/docs/docs/optimization.html b/docs/docs/optimization.html index 28ae5b90b2..0bd307a04d 100644 --- a/docs/docs/optimization.html +++ b/docs/docs/optimization.html @@ -8,7 +8,7 @@ - + @@ -100,6 +100,6 @@ →

- + diff --git a/docs/docs/schema.html b/docs/docs/schema.html index 48f75d8a3c..dea633a3a0 100644 --- a/docs/docs/schema.html +++ b/docs/docs/schema.html @@ -8,7 +8,7 @@ - + @@ -170,6 +170,6 @@ →

- + diff --git a/docs/docs/stitching.html b/docs/docs/stitching.html index dbcb31a45f..c6f4527c6e 100644 --- a/docs/docs/stitching.html +++ b/docs/docs/stitching.html @@ -8,7 +8,7 @@ - + @@ -175,6 +175,6 @@ →

- + diff --git a/docs/docs/tools.html b/docs/docs/tools.html index c9512735e7..2017477d8c 100644 --- a/docs/docs/tools.html +++ b/docs/docs/tools.html @@ -8,7 +8,7 @@ - + @@ -75,6 +75,6 @@ →

- + diff --git a/docs/docs/validation.html b/docs/docs/validation.html index b1022f4ee0..dc93ce7356 100644 --- a/docs/docs/validation.html +++ b/docs/docs/validation.html @@ -8,7 +8,7 @@ - + @@ -54,6 +54,6 @@ →

- + diff --git a/docs/faq/index.html b/docs/faq/index.html index 8932308173..cac960a163 100644 --- a/docs/faq/index.html +++ b/docs/faq/index.html @@ -8,7 +8,7 @@ - + @@ -57,6 +57,6 @@ Schema.customErrorEffectSchema((code: Int) => ExecutionError(s"Error code $code"))

With this implicit in scope, Caliban will know how to handle any IO[Int, A] effects. Caliban will automatically fill the error path and the error location inside ExecutionError if an error happens during the query execution.

- + diff --git a/docs/index.html b/docs/index.html index e68a56aee9..0a9cfa2927 100644 --- a/docs/index.html +++ b/docs/index.html @@ -8,7 +8,7 @@ - + @@ -43,6 +43,6 @@

Get Started →

Purely functional

All interfaces are pure and types are referentially transparent. Schemas are type safe and derived at compile time.

Minimal boilerplate

No need to manually define a schema for every type in your API. Let the compiler do the boring work.

Excellent interoperability

Out-of-the-box support for major HTTP server libraries, effect types, Json libraries and more.

- + diff --git a/docs/resources/index.html b/docs/resources/index.html index 0073a824ed..7eec30d043 100644 --- a/docs/resources/index.html +++ b/docs/resources/index.html @@ -8,7 +8,7 @@ - + @@ -38,6 +38,6 @@ Scaladoc (opens new window)

# Resources

# Talks

# Blog Articles

- +