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

[ FEATURE REQUEST ] - Event based handling response #4

Open
saniyar-dev opened this issue Feb 16, 2025 · 3 comments
Open

[ FEATURE REQUEST ] - Event based handling response #4

saniyar-dev opened this issue Feb 16, 2025 · 3 comments
Assignees
Labels
enhancement New feature or request feature-request This issue is a feature request help wanted Extra attention is needed

Comments

@saniyar-dev
Copy link
Owner

Is your feature request related to a problem? Please describe.
Yes, now if anyone wants to create a request using client they should write the script like this:

  • Default client used:
import { Client } from 'k6/x/net/http';

export default async function () {
  const client = new Client();
  const response = await client.get('https://httpbin.test.k6.io/get');
  const jsonData = await response.json();
  console.log(jsonData);
}
  • Custom params to set for client and use it for all requests:
import { Client } from 'k6/x/net/http';

export default async function () {
  const client = new Client({
    proxy: 'http://127.0.0.1:1080',
    headers: { 'User-Agent': 'saniyar' },  // set some global headers
  });
  const response = await client.get('https://httpbin.test.k6.io/get');
  const jsonData = await response.json();
  console.log(jsonData);
}

See the problem?
User need to wait for response to do some actions on it. This way of doing request wouldn't be useful and there is no reason behind doing them async, because we actually need to wait for the response to take an action on it.


More proper way to handle the response:
If we can add an eventlistener to client object so we can listen on receiving response events and take some actions for it, we can solve this issue.

  • Add event listener for requestToBeSent and responseReceived:
import { Client } from 'k6/x/net/http';

export default async function () {
  const client = new Client();
  let requestID;  // used to correlate a specific response with the request that initiated it

  client.on('requestToBeSent', event => {
    const request = event.data;
    if (!requestID && request.url == 'https://httpbin.test.k6.io/get?name=k6'
        && request.method == 'GET') {
      // The request ID is a UUIDv4 string that uniquely identifies a single request.
      // This is a contrived check and example, but you can imagine that in a complex
      // script there would be many similar requests.
      requestID = request.id;
    }
  });

  client.on('responseReceived', event => {
    const response = event.data;
    if (requestID && response.request.id == requestID) {
      // Change the request duration metric to any value
      response.metrics['http_req_duration'].value = 3.1415;
      // Consider the request successful regardless of its response
      response.metrics['http_req_failed'].value = false;
      // Or drop a single metric
      delete response.metrics['http_req_duration'];
      // Or drop all metrics
      response.metrics = {};
    }
  });

  await client.get('https://httpbin.test.k6.io/get', { query: { name: 'k6' } });
}

You can see other desired implementation on the refrence Design documentation which aligns with goal of this extension:

Describe the solution you'd like
I have my own solution for it and i'm going to implement it, but i'm welcome to anyone ideas on implementation and addressing this issue.

Additional context

  • We can embed the eventlisteners definition in Client constructor call too
import { Client } from 'k6/x/net/http';

export default async function () {
  const client = new Client();
  await client.get('https://httpbin.test.k6.io/get', {
    eventHandlers: {
      'responseReceived': event => {
        const response = event.data;
        // ...
      }
    }
  });
}

Actually i don't like this way but it's mentioned in the design document for new HTTP API

@saniyar-dev saniyar-dev added enhancement New feature or request feature-request This issue is a feature request help wanted Extra attention is needed labels Feb 16, 2025
@saniyar-dev saniyar-dev self-assigned this Feb 16, 2025
@saniyar-dev
Copy link
Owner Author

saniyar-dev commented Feb 16, 2025

Related branch: #5

@saniyar-dev
Copy link
Owner Author

There is a lot of more work to do on this issue so i will leave it alone and open for any enhancements and other pull requests

But for now after i merged pull request #5 users can use events like this:

import { Client } from 'k6/x/net/http';

export default async function () {
  const client = new Client({
    proxy: 'http://127.0.0.1:1080',
    headers: { 'User-Agent': 'saniyar' },  // set some global headers
  });

  client.on('responseReceived', async response => {
    console.log(await response.json())
    // access to related request object:
    console.log(response.request.id)
    console.log(response.id)
  }

  await client.get('https://httpbin.test.k6.io/get');
}

@saniyar-dev
Copy link
Owner Author

There is also another related open issue on the behavior of events callbacks on eventloop, which i recommend to take a look at: #6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request feature-request This issue is a feature request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant