I am have some problems passing in the correct headers for my graphql endpoints
The use case in Postman:
call requestToken endpoint to obtain sessionToken value
requestToken response contains Key Value " and Token Value.
For subsequent calls, I set postman headers as:
Key = X_SESSION_TOKEN Value = Token Value
The user case in Karate
1st feature 'requestToken.feature' successfully calls and stores key + tokenValue
2nd feature successfully defines and prints the token value
here is my 2nd request:
Feature: version
Background:
* url 'http://api-dev.markq.com:5000/'
* def myFeature = call read('requestToken.feature')
* def authToken = myFeature.sessionToken
* configure headers = { 'X_SESSION_TOKEN': authToken , 'Content-Type': 'application/json' }
Scenario: get version
Given path 'query'
Given text query =
"""
query {
version
}
"""
And request { query: '#(query)' }
When method POST
Then status 200
And print authToken
And print response
I am not sure I send the headers right. Its coming back 200, but I keep getting a error 'token malformed' in the response message
Any suggestions? New at this, thanks!
Honestly this is hard to answer, a LOT depends on the specific server.
EDIT: most likely it is this change needed, explained here: https://github.com/intuit/karate#embedded-expressions
* configure headers = { 'X_SESSION_TOKEN': '#(authToken)' , 'Content-Type': 'application/json' }
2 things from experience:
should it be X-SESSION-TOKEN
add an Accept: 'application/json' header
And try to hardcode the headers before attempting call etc.
Here is an example that works for me:
* url 'https://graphqlzero.almansi.me/api'
* text query =
"""
{
user(id: 1) {
posts {
data {
id
title
}
}
}
}
"""
* request { query: '#(query)' }
* method post
* status 200
Related
Many have experience with generic automated tests with Puppeteer. This is mostly about imitating user behavior on web pages and asserting results. But what if you need to test representation of errored state, which you cannot (or don’t know how to) trigger by a user action? For example, we have a form. When user submits the app sends a POST request to the server and shows success messages as soon as the server responds with 200 OK. That is the expected behavior. Yet, in real world the server may happened to be down or respond with Internal Error. Imagine the app covers gratefully this case. But how we would reproduce it with Puppeteer?
Given that Puppeteer provides a lot of possibilities on handling HTTP/S requests, I came up with the following solution. While submitting the form I mock the server response with my own.
Basically I set up an interceptor, which replaces the next request matching a given URL fragment with custom server response:
await bs.mockRequest( "response.json", { "GET", "500 Internal Server Error", "application/javascript", "{ \"status\": \"FAIL\" }", [] });
While it’s watching the network, I can submit the form, e.g. by emulating click on the submit button. The following request will be replaced so that the app under test would treat it as in the case of real server error.
Here the source code of the mockRequest:
class BrowserSession {
// obtaining page context from Puppeteer
// #see https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-puppeteerlaunchoptions
async setup( options ) {
this.browser = await puppeteer.launch( options );
this.context = await this.browser.createIncognitoBrowserContext();
this.page = await this.context.newPage();
}
/**
* Intercept and replace request
* #param {String} url - URL substring to match
* #param {Object} newRespond
*/
async mockRequest( url, { method, status, contentType, newBody, headers }) {
const session = await this.page.target().createCDPSession(),
patterns = [ `*${ url }*` ];
await session.send( "Network.enable" );
await session.send( "Network.setRequestInterception", {
patterns: patterns.map( pattern => ({
urlPattern: pattern,
interceptionStage: "HeadersReceived"
}))
});
session.on( "Network.requestIntercepted", async ({ interceptionId, request, responseHeaders, resourceType }) => {
if ( ( method || "GET" ) !== request.method.toUpperCase() ) {
await session.send( "Network.continueInterceptedRequest", { interceptionId });
return;
}
const newHeaders = [
"Date: " + ( new Date() ).toUTCString(),
"Connection: closed",
"Content-Length: " + newBody.length,
"Content-Type: " + contentType,
...headers
];
await session.send( "Network.continueInterceptedRequest", {
interceptionId,
rawResponse: btoa( `HTTP/1.1 ${ status }\r\n`
+ newHeaders.join('\r\n') + '\r\n\r\n' + newBody )
});
session.detach();
});
}
}
I'm using Swagger Swashbuckle in a dotnet core 3.1 web api project and have trouble to send bearer authorization to the requests calls.
I've defined this in my ConfigureServices method:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo() { Title = "MyApi", Version = "v1" });
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Password = new OpenApiOAuthFlow()
{
TokenUrl = new Uri("/api/Account/Login", UriKind.Relative),
}
},
In = ParameterLocation.Header,
Name = "Authorization",
Scheme = "Bearer",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme()
{
Reference = new OpenApiReference()
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "Bearer",
Type = SecuritySchemeType.Http,
Name = "Bearer",
In = ParameterLocation.Header
}, new List<string>()
}
});
});
When running, I see the Authorize button that show the login dialog:
Once logged, the API routes show the locked padlock but when I try to use them, I see the call is done without the returned bearer:
curl -X GET "http://localhost:5000/api/Account" -H "accept: */*" -H "Authorization: Bearer undefined"
What's wrong with my definitions?
In the cURL request you can see: -H "Authorization: Bearer undefined".
This means that when Swagger-UI tries to get the token that will be added to the request header, it cannot be found.
Then, where the token cames from, and why Swagger-UI cannot found it? The token comes in the json returned from your login endpoint (/api/Account/Login).
You must be sure that returned json from your login endpoint repect the expected format for a OAuth password flow, as explained in the RFC6749 section 4.1.4 (Access Token Response).
From your login endpoint you must return a json response like this:
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"bearer"
}
It's a common mistake, that when you serialize the response from the controller you dont respect the json property names. In example: you can be returning a json like this:
{
"accessToken":"2YotnFZFEjr1zCsicMWpAA",
"tokenType":"bearer"
}
Where "accessToken" is not the same as "access_token" and so on.
This little difference causes that Swagger-UI cannot found the bearer token when it deserializes the returned json.
TIP: decorate the "AccessToken" property of your response object, so it will be serialized correctly.
[JsonPropertyName("access_token")]
[JsonProperty(PropertyName = "access_token")]
public string AccessToken { get; set; }
Although what is explained is the main point of your problem, I want to tell you that adding the security requirement globally is not the most correct way to do it. In this way you are protecting all the endpoints, regardless of whether they are decorated with the Authorize attribute or not.
In the startup you only must set a "Security Definition", and add an "OperationFilter" that handles the "security requirements". Then "SecurityRequirement" references the "SecurityDefinition", then you don't repeat the security definition configuration (Scheme, Type, Name, In, etc.) inside the security requirements as you are doing in your example.
Refer to this github post that shows you the correct way to do it.
I need a way to set the headers of the dart http Request object to application/JSON.
I want to build a Request object to send to my backend API. I set the body to my JSON object, but when it gets sent, it defaults the headers to text/html instead of application/json.
I have tried using the built-in method
http.post(url,dynamic body);
but unfortunately this method places the body in the parameters of the URL and I need it in the actual body of the request.
So instead I built an http Request object, and manually set the URL and body but like I said, it sets the headers to text/html.
I have read the docs for https://pub.dev/documentation/http/latest/http/Request-class.html, but unfortunately, I haven't found a way to set the headers.
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
Much thanks for any possible solutions!
Ps. this is my first ask on Stack Overflow so I apologize if I made any errors in posting.
Solved!
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.headers.clear();
request.headers.addAll({"content-type":"application/json; charset=utf-8"});
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
I was having some issues with the Request object default setting the encoding.
By manually specifying utf-8, the server I am contacting accepts it.
for the post or get any request you can Add Header like this -
var permAddUrl = 'your requested url';
var bodyParameters = {
'Email': email,
'MobileNo': mobileNumber,
};
await http.post(
requesturl,
headers: { 'Content-Type': 'application/x-www-form-urlencoded',
"Authorization":"$token",
},
body: bodyParameters,).then((response) {
var data = json.encode(response.body);
print(data);
setState(() {
if(response.statusCode == 200){
//var statesList = data['data'];
UtilAction.showSnackBar(context, " Details Submitted Successfully");
}
});
});
I'm trying to make a demo app with flutter and trying to fetch products from a demo magento site.
This is my code:
Future<List<Product>> fetchProducts() async {
final params = <String, String>{
'searchCriteria[filter_groups][0][filters][0][condition_type]': 'in',
'searchCriteria[filter_groups][0][filters][0][field]': 'type_id',
'searchCriteria[pageSize]': '20',
'searchCriteria[filter_groups][0][filters][0][value]': 'simple,configurable,bundle',
'searchCriteria[currentPage]': '1',
'searchCriteria[sortOrders][0][field]': 'created_at',
'searchCriteria[sortOrders][0][direction]': 'DESC'
};
var uri = Uri.parse('https://demo.com/rest/v1/default/products');
uri = uri.replace(queryParameters: params);
print(uri);
final response =
await http.get(uri, headers: {HttpHeaders.authorizationHeader: "Bearer qb7157owxy8a29ewgogroa6puwoafxxx"});
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON.
final data = json.decode(response.body);
final products = data["items"] as List;
return products.map<Product>((json) => Product.fromJson(json)).toList();
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
When I debugged, the response was 400 - Bad request. I guess that because the uri was encoded to include percentage characters as I printed as below:
So how can I disable encoding the uri?
Thank you, guys.
I believe you should replace:
var uri = Uri.parse('https://demo.com/rest/v1/default/products');
uri = uri.replace(queryParameters: params);
print(uri);
with:
var uri = Uri.https('demo.com', '/rest/v1/default/products', params);
more on this: Uri.https
more on: replace
example result:
regardless of this, if I try with your params, the library behaves normal and encodes the special characters. (see more here)
if we put the actual request in the browser to check the response:
https://demo.mage-mobile.com/rest/v1/default/products?searchCriteria[filter_groups][0][filters][0][condition_type]=in&searchCriteria[filter_groups][0][filters][0][field]=type_id&searchCriteria[pageSize]=20&searchCriteria[filter_groups][0][filters][0][value]=simple%2Cconfigurable%2Cbundle&searchCriteria[currentPage]=1&searchCriteria[sortOrders][0][field]=created_at&searchCriteria[sortOrders][0][direction]=DESC
we get the following response:
And this brings me to my initial suspicion: the API does not support this call.
Maybe you should also check this type of param from your code: 'searchCriteria[filter_groups][0][filters][0][condition_type]', it seems you are trying to acces some information from a collection but you actually writing a string...
try removing the quotes (' bla bla ') from these params id... also try to put the request direcly in the browser(or postman) to see it work.
About the encoding (changing [ to %5B) -- this is normal and it should happen.
I'm new to Angular, I'm using Angular 7 as client side and ASP.NET as server side.
I want to pass more than 2 parameters. I've succeeded to send one parameter.
Here's my Angular service method that sends 2 parameters:
validate_user(user : Users, active: boolean): Observable<UsersError> {
console.log(user);
return this.http.post<UsersError>(this.users, user, active);
}
Here's my ASP.NET post method:
public UsersError Post([FromBody] sp_GetUsers_Result user, bool active)
{
UsersError u = new UsersError
{
UserName = "Username Invalid",
Password = "Password Invalid"
};
return u;
}
I know I can wrap the parameters into an object and send it as one, but I want to know is there a way to do it with two or more parameters (objects).
I tried to use HttpParams with various combinations, but nothing worked.
The third parameter in .post is httpOptions :
Example:
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'my-auth-token'
})
};
So you'd need to change this line :
return this.http.post<UsersError>(this.users, user, active);
active should be send as param
Regarding asp.net : submitting/posting must match an object in the controller.
Asp.net wil take the body params and will try to match them into the controller argument (fromBody). You can't mix it with another argument(*).
In short , you'd have to add active to a new model in server.
* You can , but it will require some other hacks - like I've built: https://github.com/RoyiNamir/SimplePostVariableParameterBindingExtended
BundleTypeAttributeView(users: string, Active: boolean, ): Observable<any> {
const params = new HttpParams().set('users', users).set("Active", Active);
return this.http.get<any>(this.endPoint + 'bundleTypeAttributes', { params });
}