-
Notifications
You must be signed in to change notification settings - Fork 445
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
Feature request: formatted GraphQL queries for POST requests #127
Comments
@codepunkt nice suggestion, I will investigate it first and will update this thread later |
@Huachao I'm investigating myself. I can do this:
But when i send it to a simple JSON parser, e.g. Another idea that i had was having each graphQL query in it's own The GraphQL query itself would only be the string value of the |
Okay. So it seems it would be easier to pass in GraphQL from a file.
query ProjectLists($defaultCount: Int!) {
projectList(count: $defaultCount) {
id
name
}
}
variables {
"defaultCount": 50
} If this would work, it would be great! {
"query":"query ProjectLists($defaultCount: Int!) {\n projectList(count: $defaultCount) {\n id\n name\n }\n}",
"variables":{
"defaultCount":50
},
"operationName":"ProjectLists"
} There is a web frontend to explore and send GraphQL queries called GraphiQL, which basically does this: They get the variables and query and transform them to corresponding JSON that is sent in a request body. I'm currently looking through their codebase to see if the code doing this is in it's own module - which would be a godsend because we might be able to reuse (parts of) it here. Detect .gql piped into request body, use module to transform to JSON - done! 😁 |
@codepunkt if use the post request for querying, does the content type should be 'application/graphql'. And I think for a graphql server side normally will support both get and post cases. But the request body is not in JSON. |
The POST Request section of the GraphQL docs states this explicitly. Content-Type is application/json. |
@codepunkt you are right, however I also found following sentences in the page you provided
So the content-type is "application/graphql" works the same as query string, and no need to transform to JSON |
Yes, that is correct. However, this is a way to query a server that almost no one uses and that i've not seen in production ever. Main reason is that it does not support variables, which is an important part of GraphQL. A lot of GraphQL server libraries don't even implement it and imho there was a discussion somewhere to even remove it from the docs which i couldn't find offhand. |
@codepunkt thanks, previously I am not quite familiar with GraphQL. I will consider your suggestions carefully. |
@Huachao that you are even considering this, not being familiar with the technology, is amazing. Even if nothing comes from this, thank you! |
@codepunkt Thanks for your suggestion. I think it's a must to support GraphQL. And I will work in two aspects:
|
How can i help? I don't have any experience with vscode exensions, but if you have questions on GraphQL or need a second opinion on anything, let me know! |
@codepunkt thanks, I will sure turn to you when I have questions about GraphQL |
@Huachao @codepunkt I'm up to help, too. This plugin is amazing and support for graphQl will be real time saver (not only for me, I suppose). I can help with function to serialize the payload - in another words it prepare object that should be sent then (like extract operation name and prepare query value). Would that help? |
@dacz if you can help, that will be fantastic! |
Any status on this feature? Love the plugin - GraphQL would be a huge value add for us. |
@marija17 sorry for no any update on this feature, since I am busy in my daily work |
@Huachao - Thanks for the prompt response! If I were to explore this myself, are you open to contributions to your plugin? I'm not sure how far you explored this addition - but did you run into any particular challenges or roadblocks you could note? Alternatively, would you be open to someone using your plugin as a base (with credits given) to create a new plugin particularly for graphql? |
@marija17 I really welcome that you can contribute to my extension for the graphql feature. The challenges for me(since I am not familiar with graphql), what kind of request body should we support and how to support. Like following two examples: POST http://localhost:2018/graphql
Accept: application/json
query {
projectList(count: 50) {
id
name
}
} and {
"query": "{
projectList(count: 50) {
id
name
}
}"
} In both examples, they are not standard json body, that means how should we identify the request body targets for graphql and we should do some additional operations on the request body. BTW, do you think what other features we should support for this feature? Thanks in advance. |
thank for the great work so far POST {{graphqlEndpoint}}
content-type: application/json
{
"mutation": "{ purchaseMovie(input: {id: \"ssss\", pin: \"4444\", deviceType: STB}){ clientMutationId }}"
} |
GraphQL mutations over HTTP still use POST {{graphqlEndpoint}}
content-type: application/json
{
"query": "mutation { purchaseMovie(input: {id: \"ssss\", pin: \"4444\", deviceType: STB}){ clientMutationId }}"
} |
diff --git a/src/utils/httpRequestParser.ts b/src/utils/httpRequestParser.ts
index d9f8520..3c1a960 100644
--- a/src/utils/httpRequestParser.ts
+++ b/src/utils/httpRequestParser.ts
@@ -45,7 +45,10 @@ export class HttpRequestParser implements IRequestParser {
// get headers range
let headers: Headers;
let body: string | Stream;
+ let variables: string | Stream;
let bodyLines: string[] = [];
+ let variableLines: string[] = [];
+ let isGraphQlRequest: boolean = false
let headerStartLine = ArrayUtility.firstIndexOf(lines, value => value.trim() !== '', 1);
if (headerStartLine !== -1) {
if (headerStartLine === 1) {
@@ -55,7 +58,7 @@ export class HttpRequestParser implements IRequestParser {
let headerLines = lines.slice(headerStartLine, headerEndLine);
let index = 0;
let queryString = '';
- for (; index < headerLines.length; ) {
+ for (; index < headerLines.length;) {
let headerLine = (headerLines[index]).trim();
if (['?', '&'].includes(headerLine[0])) {
queryString += headerLine;
@@ -73,6 +76,7 @@ export class HttpRequestParser implements IRequestParser {
// get body range
const bodyStartLine = ArrayUtility.firstIndexOf(lines, value => value.trim() !== '', headerEndLine);
if (bodyStartLine !== -1) {
+ const requestTypeHeader = getHeader(headers, 'x-request-type');
const contentTypeHeader = getHeader(headers, 'content-type') || getHeader(this._restClientSettings.defaultHeaders, 'content-type');
firstEmptyLine = ArrayUtility.firstIndexOf(lines, value => value.trim() === '', bodyStartLine);
const bodyEndLine =
@@ -80,6 +84,16 @@ export class HttpRequestParser implements IRequestParser {
? lines.length
: firstEmptyLine;
bodyLines = lines.slice(bodyStartLine, bodyEndLine);
+
+ if (requestTypeHeader && requestTypeHeader === 'GraphQL') {
+ const variableStartLine = ArrayUtility.firstIndexOf(lines, value => value.trim() !== '', bodyEndLine);
+ if (variableStartLine !== -1) {
+ firstEmptyLine = ArrayUtility.firstIndexOf(lines, value => value.trim() === '', variableStartLine)
+ variableLines = lines.slice(variableStartLine, firstEmptyLine === -1 ? lines.length : firstEmptyLine);
+ isGraphQlRequest = true;
+ }
+ }
+
}
} else {
// parse body, since no headers provided
@@ -99,19 +113,31 @@ export class HttpRequestParser implements IRequestParser {
// parse body
const contentTypeHeader = getHeader(headers, 'content-type') || getHeader(this._restClientSettings.defaultHeaders, 'content-type');
- body = HttpRequestParser.parseRequestBody(bodyLines, requestAbsoluteFilePath, contentTypeHeader);
- if (this._restClientSettings.formParamEncodingStrategy !== FormParamEncodingStrategy.Never && body && typeof body === 'string' && MimeUtility.isFormUrlEncoded(contentTypeHeader)) {
- if (this._restClientSettings.formParamEncodingStrategy === FormParamEncodingStrategy.Always) {
- const stringPairs = body.split('&');
- const encodedStringParis = [];
- for (const stringPair of stringPairs) {
- const [name, ...values] = stringPair.split('=');
- let value = values.join('=');
- encodedStringParis.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
+ if (isGraphQlRequest) {
+ body = HttpRequestParser.parseRequestBody(bodyLines, requestAbsoluteFilePath, contentTypeHeader);
+ variables = HttpRequestParser.parseRequestBody(variableLines, requestAbsoluteFilePath, contentTypeHeader);
+
+ let graphQlPayload = {
+ query: body,
+ variables: JSON.parse(variables.toString())
+ };
+ body = JSON.stringify(graphQlPayload, null, 2);
+ bodyLines = body.split(EOL)
+ } else {
+ body = HttpRequestParser.parseRequestBody(bodyLines, requestAbsoluteFilePath, contentTypeHeader);
+ if (this._restClientSettings.formParamEncodingStrategy !== FormParamEncodingStrategy.Never && body && typeof body === 'string' && MimeUtility.isFormUrlEncoded(contentTypeHeader)) {
+ if (this._restClientSettings.formParamEncodingStrategy === FormParamEncodingStrategy.Always) {
+ const stringPairs = body.split('&');
+ const encodedStringParis = [];
+ for (const stringPair of stringPairs) {
+ const [name, ...values] = stringPair.split('=');
+ let value = values.join('=');
+ encodedStringParis.push(`${encodeURIComponent(name)}=${encodeURIComponent(value)}`);
+ }
+ body = encodedStringParis.join('&');
+ } else {
+ body = encodeurl(body);
}
- body = encodedStringParis.join('&');
- } else {
- body = encodeurl(body);
}
} Here is a patch of Request looks something like this : POST http://localhost:60000/graphql HTTP/1.1
content-type: application/json
x-request-type: GraphQL
Authorization: Bearer xxxx
query ($context: ListDataFilesInput) {
listDataFiles(input: $context) {
name,
lastModified
}
}
{
"context": {
"customerCode": "test",
"meshKey": "test",
"dataBucketCode": "test-bucket",
"filter": ""
}
}
#### Pay special attention to |
@codepunkt @Huachao We have used the update above (from @ferronrsmith) in order to use GraphQL (which we use a great deal). It works very well. Would you be able to apply the patch above? This plugin is extremely useful and having GraphQL support like this opens up the audience even more. |
@Huachao I second that.. GraphQL support like this would be beautiful.. Nice job @ferronrsmith |
@ferronrsmith @CorfitzMe @dremekie PR is warmly welcomed, pls feel free to create a PR and I will review it. Thanks in advance |
My organization fork uses (Note in cases anyone wants to do this). Example : POST http://localhost:60000/graphql HTTP/1.1
content-type: application/json
x-request-type: GraphQL
Authorization: Bearer xxxx
query ($context: ListDataFilesInput) {
listDataFiles(input: $context) {
name,
lastModified
}
}
{
context: {
customerCode: 'test', // customer unique identifier
meshKey: 'test', // customer environment (test/prod/demo)
dataBucketCode: 'test-bucket',
filter: '' // mongo filter can be passed here
}
}
#### |
@codepunkt @marija17 @jon301 @bisyonary @offero @mfulton26 @wprater @CorfitzMe @dacz @alembiq @dremekie with the fantastic patch from @ferronrsmith, the extension has the capability to send the GraphQL request directly. And this feature will be published in next release! You can provide a required query body and optional variables section. You can easily achieve this by adding a custom http header in your request headers POST http://localhost:60000/graphql HTTP/1.1
content-type: application/json
x-request-type: GraphQL
Authorization: Bearer xxxx
query ($context: ListDataFilesInput) {
listDataFiles(input: $context) {
name,
lastModified
}
}
{
"context": {
"customerCode": "test",
"meshKey": "test",
"dataBucketCode": "test-bucket",
"filter": ""
}
} Thanks @ferronrsmith for your contribution 😄 |
@codepunkt @marija17 @jon301 @bisyonary @offero @mfulton26 @wprater @CorfitzMe @dacz @alembiq @dremekie |
What about graphql fragment support ? |
hi @ferronrsmith, could you please add graphql fragment support also |
Amazing extension, thanks a lot!
What's missing for my usecase is a way of adding a formatted GraphQL query as a POST body.
I can do this to send GET with GraphQL queries, but this gets unreadable a lot really quick once the queries get more complicated:
What i would love to do instead is something like this:
I know that
Type
is not a header you'd want to specify and adding meta information that is not sent as a header is probably not part of RFC 2616, but it would be a way to format a query accordingly and could even have syntax highlighting for the query included.Maybe there's others who would be interested in this ?
The text was updated successfully, but these errors were encountered: