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] Allow accessing request body and headers when performing http request #16239

Open
Sakshamrameshhudiya opened this issue Aug 4, 2022 · 51 comments

Comments

@Sakshamrameshhudiya
Copy link

I am trying invoking an API via playwright and I am setting extraheaders via playwright = Playwright.create();
return playwright.request().newContext(new APIRequest.NewContextOptions()
.setBaseURL(TeamCityEnvironmentVariable("APIBaseUrl"))
.setExtraHTTPHeaders(headers));

and also adding request body to it via pojo classes but I am not able to see what headers and request body is set onces response is given by API.

@mxschmitt
Copy link
Member

what is pojo?

I'm not completely following this request, could you give us an example what you are trying to do?

You want to see which extraHttpHeaders are set on a request context?

@Sakshamrameshhudiya
Copy link
Author

Hey Team, I actually want to debug what exact request body I am setting in json format in APIRequestContext

@mxschmitt
Copy link
Member

what do you mean with json format? Could you provide a code example?

@Sakshamrameshhudiya
Copy link
Author

by json format i mean i want to know what request is set in request context ? example :
{
"teamIds": "99790",
"effectiveDate": "2020-01-01"
}

@mxschmitt
Copy link
Member

Fair enough, so we can make a feature request out of it and call it "Access request object when performing http requests". This would allow you to access headers, body, etc.

@Sakshamrameshhudiya
Copy link
Author

Sakshamrameshhudiya commented Aug 4, 2022

can you please give me and code example in java so as to how fetch these details or if there is some link to refer or something in playwright docuement.

@mxschmitt
Copy link
Member

It's not possible yet.

@mxschmitt mxschmitt changed the title [Question] Is there a way to know what setExtraHTTPHeaders are set & What request body is created to Response ? [Feature] Allow accessing request body and headers when performing http request Aug 4, 2022
@Sakshamrameshhudiya
Copy link
Author

Are we thinking of implementing this? I feel this should be a must for debugging if the request body or any other parameter is incorrectly set. If possible, can we also add a logging or trace feature to hit specific requestcontext API. If these features are added this would make it really powerful and a competitor to rest assured.
Thanks

@mxschmitt
Copy link
Member

Usually you already know which request body you pass into, so you kinda have it. Mostly you care about the response instead, not saying its a bad feature to have, depending on the upvotes we'll implement it.

@mstepin-edt
Copy link

mstepin-edt commented Nov 15, 2022

Agree that this would be nice for debugging. According to your docs its already possible for page:
PW docs say:

response.request()
Added in: v1.8
returns: <[Request](https://playwright.dev/docs/api/class-request)>[#](https://playwright.dev/docs/api/class-response#response-request-return)
Returns the matching [Request](https://playwright.dev/docs/api/class-request) object.

Could be great for API debugging so I can be sure my headers have worked correctly, especially if the body or headers passed to APIRequestContext.post() have runtime variables.
Currently I cant even retrieve the headers or body from the APIRequestContext object, let alone the APIResponse object.

@tepmehatop
Copy link

tepmehatop commented Nov 18, 2022

Hi,
The same problem, I did not find a solution how to log the body of the request, exactly the part that was sent, not the response body.

Previously used axios for request in playwright, now using pure playwright. a
Axios had a method for logging what was sent, what headers and body. "axios.interceptors.request.use..."

It helps to debug the code, very convenient.
For example, I send a POST request where there is a set of variables that are requested in the process for data from other places.
Ultimately, there is no understanding of what exactly is sent in the body.

{ "id": 0, "category": { "id": 0, "name": await Users.getUsers(request, 'Andy Warhol', 'rw', token),}, "name": nameState, "tags": [ { "id": 0, "name": nameStateTags } ], "status": await States.getCurrentState(request, 'create', token), }

@mstepin-edt
Copy link

yeah for my previous project we went with supertest for api calls. We made that design decision over 1 1/2 years ago. Now new job and new project, I thought I'd give the native PW api requests another go, thinking they have improved in some way. I was wrong, and will be using supertest again in the new project.

@mikekol
Copy link

mikekol commented Jan 9, 2023

Another +1 for "please add this". I can log in via the API I'm supposed to test in literally every other language and dialect of JavaScript/TypeScript I've tried, but can't make it work in a Playwright API test and I can't even make sure that it's sending the data I asked it to.

To the person earlier who said that we should know what data we're sending - I know what data I'm telling Playwright to send, I have no idea what data Playwright is actually sending. That's why we need this feature.

@sergiofbsilva
Copy link

Hello 👋 Any news regarding this? We also need this badly 🙏

@BogachevaN
Copy link

Hi! And we really need it! 🙏

@marcosvfranco
Copy link

marcosvfranco commented Jun 13, 2023

Up! I also need! unless I will need to use third party like chai-http but I dont like this idea

@lucy-mfv
Copy link

Hi! And we really need it too, it's so hard to debug now! 🙏

@tongilcoto
Copy link

yes, please, it is a major debug feature!!!
How do we vote for this feature to be implemented? I am assuming it is not just leaving a comment here ....

@marcosvfranco
Copy link

Hey fellas, I realized that we can get this info on Trace Viewer! Just go to the line of the API request and you will have all the info about what we need

@lucy-mfv
Copy link

Yep, we can use Trace viewer for trace fail script. It's very helpful

@tongilcoto
Copy link

Trace viewer is for UI testing, right? Our problem is for API testing, we just have the "request" response, not the full browser

@lucy-mfv
Copy link

@tongilcoto Trace viewer can use for api too, please try to use this for api

@tongilcoto
Copy link

Thank you very much @lucy-mfv
I have tried it! looks quite good!!! but this is not valid for runtime tasks, i.e. programmatically accessing request data or debugging

@rohit-walia
Copy link

rohit-walia commented Aug 13, 2023

+1 for access to request context for better debugging. I'm getting a "415 Unsupported media type" http error from a POST request and I can not get the request header field "content-type" to verify if it's correctly being set to 'application/json'.

And because these APIs are being executed against the BrowserContext without actually opening a new Page object, TraceViewer is not helpful either.

Pesudo code:

BrowserContext ctx = PlaywrightResourceFactory.BrowserObj.getInstance().newContext();
APIResponse resp = ctx.request().post("/api/login");

@odonnell-anthony
Copy link

+1 please provide this, it such an odd thing to be lacking

@mitchismycoffeename
Copy link

Another vote to please add! I can do it with trace viewer, but it's a very heavy-weight solution and, as others have pointed out, this is pretty standard on other API tools. But I want to do my UI testing and API testing in concert, and I could really use this information for debugging. Thanks.

@AnnaRennie
Copy link

+1 vote for having this feature

@asmyshlyaev177
Copy link

+1

@Kranael
Copy link

Kranael commented May 23, 2024

+1 here! Pls add this feat! @mxschmitt

@Dement57
Copy link

+1

2 similar comments
@Valiantsin2021
Copy link

+1

@kazwata
Copy link

kazwata commented Sep 10, 2024

+1

@Skn0tt Skn0tt assigned Skn0tt and unassigned Skn0tt Sep 13, 2024
@mfaisalkhatri
Copy link

+1

@grajesh690
Copy link

+1 having this feature would help us to have better control and back tracking.

@AshConnolly
Copy link

+1

1 similar comment
@marcusNumminen
Copy link
Contributor

+1

@F88
Copy link

F88 commented Feb 12, 2025

+1

@Skn0tt Skn0tt self-assigned this Feb 21, 2025
@Skn0tt Skn0tt added the v1.52 label Feb 24, 2025
@shahzad31
Copy link

We are really looking forward to this, we would like to have access to actual raw response object on the APIREQUESTCONTEXT

@Skn0tt
Copy link
Member

Skn0tt commented Mar 4, 2025

We are really looking forward to this, we would like to have access to actual raw response object on the APIREQUESTCONTEXT

That sounds like a different feature. Could you open a feature request and elaborate on what's missing from the existing response object?

@shahzad31
Copy link

That sounds like a different feature. Could you open a feature request and elaborate on what's missing from the existing response object?

We would like to be able to listen to on('resposnse', callback) on the request

@Skn0tt
Copy link
Member

Skn0tt commented Mar 4, 2025

I'm confused. Are you talking about API requests made in your test code, or browser-issued requests?

@Skn0tt
Copy link
Member

Skn0tt commented Mar 4, 2025

And what is on('response', callback)? What'd be the response object passed to the callback?

@Kranael
Copy link

Kranael commented Mar 4, 2025

@Skn0tt pls dont forget accessing request query params.

It should be possible to extract it from params object.

Body from data and header from extraHttpHeaders

Params is also very important.

Thank you in Advance!

@Kranael
Copy link

Kranael commented Mar 4, 2025

oh and it would be perfect if we can access also request method like

request.operation() (or method) -> return ."PUT" for example

@Skn0tt
Copy link
Member

Skn0tt commented Mar 4, 2025

@Kranael could you elaborate on your usecase? If you're using APIRequestContext to make an HTTP request, you already know all that information because you're passing it in. Why do you need to have the info on the return value of that call?

@Kranael
Copy link

Kranael commented Mar 4, 2025

@Skn0tt

The usecase would be to not build some wrapper class. We would have all information accessable on the request object like we have with response.

We do contract testing for example. We build a function for it.

validateRequest(req: Request, contract: JSON, path: string)

today we cannot use it just with request because it needs header, body, params and we cannot access it.

So we would need

validateRequest(header: extraHTTPHeader, params: JSON, body: JSON, method: string, contract: JSON, path: string)

It works but having all information of the request sent on the request object itself would really help to make clean code.

So somthing like:
request.headers() -> return headers as object
request.body() -> return body as object
request.params() -> return params as object
request.method() or operation() -> return string "put" for example

With this all information is concentrated in the request object like it is with response.

@shahzad31
Copy link

@Skn0tt i am primarily interested in building an object like this which playwright internally does and stores in har tracing

export type APIRequestFinishedEvent = {
  requestEvent: APIRequestEvent,
  httpVersion: string;
  headers: http.IncomingHttpHeaders;
  cookies: channels.NetworkCookie[];
  rawHeaders: string[];
  statusCode: number;
  statusMessage: string;
  body?: Buffer;
  timings: har.Timings;
  serverIPAddress?: string;
  serverPort?: number;
  securityDetails?: har.SecurityDetails;
};

i tried to do this in the PR by exposing the event externally but unfortunately PR got closed
#34938

@shahzad31
Copy link

@Skn0tt @pavelfeldman do you think there is any risk in using this kind of approach to capture the data?

const originalEmit = EventEmitter.prototype.emit;

EventEmitter.prototype.emit = function emit(type, ...args) {
  if (type === 'requestfinished') {
    console.log(`Captured event: ${type.toString()}`, args);
  }
  return originalEmit.apply(this, [type, ...args]);
};

so is user makes
await request.get('https://www.google.com');
we capture following information

Captured event: requestfinished [
  {
    requestEvent: {
      url: URL {},
      method: 'GET',
      headers: [Object],
      cookies: [],
      postData: undefined
    },
    httpVersion: '1.1',
    statusCode: 200,
    statusMessage: 'OK',
    headers: {
      date: 'Tue, 04 Mar 2025 09:46:59 GMT',
      expires: '-1',
      'cache-control': 'private, max-age=0',
      'content-type': 'text/html; charset=UTF-8',
      'content-security-policy-report-only': "object-src 'none';base-uri 'self';script-src 'nonce-GZ2wI9Si1dm7Yv-nbWK3TQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp",
      'cross-origin-opener-policy': 'same-origin-allow-popups; report-to="gws"',
      'report-to': '{"group":"gws","max_age":2592000,"endpoints":[{"url":"https://csp.withgoogle.com/csp/report-to/gws/other"}]}',
      'accept-ch': 'Sec-CH-Prefers-Color-Scheme, Downlink, RTT',
      'permissions-policy': 'unload=()',
      p3p: 'CP="This is not a P3P policy! See g.co/p3phelp for more info."',
      'content-encoding': 'br',
      server: 'gws',
      'content-length': '79290',
      'x-xss-protection': '0',
      'x-frame-options': 'SAMEORIGIN',
      'set-cookie': [Array],
      'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000'
    },
    rawHeaders: [
      'Date',
      'Tue, 04 Mar 2025 09:46:59 GMT',
      'Expires',
      '-1',
      'Cache-Control',
      'private, max-age=0',
      'Content-Type',
      'text/html; charset=UTF-8',
      'Content-Security-Policy-Report-Only',
      "object-src 'none';base-uri 'self';script-src 'nonce-GZ2wI9Si1dm7Yv-nbWK3TQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp",
      'Cross-Origin-Opener-Policy',
      'same-origin-allow-popups; report-to="gws"',
      'Report-To',
      '{"group":"gws","max_age":2592000,"endpoints":[{"url":"https://csp.withgoogle.com/csp/report-to/gws/other"}]}',
      'Accept-CH',
      'Sec-CH-Prefers-Color-Scheme',
      'Accept-CH',
      'Downlink',
      'Accept-CH',
      'RTT',
      'Permissions-Policy',
      'unload=()',
      'P3P',
      'CP="This is not a P3P policy! See g.co/p3phelp for more info."',
      'Content-Encoding',
      'br',
      'Server',
      'gws',
      'Content-Length',
      '79290',
      'X-XSS-Protection',
      '0',
      'X-Frame-Options',
      'SAMEORIGIN',
      'Set-Cookie',
      'AEC=AVcja2dH16RbfuewTK8C6JV5ynLqBsEdFAlAnjwTsfkD9wpg5cr2YE20JQ; expires=Sun, 31-Aug-2025 09:46:59 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax',
      'Set-Cookie',
      '__Secure-ENID=26.SE=Z4beaaOQfARSQSA8rmzgj4jmZm-ob20e5GHeZt_21D3jzhNLb6t-gs63qmSUuvo5D5NEJja9ae8uyF9ZXujCwBfXxi-cJfWnBiqV-HqeB5dPaBAxxrMj_MnN53SumzaW8Bq4m6jo_FJnzbFjh1QvhcbnVdaPL9sVaNPLRKx6_MJ8CgSBnaDS_4MkHW8jqF1h7S5JEjKIxBSwbjx9a2e0; expires=Sat, 04-Apr-2026 02:05:17 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax',
      'Alt-Svc',
      'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000'
    ],
    cookies: [ [Object], [Object] ],
    body: <Buffer 3c 21 64 6f 63 74 79 70 65 20 68 74 6d 6c 3e 3c 68 74 6d 6c 20 69 74 65 6d 73 63 6f 70 65 3d 22 22 20 69 74 65 6d 74 79 70 65 3d 22 68 74 74 70 3a 2f ... 263340 more bytes>,
    timings: {
      send: 91.58400000000006,
      wait: 100.68899999999985,
      receive: 49.639000000000124,
      dns: 32.52600000000007,
      connect: 91.35899999999992,
      ssl: 23.322999999999865,
      blocked: -1
    },
    serverIPAddress: '2a00:1450:4005:801::2004',
    serverPort: 443,
    securityDetails: {
      protocol: 'TLSv1.3',
      subjectName: 'www.google.com',
      validFrom: 1736152676,
      validTo: 1743410275,
      issuer: 'WR2'
    }
  }
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests