8000 Send a mutation with POST, also in GET mode by hugo-vrijswijk · Pull Request #829 · gemini-hlsw/clue · GitHub
[go: up one dir, main page]

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion scalajs/src/main/scala/clue/js/FetchJsBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package clue.js
import cats.effect.*
import cats.syntax.all.*
import clue.*
import clue.model.GraphQLQuery
import clue.model.GraphQLRequest
import clue.model.json.given
import io.circe.Encoder
Expand Down Expand Up @@ -44,7 +45,7 @@ final class FetchJsBackend[F[_]: Async](fetchMethod: FetchMethod)
// that the caller set stays unchanged.
if (!_headers.has(FetchJsBackend.AcceptHeaderName))
_headers.set(FetchJsBackend.AcceptHeaderName, FetchJsBackend.AcceptHeaderValue)
val promise = fetchMethod match {
val promise = FetchJsBackend.methodFor(fetchMethod, request.query) match {
case FetchMethod.POST =>
_headers.set("Content-Type", "application/json")
Fetch
Expand Down Expand Up @@ -108,6 +109,19 @@ object FetchJsBackend {
private val AcceptHeaderValue: String =
s"${GraphQLOverHttp.GraphQLResponseMediaType}, $JsonMediaType;q=0.9"

/**
* The HTTP method for one request.
*
* GraphQL-over-HTTP forbids GET for a mutation operation, because an intermediary can cache, log
* or replay a GET request. A mutation therefore goes out with POST, also when the backend is
* configured with `FetchMethod.GET`.
*/
private[js] def methodFor(fetchMethod: FetchMethod, query: GraphQLQuery): FetchMethod =
fetchMethod match {
case FetchMethod.GET if query.operationType.contains("mutation") => FetchMethod.POST
case method => method
}

/**
* Build the URL for a GraphQL GET request.
*
Expand Down
21 changes: 21 additions & 0 deletions scalajs/src/test/scala/clue/js/FetchJsBackendSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package clue.js

import cats.syntax.all.*
import clue.model.GraphQLQuery

import scala.scalajs.js.URIUtils

Expand Down Expand Up @@ -52,6 +53,26 @@ class FetchJsBackendSuite extends munit.FunSuite {
assertEquals(parseParams(uri)("variables"), variables)
}

test("methodFor sends a mutation with POST, also when GET is configured") {
val query = GraphQLQuery("mutation Save($x: Int!) { save(x: $x) { id } }")
assertEquals(FetchJsBackend.methodFor(FetchMethod.GET, query), FetchMethod.POST)
}

test("methodFor sends a query with GET when GET is configured") {
val query = GraphQLQuery("query Foo { id }")
assertEquals(FetchJsBackend.methodFor(FetchMethod.GET, query), FetchMethod.GET)
}

test("methodFor sends an anonymous selection set with GET when GET is configured") {
val query = GraphQLQuery("{ id }")
assertEquals(FetchJsBackend.methodFor(FetchMethod.GET, query), FetchMethod.GET)
}

test("methodFor keeps POST for a query when POST is configured") {
val query = GraphQLQuery("query Foo { id }")
assertEquals(FetchJsBackend.methodFor(FetchMethod.POST, query), FetchMethod.POST)
}

test("buildGetUri encodes the operationName") {
val uri =
FetchJsBackend.buildGetUri("https://example.com/gql", "query { id }", none, "Op&x=1".some)
Expand Down
Loading
0