Is it possible to use OwinResponse.Write while setting the status code to something other than 200?
I have the following code in an OwinMiddleware but as long as OwinResponse.Write is called the StatusCode is always set to 200 :(
response.OnSendingHeaders(state =>
{
var resp = (OwinResponse) state;
var message = string.Format(
"Max API concurrent calls quota exceeded, please try again later. Maximum admitted: {0}",
_maxConcurrentRequests);
resp.ReasonPhrase = message;
resp.Write(message);
resp.StatusCode = 429; // doesn't work here unless I comment out the line above
}, response);
StatusCode must be set before writing to the body, not after.
Don't write to the body inside OnSendingHeaders, it's recursive as
OnSendingHeaders is usually triggered by a write to the body.
Why are you even using OnSendingHeaders here? Why not just do all of
this directly on the response?
That's far more information than is usually included in a reason phrase. That level of detail belongs in the response body. The default reason phrase for 429 is Too Many Requests.
Related
Let's say my API call URL is www.example.com/quiz with POST method.
And I get the response body like this. And
var jsonData = pm.response.json();
pm.collectionVariables.set("cv_quiz_order", quiz_order)
if(!jsonData.is_end){
// TODO: request next question using `quiz_order`
}else{
// TODO: finish this API and go to the next request.
}
When I use Run Collection. I want it(the Apis) tests one by one in regular sequence. And only this Api repeats until its is_end is true.
How can I do this?
var jsonData = pm.response.json();
pm.collectionVariables.set("cv_quiz_order", quiz_order)
if(!jsonData.is_end){
postman.setNextRequest(pm.info.requestName)
}else{
// TODO: finish this API and go to the next request.
}
this will keep sending the same request until is_end is true
postman.setNextRequest allows you to set the next reqeust to be executed , pm.info.requestName gives thecurrent request Name , so you are saying run this request as next request
I have a GET request to OKTA to retrieve some information that uses some variables etc. It returns a body. I have a second request of type PUT where I manually paste the BODY and make a change to one variable. I am trying to determine if I can remove the manual process of pasting in the response body from the 1st GET request onto the second PUT request.
As an example, I have a URL:
GET https://{{myurl}}/api/v1/apps/{{instanceid}}
This returns some dyanmic JSON data in the payload like so
"blah":{ some more blah
},
"signOn": {
"defaultRelayState": null,
"ssoAcsUrlOverride": ""
"audienceOverride": null,
"recipientOverride": null
}
what I am hoping to do is:
PUT https://{{myurl}}/api/v1/apps/{{instanceid}}
{replay entire body from 1st request with the modification of
"ssoAcsUrlOverride": "{{some var that points to a new url}},
}
I have looked at some articles that show:
Using Tests to send a GET request with a static body and replaying that exact body. In this case, I am looking to modify a parameter not replay as=is
I tried this thread here (In postman, how do I take a response body and use it in a new request within Tests
postman-how-do-i-take-a-response-body-and-use-it-in-a-new-request-within-tes) but I get an error stating that responseBody is not defined
First of all, let's validate the JSON response first. Here is the valid JSON with some dummy data.
{
"blah": "some more blah",
"signOn": {
"defaultRelayState": "1",
"ssoAcsUrlOverride": "www.google.com",
"audienceOverride": "true",
"recipientOverride": "yes"
}
}
1) Save first request's response into a environment variable req_body as follows,
var jsonData = pm.response.json();
pm.environment.set("req_body", jsonData);
2) In the PUT request, take another environment variable replace_this_body in body.
3) Get the value of E'variable req_body we had set in the first request in Pre-request script. Then change the value of it and set current request's body variable.
var requestBody = pm.environment.get("req_body");
requestBody.signOn.ssoAcsUrlOverride = "https://www.getpostman.com";
pm.environment.set("replace_this_body", JSON.stringify(requestBody));
Finally, you will get updated request data into PUT request!
I am trying to create a lex bot that lets users learn about different options. For example, it can tell a user about the three different products available. I can't seem to find documentation about how to do this without using a lambda function, and I can't figure out how to pass the user input from the bot itself into the lambda function in order to use a simple "if/then" and then return the appropriate message. It seems excessive to have to use an lambda function to just give a response based on input, but I am stuck. Thanks.
To shed a little more light on how a Lex bot works, the service enables you to define utterances ("if" conditions), that it will intelligently try to perform fuzzy-matching to determine whether a user has said something that fits one of the utterances you've defined. You can declare and modify these utterances within the AWS console, examples of this are available here.
The "then" part of this conditional application is where you get to define what happens after the user input matches a defined utterance (state), where some basic computation is handled, most easily in the form of a Lambda function.
For something simple like returning static text/info once a condition is met:
Return from your lambda_handler function a string with the proper result. A barebones pseudocodey Python implementation of this would look like the following:
# Here's an implementation where you have an intent of a user asking
# for more info about a particular object (info_type as defined in Lex console).
def lambda_handler(event, context):
info_name = event['info_type']
if info_name = 'business_hours':
return "Our business hours are 9am-5pm"
elif info_name = 'slogan':
return "We're customer obsessed"
else:
return "Sorry, we don't have info about this!"
Depending on how you want to set up your application, you can decide how you want to split up the logic between different utterances and if/then cases with prop data passed in. If you have more complex queries, question types, and computation involved, these will all determine what the optimal way to architect your Lex chat bot will be.
A Lex bot by itself is really only good enough for simple FAQ conversations where certain inputs have pre-defined responses. But you cannot set the responses based on the slot values Lex captures. You could have a very limited dynamic response where those slot values are simply placed inside a response (imagine a Mad Libs game), but that's about it.
As soon as you want to create a truly dynamic response based on the user input, then you will need to use a Lambda function to compare the Lex request and build an appropriate response based on the user input or slot values.
Documentation
Amazon Lex - Using Lambda Functions
Create a Lambda Function (example Order Flowers)
Set the Lambda Function as the Lex Intent's Code Hook
Once you have your Lambda function set up and Lex ready to pass the processed user input through as a Lex Request (also referred to as "Event"), then you will have to pay close attention to this document:
Lex Request and Response Format
The incoming request has a consistent format for delivering the currentIntent, the sessionAttributes, the slots, the inputTranscript (the full user input), and more. It might look like a lot to take in but once you parse it into its main components, then it's really quite easy to work with in order to build dynamic responses. Just make sure you are following the Lex Request and Response format precisely.
Example
Here is an example for the start of your Lambda Function (Node.js):
// The JSON body of the request is provided in 'event'.
// 'respondToLex' is the callback function used to return the Lex formatted JSON response
exports.handler = (event, context, respondToLex) => {
console.log( "REQUEST= "+JSON.stringify(event) ); //view logs in CloudWatch
// INCOMING VARIABLES FROM REQUEST EVENT
// -------------------------------------
var intentName = event.currentIntent.name;
var slots = event.currentIntent.slots
var sessionAttributes = event.sessionAttributes
var userInput = event.inputTranscript
// OUTGOING VARIABLES FOR RESPONSE
// -------------------------------
var responseMsg = "";
var responseType = "";
var slotToElicit = "";
var error = null;
var fulfillmentState = null;
// DETERMINE RESPONSE BASED ON INTENTS AND SLOT VALUES
// ---------------------------------------------------
if (intentName == "intentA") {
responseType = "Close";
responseMsg = "I am responding to intentA";
fulfillmentState = "fulfilled';
}
elseif (intentName == "intentB") {
if (slots["productChoice"] == null) {
responseMsg = "I can tell that productChoice slot is empty, so I should elicit for it here. Which product would you like? Hat or Shoes?";
responseType = "ElicitSlot";
slotToElicit = "productChoice";
}
else {
if (slots["productChoice"]=="hat") {
responseMsg = "I can tell you selected a hat, here is my dynamic response based on that slot selection.";
}
elseif (slots["productChoice"]=="shoes") {
responseMsg = "I can tell you selected shoes, here is my dynamic response based on that slot selection.";
}
}
}
else {
error = "Throw Error: Unknown Intent";
}
// CREATE RESPONSE BUILDER for each responseType (could turn into functions)
// -------------------------------------------------------------------------
if (responseType=="Close") {
var response = [
"sessionAttributes" = sessionAttributes,
"dialogAction" = [
"type" = responseType,
"fulfillmentState" = fulfillmentState,
"message" = [
"contentType" = "PlainText";
"content" = responseMsg,
]
]
];
}
elseif (responseType == "ElicitSlot) {
var response = [
"sessionAttributes" = sessionAttributes,
"dialogAction" = [
"type" = responseType,
"intentName" = intentName,
"slots" = slots
"slotToElicit" = slotToElicit,
"message" = [
"contentType" = "PlainText";
"content" = responseMsg,
]
]
];
}
responseJSON = JSON.stringify(response);
console.log("RESPONSE= "+ responseJSON); // view logs in CloudWatch
respondToLex(error, responseJSON);
}
By definition the http response is split in 3 parts, status-code -> headers -> body, and when doing akka client http requests the http response is received after the first 2 parts have been completely
received.
val responseFuture: Future[HttpResponse]
responseFuture.map {
case HttpResponse(statusCode:StatusCode, headers:Seq[HttpHeader], entity:ResponseEntity, protocol:HttpProtocol)
}
This is completely fine for most use cases, but in my particular case I need access to the headers before all the headers are received (a third party server is returning progress by writing custom progress headers until the response is ready). Is there any way to access the headers the same way we access the body?
val entity: ResponseEntity
val entitySource:Source[ByteString, Any] = entity.dataBytes
In the perfect world there would be a way to access the headers as a source as well
HttpResponse(statusCode:StatusCode, headers:Source[HttpHeader, NotUsed], entity:ResponseEntity, protocol:HttpProtocol)
Not Possible With akka-http
The representation of HttpResponse treats the headers as a Seq[HttpHeader] instead of an Iterator or an akka-stream Source. Therefore, as explained in the question, it is not possible to instantiate an HttpResponse object without having all the header values available first.
I do not know the exact reason behind this design decision but I suspect it is because it would be difficult to support a Source for the headers and a Source for the body. The body Source would not be able to be consumed without first consuming the header Source, so there would have to be a strict ordering of accessing the response's member variables. This would lead to confusion and unexpected errors.
Lower Level Processing with akka-stream
The hypertext transfer protocol is just an application layer protocol, usually on top of TCP. And, it is a fairly simple message format:
The response message consists of the following:
A status line which includes the status code and reason message (e.g.,
HTTP/1.1 200 OK, which indicates that the client's request succeeded).
Response header fields (e.g., Content-Type: text/html).
An empty line.
An optional message body.
Therefore, you could use the Tcp binding to get a connection and parse the message ByteString Source yourself to get at the headers:
val maximumFrameLength = 1024 * 1024
val endOfMessageLine : () => Byte => Boolean = () => {
var previousWasCarriage = false
(byte) =>
if(byte == '\r') {
previousWasCarriage = true
false
}
else if(byte == '\n' && previousWasCarriage) {
previousWasCarriage = false
true
}
else {
previousWasCarriage = false
false
}
}
def subFlow =
Flow[ByteString].flatMapConcat(str => Source.fromIterable(str))
.splitAfter(endOfMessageLine())
Unfortunately this probably requires that your request be sent as a raw ByteString via the Tcp binding as well.
I am working on an ASP Net Core 2.0 Web API. One of my endpoints returns a json object that includes a text field that can be fairly large. When this field gets around 10Mb in size the controller just stops until the timeout is hit. When I debug, I see that the json object is created in my business logic and passed to the endpoint controller but the controller just stops right after it receives json object with no error and doesn't return to the caller until the request finally times out. I increased my requestTimeout to 20 mins even though the business logic generates the json object in less than 2 minutes. It just hangs until the 20 minute timeout is hit.
Here is my controller action;
[EXAMPLE 1]
[HttpGet(Name = "GetFile")]
public async Task<FileResponseDto> GetFile([FromRoute] int companyId, [FromRoute] int siteId, [FromRoute] int FileId,
[FromHeader(Name = "Accept")] string mediaType, CancellationToken cancellationToken)
{
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
// This is the point where the controller appears to hang
return await Task.Factory.StartNew(() => fileResponseDto, cancellationToken);
}
and my DTO object;
public class FileResponseDto
{
public string ReferenceId { get; set; }
public string Filename { get; set; }
public string ProcessingFile { get; set; }
}
The property that is the large string is the ProcessingFile property in the FileResponseDto class.
This works fine until my ProcessingFile property gets to around 30K lines (about 10Mb) and then the controller just hangs after it completes the line;
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
At this point, my assumption was that I have hit some limitation in the size of the json object. So, to test, I changed my controller so that it returns a file instead, like what is shown below;
[EXAMPLE 2]
[HttpGet(Name = "GetFile")]
public async Task<FileContentResults> GetFile([FromRoute] int companyId, [FromRoute] int siteId, [FromRoute] int fileId,
[FromHeader(Name = "Accept")] string mediaType, CancellationToken cancellationToken)
{
var fileResponseDto = _fileBll.GetFile(companyId, siteId, fileId, HttpContext);
var outputFile = Encoding.ASCII.GetBytes(fileResponseDto.ProcessingFile);
return await Task.Factory.StartNew(() =>
new FileContentResult(outputFile, new MediaTypeHeaderValue(MediaTypeNames.Application.Octet))
{
FileDownloadName = fileResponseDto.Filename
}, cancellationToken);
}
Making this change works and I can receive a file download dialog popup and a successful file if I select "Send and Download" in Postman.
So, this leads me to believe that there is something size related to the json object being transferred in the first example.
However, web searches have not turned up anything useful on this issue, which makes me think that perhaps I am missing something here.
I did find this link in StackOverflow and tried it by using...
var outfileJson = JsonConvert.SerializeObject<fileResponseDto>;
outfileJson.MaxJsonLength = Int32.MaxValue;
but outfileJson did not have a MasJsonLength property.
So.. any ideas?
EDIT 6/8/18
After 2 days, 22 views and no actual responses. I figured something must be wrong with my approach. I realized that I did not mention that I was performing these tests in Postman, which is where I was seeing the problem. After further digging, I found a post on GitHub that seemed to be related to what I was experiencing in Postman (the hang on large response payload). It seems that Postman has a limit in the number of "rows" it returns in the response. The GitHub post was a feature request to increase the number of rows.
I am not sure how to handle this StackOverflow question now. Since I didn't mention Postman in the original post, I don't feel right just answering my own question. So, I guess I will leave it as is for a couple of days to see if anyone chimes in with their thoughts before I do that.
As it turns out, the was, if fact, an issue with Postman and the size of the response payload it currently supports. If, instead of selecting Send, I select Send and Download in Postman, It will download the JSON object and pop up a dialog box to allow me to save it to my local drive. Then when I examine the file, I can see the json object is correctly formatted and transferred.
I confirmed that it was only a Postman issue and not a .NET HttpResponse issue by performing the API call in a .Net client application, which was able to receive the Json object without error.