GraphQL body type
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)
}
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"
}
```
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.
- 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
}
}
Any update about GraphQL body type support? This is the only feature I am waiting for :)
Thank you for hurl! :heart:
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.
@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 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!
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)
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
👋 So happy this is live now but I think I've found a bug and was curious if others are seeing this as well
https://github.com/Orange-OpenSource/hurl/issues/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