Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL body type #504

Closed
dalejefferson-rnf opened this issue Mar 17, 2022 · 9 comments · Fixed by #1023
Closed

GraphQL body type #504

dalejefferson-rnf opened this issue Mar 17, 2022 · 9 comments · Fixed by #1023
Labels
enhancement New feature or request
Milestone

Comments

@dalejefferson-rnf
Copy link

dalejefferson-rnf commented Mar 17, 2022

I would like to use Hurl to test our GraphQL api but I can't find a good pattern to create the requests other than just justing JSON. While JSON does work it's a bit clunky, it would be great if GraphQL was supported natively.

This is an example query

POST https://localhost:8080/graphql
{
  "query": "{person {name age}}"
}

Once you get lots of properties and nesting it gets pretty ugly as you can't put new lines in graphql

POST https://localhost:8080/graphql
{
  "query": "{person {name age friends {name friends {name}}}}"
}

It would be great if GraphQL was a supported body type so we could just do

POST https://localhost:8080/graphql
{
  person {
    name 
     age
   }
}

This would be converted into a valid json object (adding a query key and escaping the new lines)

Using external graphQL files would also be great

POST https://localhost:8080/graphql
graphql,person.graphql

We would also need a way of providing variables

POST https://localhost:8080/graphql
[GraphQLParams]
message: hello
query Echo($message: String) {
  echo(message: $message)
}

And mutations

POST https://localhost:8080/graphql
[GraphQLParams]
thing: hello
mutation UpdateThing($thing: String) {
  updateThing(thing: $thing)
}
@jcamiel jcamiel added the enhancement New feature or request label Mar 17, 2022
@jcamiel
Copy link
Collaborator

jcamiel commented Mar 17, 2022

Hi @dalejefferson-rnf

Definitively a good idea to support GraphQL body. We've not very versed in GraphQl, nor heavy user of it so we've a lot of question:

  • how can we support the following GraphQL query:
query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}

I don't know if fragments are heavily used in GraphQL but this possible Hurl syntax can be tricky to parse:

POST https://localhost:8080/graphql
query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}

HTTP/* 200

Maybe we can extand, in a first time, our multiline strings:

POST https://localhost:8080/graphql
```graphql
query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}
```
HTTP/* 200

Whatever is between

```graphql 
xxx 
```

is considered as a GraphQL query.

Note: we could also extend multiline string to support hex and base64 which are only one one line today:

```base64
MIIEowIBAAKCAQEAwgilgLyb/oSShncjuaueb5mgmeOLZ34g9BMoRJdeBo52aA0L
T9KPoHPiOdsLDheAdXci3xwxtV3+bbEEEtChTnoWJwAXJ5wXT/eJdysPlNo2NSRG
USPb5PW8+vhsOeHpJiQZUOWAUJNfMys0l3jwC7fkCrBs20+sCJxb
```
```hex
2d2d2d2d2d424547494e205253412050
2d2d2d2d2d424547494e205253412050
2d2d2d2d2d424547494e205253412050
```
  • should we have a short hand syntax for "simple" GraphQL query:

Given a "simple" GraphQL query (without fragments etc...), do we support this syntax:

POST https://localhost:8080/graphql
{
  person {
    name 
     age
   }
}

Syntax seems natural and there seems to be no problem differentiating with JSON body when we parse it. In detail,
we'll have to check error message but it can be doable. Our question: is this kind of "simple" queries common in GraphQL usage ? If yes, we can support graphql xxx in a first time, and support this syntax in a second time.

Regarding variables (GraphQL variables), we should see if we need a specific section or if we could use the graphql :

POST https://localhost:8080/graphql
```graphql
query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
{
  "episode": "JEDI"
}
```

@dalejefferson-rnf
Copy link
Author

dalejefferson-rnf commented Mar 17, 2022

Thanks for the prompt response @jcamiel

Yes I see the problem how will you know when the graphQL ends, the multiline string solution works.

Fragments are used lots, but they are used to share code between queries or as shorthand, you can always inline the fragment like below. (I'm not a GraphQL expert there may be other reasons).

In this example it just saved you having to write the body twice, you would likely split this test into two anyway with Hurl.

query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
      name
    friendsConnection(first: $first) {
      totalCount
      edges {
        node {
          name
        }
      }
    }
    }
    rightComparison: hero(episode: JEDI) {
      name
    friendsConnection(first: $first) {
      totalCount
      edges {
        node {
          name
        }
      }
    }
  }
}

So you could have a limited set of syntax which add a lot of value and use external files for complex queries.

  1. Shorthand syntax (this is optional, you can write this as a named query)
{
   person {
       name
   }
}

2a. With operation query

query getPerson {
    person {
       name
   }
}

2b. With operation mutation

mutation updateThing($thing: String) {
  updateThing(thing: $thing)
}

With 2 you have query|mutation terminated by a closing brace which could be parsed.

I also like the idea of externalising the graphQL files (We generally do this in our client code) so we get full IDE support (Autocompletion), validation, formatting and even testing queries used by the client.

Keeping the variables separate would be valuable for this use-case, you could fire the same query with different variables.

POST https://localhost:8080/graphql
[GraphQLVariables]
first: 10
graphql,heroComparison.graphql

POST https://localhost:8080/graphql
[GraphQLVariables]
first: 5
graphql,heroComparison.graphql

heroComparison.graphql

query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}

someClientCode.js

import query from 'heroComparison.graphql'

If I was writing tests I would likely use the simple shorthand syntax and inline any variables.

Shorthand

{
    getPerson(name: "Dale") {
       name
   }
}

With operation name and variables. This does not add much value in a test (in my opinion) I would write my production queries like this thou.

query getPerson($name: String) {
    getPerson(name: $name) {
       name
   }
}

@azzamsa
Copy link
Contributor

azzamsa commented Nov 8, 2022

Any update about GraphQL body type support?
This is the only feature I am waiting for :)

Thank you for hurl! ❤️

@jcamiel
Copy link
Collaborator

jcamiel commented Nov 8, 2022

Hi @azzamsa,
It's one of the features that we've prioritized for our next version!
I'm not an expert on GraphQL so maybe I will ping people in this thread for feedback as soon as we've something working.

@jcamiel
Copy link
Collaborator

jcamiel commented Nov 27, 2022

@dalejefferson-rnf @azzamsa I would be happy if you could test the GraphQL features and gives me feedback on it. You'll have to be able to build Hurl on the last master (see Building from sources). I can help if you need.

The syntax adopted for GraphQL is an extension of the multiline string body that we already supported.

  • Unnamed query:
POST http://localhost:8000/graphql
```graphql
{
  allFilms {
    films {
      title
      director
      releaseDate
    }
  }
}
```

Any GraphQL queries should be supported without issues.

  • Query with variables:
POST http://localhost:8000/graphql
```graphql
query Person($id: ID!) {
  person(id: $id) {
    name
  }
}

variables {
  "id": "cGVvcGxlOjQ="
}
```

Variables is a JSON object, that can also be templatized with Hurl variables (à la Inception):

POST http://localhost:8000/graphql
[Options]
variable: id=cGVvcGxlOjQ=
```graphql
query Person($id: ID!) {
  person(id: $id) {
    name
  }
}

variables {
  "id": "{{id}}"
}
```

For the moment, we haven't yet addressed injecting GraphQL queries from files but we have a syntax in mind that will be elegant and simple without introducing new concept!

If you can't test it, that's not a problem, we'll release a version soon that will support it and you will be able to test it then.

@jcamiel jcamiel added this to the 1.9.0 milestone Nov 28, 2022
@azzamsa
Copy link
Contributor

azzamsa commented Dec 14, 2022

@jcamiel Very glad finally. It lands on the master!

Currently, my requirement is not complicated. This worked well for me https://github.com/azzamsa/tin/blob/master/tests/tests.hurl

This also worked well:

# meta
POST http://127.0.0.1:8000/graphql

``graphql
mutation {
  createUser (input: {name: "hurl"}) {
		id
		name
		fullName
  }
}
``

HTTP/1.1 200
[Asserts]
status == 200
jsonpath "$.data.createUser.name" == "hurl"

It is very hard to read without syntax highlighting, so I made a simple one https://github.com/azzamsa/emacs-hurl

Thanks a lot for Hurl!

@jcamiel
Copy link
Collaborator

jcamiel commented Dec 14, 2022

Thanks @azzamsa for the feedback, We'll try to improve Hurl tooling support in 2023. Don't hesitate to make a PR on Hurl with your first draft of emacs support, we have a folder for various editor with basic support here https://github.com/Orange-OpenSource/hurl/tree/master/contrib (see also CONTRIBUTING.md)

@azzamsa
Copy link
Contributor

azzamsa commented Dec 16, 2022

We'll try to improve Hurl tooling support in 2023.

Glad to hear it.

I have just basic knowledge of building emacs mode for syntax #1105

@softprops
Copy link

👋 So happy this is live now but I think I've found a bug and was curious if others are seeing this as well

#1218

My server is not able to process requests with hurls encoding of variables (a json object encoded within a string). Nased on graphql.org docs it looks like other servers might not was well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants