3

I am using Qt to interact with a GraphQL host. I am using QNetworkRequest, and the login process is done well, gives me a token in JSON format. Since then, GraphQL expects the token to be in the HTTP header:

{
   "Authorization": "Bearer <token>"
}

Testing the server, I wrote a small Python code, which works well:

headers = {'Authorization': "Bearer {0}".format(token)}
url = "http://example.com:8000/graphql"
params = {'query': '{fieldQueries{fields(userId:"xxx"){fieldName fieldID}}}'} 
result = requests.post(url, params=params, headers=headers)
print(result.json())

The below code is supposed to do the same operation in Qt:

QUrl url = QUrl("http://example.com:8000/graphql");
QNetworkAccessManager * mgr = new QNetworkAccessManager(this);
QNetworkRequest request(url);
QString query = QString("{fieldQueries{fields(userId:\"%1\"){fieldName fieldID}}}").arg(userId);
QUrlQuery params;
params.addQueryItem("query", query);

connect(mgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(onQueryFinish(QNetworkReply*)));
connect(mgr, SIGNAL(finished(QNetworkReply*)), mgr, SLOT(deleteLater()));

auto header = QString("Bearer %1").arg(token);
request.setRawHeader(QByteArray("Authorization"), header.toUtf8());

mgr->post(request, params.query().toUtf8());

However, server gives back an internal server error (500).

As soon as I comment out the request.setRawHeader, server gives back You are not authorized to run this query.\nNot authenticated with no error.

  • How to make Qt to send this header correctly?

  • I don't know if it helps, but I checked the packets using WireShark. The Python generated packet for this request is a single packet (around 750 bytes), though Qt request is broken into two packets which the length of the first is 600 byte.

The working package:

...POST /graphql?query=%7BfieldQueries%7Bfields%28userId%3A%22xxx%22%29%7BfieldName+fieldID%7D%7D%7D
HTTP/1.1..Host: xxx:8000..
User-Agent: python-requests/2.21.0..
Accept-Encoding: gzip, deflate..
Accept: */*..
Connection: keep-alive..
Content-Type: application/json..
Authorization: Bearer <688 bytes token>..Content-Length: 0....

Qt generated packages:

....POST /graphql HTTP/1.1..Host: xxx:8000..
Authorization: Bearer <364 bytes token>..
Content-Type: application/json..
Content-Length: 113..
Connection: Keep-Alive..
Accept-Encoding: gzip, deflate..
Accept-Language: en-US,*..
User-Agent: Mozilla/5.0....

and

.e..query=%7BfieldQueries%7Bfields(useId:%22xxx%22)%7BfieldName fieldID%7D%7D%7D
am.rez
  • 876
  • 2
  • 12
  • 24
  • 1
    Can you please show us the plaintext dump of both packages from WireShark? – Martin Hennings Apr 25 '19 at 11:11
  • @MartinHennings I added the dump, as far as WireShark let me to copy in the ASCII format. – am.rez Apr 25 '19 at 11:44
  • Comparing the content length of the Python and Qt packets, it seems adding the headers, causes the query to be sent as the body in Qt. Therefore, I send the query as a get query along the url: `url?query=...`. It solves the issue, though the main question remains unanswered. – am.rez Apr 25 '19 at 13:50
  • Actually it's the python `post(...)` that seems to get it wrong, because post data doesn't belong into the address line. - Are you sure that your server script accepts POST data? – Martin Hennings Apr 26 '19 at 07:22
  • From [this post](https://blog.apollographql.com/4-simple-ways-to-call-a-graphql-api-a6807bcdb355), graphql accepts both POST an GET. I used GET in my workaround. Correct me if I am wrong, I think POST data is a part of the header, not the body, as sent in Qt request. – am.rez Apr 26 '19 at 09:54

1 Answers1

1

Graphql accepts both POST an GET requests. Therefore, instead of post, I used GET. It sends the query as a part of the URL, not the header, which from the captured packets I realized they are sent as the body. The solution is as follows:

QNetworkAccessManager * mgr = new QNetworkAccessManager(this);
QString query = QString("{fieldQueries{fields(userId:\"%1\"){fieldName fieldID}}}").arg(userId);
QUrl url = QUrl(QString("http://example.com:8000/graphql?query=%1").arg(query));
QNetworkRequest request(url);

connect(mgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(onQueryFinish(QNetworkReply*)));
connect(mgr, SIGNAL(finished(QNetworkReply*)), mgr, SLOT(deleteLater()));

auto header = QString("Bearer %1").arg(token);
request.setRawHeader(QByteArray("Authorization"), header.toUtf8());

mgr->get(request);
am.rez
  • 876
  • 2
  • 12
  • 24