-
Notifications
You must be signed in to change notification settings - Fork 436
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
Provide possibility to extract values from response #140
Conversation
And add ability to extract response values through dotted variable name
@cbrevik @fmartingr @akalcik thank you all, and @cbrevik, this is a really nice patch and makes a solid step towards implementing
###
# @name ExampleRequest
GET https://api.example.com
###
Again, thank you all for your great contribution to this extension. 😄 |
we should go agile and try to make simple and usable solution, which can be enhanced later.
When we are working with the JSON we could probably use same JSON Query Language, like https://marketplace.visualstudio.com/items?itemName=joshwong.vscode-jmespath or http://www.jsoniq.org/ |
|
I'm not denying/ignoring the comments for more enhancements here but I'm focusing only to reach a MVP feature set where this is usable and when is ready and launched iterate more over it. |
@fmartingr @cbrevik @akalcik thank you all for your quick responses. And I summarize the answers for developing this feature:
# @name login
POST https://api.example.com/login HTTP/1.1
Content-Type: application/json
{
"user": "xxx",
"password": "yyy"
}
###
GET https://api.example.com/docs HTTP/1.1
Authorization: Bearer {{login.resp.headers.token}}
Do you agree with this design, and any other suggestions? 😊 |
Agreed on all points :) But I'm still wondering about number 4. When you say XPath syntax, do you mean full syntax like this with node/attribute retrieval, predicates, etc. Or just a simple Is full syntax easy to support in JavaScript? |
@cbrevik I can't agree with you more. And maybe we can first support JSON path only, and leave the XPATH(or related solution) later. |
I agree with that as first iteration. I don't know how complex will be the XPath for XML because I haven't developed a lot with JS/TS but if it comes bundled in it could be nice to have at least a working way to use them. Have any of the people from #140 mentioned they want this for XML explicitly? Maybe we are trying to support it when no one has requested it (yet). |
Cache by file name + variable key
I don't think XML support is strictly necessary as an MVP either. I've done a preliminary implementation at cbrevik@f51bc85 Not finished of course. I'll merge into this PR (or create a new PR) when it is working better. And we can iterate from there. |
@cbrevik thanks so much, and waiting for your updated PR. |
Actually I liked the first proposal of @cbrevik much more! Defining variables in comment seems to be very confusing. What about this one? This is pretty clean and aligned with the current syntax.
"...file compatible with other editor's rest-client plugins, so..." Just confused. Is the file compatible now? I think to make file compatible with other editor's we need to redesign the syntax completely. |
@akalcik The @Huachao I've pushed a few more changes to this PR, reverting the old commit. It's working in a very basic manner, with red diagnostic squiggly lines if variable reference is not in memory. Just thought I'd check in here. Not done yet. Needs more error handling, better |
@akalcik sorry for the late to response to your comment about response declaration syntax. @cbrevik Thanks again for your great contribution for this feature. @akalcik @cbrevik @fmartingr I'd like to share with you about my consideration for three most requested features(#67 #74 #86) which I think all related to this PR. I have several reasons about why personally I suggest to use a syntax in comment not in request line. And a key difference of our proposals is that I use request name instead of response name to reference the response. Many of existing REST API tools(e.g., Postman, Insomnia) have the ability to add name for the request, so this way has a good compatibility if we later want to import/export data from those tools. We even have the ability to reference other request's request part, not only response. And when user references other request/response with name, we can also easily know the request dependency, even further we can trigger dependent request automatically. Another reason that I don't want to use # @name login
POST https://api.example.com/login
Content-Type: application/json
{
"user_name": "foo",
"password": "bar"
}
###
@token = {{login.resp.body.access_token}}
... Below is a full example # @name listDocs
# @descirption A test request to list all the docs
GET https://api.example.com/docs
Authorization: token 123456
###
# @name createDoc
# @status_code 201
# @resp_content_type application/json
POST https://api.example.com/docs
Authorization: {{listDocs.req.headers.Authorization}}
Content-Type: application/json
{
"author": "foo",
"content": "bar"
}
###
# @name getDoc
GET https://api.example.com/docs/{{createDoc.resp.body.id}}
|
@Huachao @cbrevik I get your points. Still confused to understand some language design decisions. Please help me. When is a file scope variable created it is like this:
Name of this variable is a Now:
In this case the we have a two variables with name What also I would propose to change is the missing operator. In one case is value set per |
@akalcik the So the metadata names are predefined for special use, currently seems we only need the And the syntax of adding metadata to request just brought from JSDoc, I don't have many good ideas either, I agree with @akalcik that this seems a little confusing with file scope variable declaration, @cbrevik @akalcik @fmartingr what kind of syntax do you think appropriate for this? Thanks again @akalcik @cbrevik @fmartingr , without your discussions, I can't think about it deeply. |
Good Discussion. How about using
Example
|
@cbrevik any updates on this, sorry to bother you. |
@Huachao I've been extremely busy since Christmas. So I haven't had a chance to work on this, sorry. I'll try to devote some more time this weekend. It's basically in a working state. The difference from your proposal is that I've only cached the |
@cbrevik that's ok, I am sorry that I didn't intend to push you, and I've fixed some conflicts and pushed into your branch. |
I really like this, when will it hit marketplace? For xml and other strange format, you could support regex as well, lets say you have the captured data in myDoc after using In a sub-sequent request you may define variable I'm not too sure about the syntax of naming response, since tripple hash (###) is really a part of the previous request when you are folding/collapsing a request. Anyway, this naming of a response should also including naming of the request for easy navigation of some kind. |
src/variableDiagnosticsProvider.ts
Outdated
private findVariables(document: TextDocument): Variable[] { | ||
let vars: Variable[] = []; | ||
let lines = document.getText().split(/\r?\n/g); | ||
let pattern = /\{\{(\w+)(\..*?)*\}\}/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a g
options for the pattern seems can finally find all the expected variables
And the logic in the while statement can be easier(no need to manually adjust the current index)
while (match = pattern.exec(line)) {
let variablePath = match[0];
let variableName = match[1];
vars.push(new Variable(
variableName,
match.index,
match.index + variablePath.length,
i
));
}
src/models/variableType.ts
Outdated
"use strict"; | ||
|
||
export enum VariableType { | ||
Custom, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about rename Custom
to File
src/models/httpElement.ts
Outdated
@@ -35,5 +35,6 @@ export enum ElementType { | |||
Authentication, | |||
SystemVariable, | |||
EnvironmentCustomVariable, | |||
FileCustomVariable | |||
FileCustomVariable, | |||
RequestVariable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about rename to RequestCustomVariable
to be consistent with other user-level custom variables
src/variableProcessor.ts
Outdated
); | ||
} | ||
|
||
public static async getVariableDefinitionsInFile(document: TextDocument): Promise<Map<string, VariableType[]>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make modifier to private seems enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, was thinking this is a utility-method which can be used in the future. But it can be made public again then. I'll update 👍
const firstPartRegex: RegExp = /^(\w+)\.$/; | ||
const secondPartRegex: RegExp = /^(\w+)\.(request|response)\.$/; | ||
|
||
export class RequestVariableCompletionItemProvider implements CompletionItemProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about only allow these completion items when the first part or so called variable name is a request variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean checking if the request variable exists at all in memory? I'm not sure that is developer friendly, personally I like having completion on "known" valid syntax, even if it won't run.
Is there a good reason to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cbrevik I don't express myself clearly, I just mean this completion item hint only make sense for request variable, not for other types of variables. So it's not necessary for request variables loaded in memory, just exist or already declared in file is enough.
And except this, other code LGTM. 👍 Really great pull request!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking maybe the check at the top was enough;
if (!VariableUtility.isPartialRequestVariableReference(document, position)) {
return [];
}
Which basically checks if the path is using a dot, which would by definition would be a request variable. (Since only that type uses dotted values).
But it does not check if the variable name is declared in the file as a request variable (# @name variableName
), is that what you're thinking should also be checked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a check for if the variable name is defined in the file as a request variable (and not necessarily in memory)
return undefined; | ||
} | ||
|
||
const parsedBody = JSON.parse(body as string); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about check the Content-Type
header first in the request or response, and check if it's JSON, if so, do as is. Otherwise, simply return the body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CIL
82916fb
to
7459df3
Compare
Think I've adressed the comments now 👍 |
@@ -67,6 +74,19 @@ export class RequestVariableCompletionItemProvider implements CompletionItemProv | |||
return completionItems; | |||
} | |||
|
|||
private checkIfRequestVariableDefined(document: TextDocument, variableName: string) { | |||
const text = document.getText(); | |||
const regex = new RegExp(Constants.RequestVariableDefinitionRegex, 'mg'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not directly construct a regex with given variableName, so that if we can found one in text
means True
, otherwise False
.
completionItems = props.map(p => { | ||
let item = new CompletionItem(p); | ||
item.detail = `(property) ${p}`; | ||
item.documentation = p; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about make the value of documentation
to the actual value of p
? User can better know what's the actual value will be inserted into the request.
|
||
completionItems = props.map(p => { | ||
let item = new CompletionItem(p); | ||
item.detail = `(property) ${p}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does user really need the (property) prefix
|
||
const valueAtPath = RequestVariableCacheValueProcessor.getValueAtPath(variableValue, fullPath); | ||
if (valueAtPath) { | ||
let props = Object.getOwnPropertyNames(valueAtPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Why not use Object.keys(), since your one will also include not enumerable properties?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor Comments
Fixed! |
@cbrevik Merged, thanks, really a great patch 👍 . And I will publish this in next release. |
Awesome, thanks for the help landing this @Huachao! It's going to be fun using this day-to-day. |
As stated in #74 (comment), this is a naive proof-of-concept implementation of #74.
It's inspired by @fmartingr's suggestion of "piping" the response to a variable name like;
POST url/auth -> authResponse
.The goal would be to allow the developer refer to the response by a variable name, and use a "dotted" property approach to access its values.
This implementation should work with something like:
@baseUrl = https://jsonplaceholder.typicode.com GET {{baseUrl}}/posts/1 -> myResponse ### GET {{baseUrl}}/users/{{myResponse.body.userId}}
Opening PR for discussion of approach. I do not consider this to be a ready solution yet. Would love input from @Huachao.
Things to discuss:
response.body
(and possibly otherHttpResponse
values?). This naive approach does aJSON.parse
automatically onbody
, which is not satisfactory. Maybe addingjsonBody
,xmlBody
, etc helper properties like @fmartingr suggested is one approach.ResponseStore
. Should it be tied to the file which ran the request instead? Or is there value in cross-file sharing? Can be confusing if variables start overwriting each other on name collisions.