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

Implement pre-request and post-request scripts (and request chaining) #218

Closed
2 tasks done
NBTX opened this issue Oct 25, 2019 · 24 comments · Fixed by #231
Closed
2 tasks done

Implement pre-request and post-request scripts (and request chaining) #218

NBTX opened this issue Oct 25, 2019 · 24 comments · Fixed by #231
Assignees
Labels
discussion Talking over coding feature New feature or request wip Work in progress

Comments

@NBTX
Copy link
Contributor

NBTX commented Oct 25, 2019

Support for pre-request and post-request scripts should be added.

Essentially this means a user should be able to enter some JavaScript code they want executed before a request to generate values - e.g. a random UUID for a request header.

Additionally, a user should be able to enter some JavaScript code they want executed after a request either for the purposes of chaining requests (i.e. automatically setting parameters for a request to data returned from a previous request) or for the purposes of presenting data.

This should work like Postman's Pre-Request Scripts.

@NBTX
Copy link
Contributor Author

NBTX commented Oct 25, 2019

This issue has been created to supersede #139 and #196. Ideally it should work in conjunction with #91 and #147.

@NBTX NBTX changed the title Implement pre-request and post-request scripts Implement pre-request and post-request scripts (and request chaining) Oct 25, 2019
@NBTX NBTX assigned aeeed99 and NBTX Oct 25, 2019
@jgroom33
Copy link
Contributor

I don't think a scripting language should be implemented. The scripting language is a crutch that ends up as garbage collection.
In place of a scripting language, a templating engine and some key handling should be implemented.
Each request in a collection would have a when key. This should be evaluated as a truthy. And when it evaluated to true, that request will execute.

@NBTX
Copy link
Contributor Author

NBTX commented Oct 25, 2019

Can you provide some justification as to why you think that?
Also, we don't just want boolean checks, in some cases we want to use data from other fields - or the response payload in the next request. Or we want to rearrange and view data in the response payload.

@jgroom33
Copy link
Contributor

There should be a default behavior where all responses are stored automatically. No scripting should be required for this. The values from all previous calls should be available as {{ foo.response.id }}

This library is a good example

Ansible uses the same concept and the result is a much cleaner implementation.

Postman should not be used as a model for implemention because they are fine with a massively bloated json collection object because they don't care about how that object looks in a git commit. They want to sell their subscription service to a UI tool, not something that is code commit friendly.

Have you ever tried to revision control a postman collection?

@aeeed99
Copy link
Contributor

aeeed99 commented Oct 26, 2019

Various data should be available from the previous request, yes. But in the case of the first request there is not much data to use. A user might want to set non request related data, or may want to format data from a previous request differently, or conditionally. I don't quite follow the point on postman's json collection. Json representation for requests are more used for imports/exports, not for reading.

Templating can still be used as well, and I agree it will probably be more frequently used than script. These two ideas can be thought of as separate features, and once added both or one could be used, or neither.

@jgroom33
Copy link
Contributor

jgroom33 commented Oct 27, 2019

For the initial call, an execution parameter should be available to load a set of variables. These should be loaded as json, not as key value pairs with only strings.

I do not presume that this project will attempt to make available a global repository for sharing collections. That would require operational costs. As such, the collections would need to be committed to a revision control platform like GitHub. If the postman approach to pre/post request scripts is followed, those commits will become indecipherable and code review on a collection will be a challenge.

The solution to these challenges have already been solved by other projects. Search for the following "ansible loops" "ansible when" "ansible register"

The addition of a register key with a jsonquery capability would probably handle the majority of use cases.

It might look something like this in a UI:

Post request variable storage

Key  |  Value
--------------------
foo.  |  $.response.array[?(@.key==2)].dictionary.a
bar   |  $.header.token

@aeeed99
Copy link
Contributor

aeeed99 commented Oct 27, 2019

I agree that jsonpath is often faster and cleaner and can be used for most situations. Storing a pre-request script in places like json for history, etc, does look a bit cumbersome, as storing a long string of text always does. Still, I'm tempted to go with a "why not have both" approach here? I'm absolutely biased on this opinion, considering I've already put in some time and found an exciting implementation. But I don't see them solving the same problem exactly, nor do I see how the presence of one of these features impedes the other.

The way I see it, each response should, as you've mentioned, be available via json format. As a smaller detail, I see the ability to interpolate the jsonpath directly:

Request: https://example.com/auth?token=${response.token}
Header: ${response.array[?@.key==2].dictionary.a}

Both are accessing data on a response object that's made available from previous requests in the case of chaining. This can be the default behavior and anyone could stop with just this functionality, which I believe satisfies the suggestion of templating and key handling.

However, if someone wished to use scripting, the same data would be available in that environment, with the ability to add more data which would be available to the upcoming request.

pw.environment.set('foo', 'bar') ;
pw.environment.set('username', pw.response.username.toUpperCase());
pw.environment.set('users', [1,1,1,1].map(user => {id: Math.random().toString().slice(2) }));
pw.environment.set('date', new Date().toISOString());

The data then available for the request would be:

{
  response: { /* unchanged, starting data */ }
  environment: {
    foo: 'bar',
    username: 'NICK',
    users: [
      {id: '587848195440719'},
      {id: '2293313864853187'},
      {id: '7297256522670248'},
      {id: '6688009846472254'},
    ],
    date: "2019-10-27T15:13:08.314Z"
  }
}

Additionally this feature could be easily enhanced by making API-ey functions available in the environment, like a random UUID creating function. It also lays some groundwork for testing assertions between calls, perhaps halting a chain of requests if a previous one does not respond as expected, etc. Lastly, some people just like scripting over configuration for whatever reason; let the user decide how and which parts of postwoman they want to use.

So why not have both?

@liyasthomas liyasthomas added the feature New feature or request label Oct 27, 2019
@liyasthomas
Copy link
Member

liyasthomas commented Oct 27, 2019

Processing env variables with scripting language and a template engine together seems like an exclusive feature. While ansible and other projects making use of template engines do have few limitations over manipulating and enforcing customs rules on env vars that could only be satisfied with the support of a scripting language.
This might be an overkill, but that's exactly what I'd expect in a better API testing tool.

@NBTX NBTX added the discussion Talking over coding label Oct 27, 2019
@jgroom33
Copy link
Contributor

I think that if a scripting language is implemented before a more structured approach, then the scripting language will become the default usage. Since most people are coming from postman, they would naturally try to find the same behavior instead of attempting the more desired approach.

Template engines provide plugin support for custom methods. So when there are requirements to perform advanced parsing, the template engine plugins could be used. This would place a focus on a more structured approach, but advanced users could still write code. Then, as commonalities present themselves in the template plugins, they can be included as supported features.

@jgroom33
Copy link
Contributor

Regarding the topic of request chaining: set next request is terrible IMO.

Something similar to the following features in ansible should be implemented:

  • import_tasks
  • when

This allows a multilevel file directory (instead of a massive json collection object like postman) to organize the requests or groups of requests.

As an example:

login/request.json

POST to http://foo/login

action/users.json

import login/request.json
GET to http://foo/users with login response header

The above approach would allow reuse of:

  • a single file with a single request
  • A single file with multiple requests
  • A directory that includes several files with requests in each file

@aeeed99
Copy link
Contributor

aeeed99 commented Oct 28, 2019

We won't know what the default usage would be until we've released something, but users tend to choose what works for them. If templating followed scripting, anyone who was struggling with scripting would explore the new alternative. Even if scripting becomes the default usage, what's the harm exactly? That suggests it satisfies their use cases enough not to switch.

If advanced users could script via plugins that could involve heavy reuse of this feature anyway. It's a small difference of viewpoint, using a "transform"-like extension in a template that is defined in code vs defining the code and interpolating its final value in the request.

@NBTX
Copy link
Contributor Author

NBTX commented Oct 29, 2019

Personally I still haven't seen an objective downside to including scripting.

To me scripting is a less cumbersome way of implementing #218 (comment) (by using simple JavaScript statements rather than JSON.)

Plus, scripting could theoretically use 'includes' (as shown in that comment) and it would make the requests in Postwoman self-documenting as one can see - at a glance - all of the variables that get assigned programmatically.

@jgroom33
Copy link
Contributor

There may not be a harm in implementing scripting. I think I was most concerned about how postman does not allow a DRY approach. This would lead to duplicated code across requests which became difficult to update.

These features would make the scripting more focused:

  • include execution of single file or directory
  • Auto storage of responses for future templating use

@NBTX
Copy link
Contributor Author

NBTX commented Oct 30, 2019

Re-opening as PR #231 is more of an MVP rather than the full solution to this script.

@liyasthomas
Copy link
Member

@nickpalenchar would you mind looking into post-request scripts implementation like pre-request scripts..? I know you're busy, but I hope it would be a peace of cake for you since you introduced pre-request scripts.

@aeeed99
Copy link
Contributor

aeeed99 commented Nov 23, 2019 via email

@liyasthomas
Copy link
Member

That's great!

@aeeed99
Copy link
Contributor

aeeed99 commented Nov 25, 2019

So the post-request step is plausible but not a piece of cake for a few reasons:

The post-request script feature is really only useful when it has data from a previous request. So really, there is no post-request script, only chained requests, each with a pre-request script that has access to data from the request that came before it.

So I think it's important that the request chaining gets implemented first. My idea is that the entire request section to the left of the history is able to get copied and paginated. There could be numbered tabs on top so the user could switch between request numbers, something like the poorly made ascii-UI shows below

|*1*| 2 | 3 | + |  <--- click one to show a different request section.
----------------------
Pre-Request Script ^
...
...

Request ^
Method: [POST] Url: https://reqres.in

Authentication  Headers  Parameters
---------------
Type ...
. . .
.
.

For this to happen, the entire request building logic needs to be refactored into its own component. This is a HUGE obstacle that is currently taking lots of time. Many abstractions between methods, data, refs, and the store need to be delicately handled.

The end result is a request-building component that has its own request data, and can expand to multiple instances as needed. The index.vue page then becomes responsible for dispatching each request, getting the response data back, and then dispatching the following request with the data from the previous request (among other functions like storing and saving in the history). The user is free to edit the requests independently, possibly even rearrange them.

I've started with this refactoring idea In this branch I recommend pulling and running it locally to get a better sense of what I mean. Many pieces of functionality have been correctly refactored but other part are regressing (like the saving to collections).

To summarize: Refactoring into a requestBuilding component is needed before we can finish the rest of this elegantly. It's not too hard, but the large refactor needs to happen all at once in order to get merged back in before it diverges from other PR's.

Thoughts? I'll try to explain more tomorrow--I'm out of time tonight!

@liyasthomas
Copy link
Member

I understand the difficulties, and I'll surely contribute into it. I guess request section component is a great idea so there could be provision for tabbed requests too. I know we've come a long way from initial commit. We can pull this off too.

@aeeed99
Copy link
Contributor

aeeed99 commented Nov 25, 2019

Awesome! Yes do feel free to add to it. I'll also try to look at it a bit more in another 24 hours, but any other contributions will surely be helpful.

@liyasthomas
Copy link
Member

This issue is resolved. (decoupling request-chaining feature from this issue).

@1ace
Copy link

1ace commented Mar 11, 2022

@liyasthomas Hi! you have closed a number of issues about request chaining/dependencies in favour of this one, which you then closed saying it didn't cover that feature anymore. Is there another issue tracking this? Or has this feature been implemented in the mean time?

I'm currently looking for a tool that does have this feature, and for some reason none of them do, so I'm really hoping this one does :)

@liyasthomas
Copy link
Member

As of now, chaining requests feature is not in our priority list. This particular issue ticket was to track pre-request and post-request script enhancements, which we already implemented and hence closed.

I will create another issue to track request chaining feature as we ship our other priority features.

Feel free to contribute to the source code and I'd appreciate if you can create a discussion thread under this repo on your feature request for future communications.

@1ace
Copy link

1ace commented Mar 11, 2022

Thanks for the really quick answer!

I have created a discussion about requests chaining/dependency management, and I'll evaluate in the next few weeks using Hoppscotch as a replacement for Postman (that we currently use). If the result is conclusive, I'll dig into the code and see if I can contribute this feature 👍

Please comment on that discussion if there was any attempt at this feature, so that it doesn't get forgotten :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Talking over coding feature New feature or request wip Work in progress
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants