I am trying to integrate my GraphQL Web API with AppSync. But I am getting the following error
"errorType": "MappingTemplate",
"message": "Template transformation yielded an empty response."
My Data Source HTTP end Point is : https://mybooking123.com
My Query is:
mutation
{
Booking(ID:111,BusNumber:"AAAA1", comment:"None")
{
BusNumber
PassngerName
TravelDate
TravelTime
ValidityDate
ValidaityTime
ErrorCode
}
}: [BookingResponse]
Schema
type Mutation {
Booking(
ID: Int!,
BusNumber: String,
comment: String
): [BookingResponse]
}
type BookingResponse
{
BusNumber: String
PassngerName: String
BookingDate: String
BookingTime: String
ValidityDate: String
ValidaityTime: String
ErrorCode: Int
}
AppSync - Request Mapping Template
{
"version": "2018-05-29",
"method": "POST",
"resourcePath": "/GraphQL",
"params":{
"query":$util.toJson($ctx.args),
"headers": {
"Authorization": "$ctx.request.headers.Authorization"
}
}
}
AppSync - Response Mapping Template
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
## If the response is not 200 then return an error. Else return the body **
#if($ctx.result.statusCode == 200)
#set($body = $util.parseJson($ctx.result.body))
$util.toJson($body) ##make it $body.data depending on the return on your rest api
#else
$utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
My GraphQL API is working with out AppSync. But I want to implement AppSync to access the GraphQL API. I am not sure what's wrong with the template mapping. Thanks for your help.
The problem can be with the $utils.appendError VTL method (line 10 of the Response Mapping Template).
Based on your Response mapping template, if there is an error in the Velocity parsing, AppSync will throw an error (line 2).
If there is no error, the Velocity parser will evaluate the response ($ctx.result) and send back the body if the statusCode is equal to 200. So far so good. The problem is if the statusCode is different from 200 (line 9).
In that case, AppSync should also throw an error. But you are using the $util.appendError. In that case, VTL will add error information to the context and will keep working to generate the result template. But because it does not do anything after this step, the generated template is empty (Template transformation yielded an empty response.).
the info from AppSync Resolver Mapping Util docs:
$util.appendError(String)
Appends a custom error. This can be used in request or response mapping templates if the template detects an error with the request or with the invocation result. Unlike $util.error(String), the template evaluation will not be interrupted, so that data can be returned to the caller.
In GraphQL is possible to have a response that has a part that was successful and a part that was an error. That happens because the response probably is coming from two different resolvers. If one of them worked in the other doesn't, you can get the response both responses in the final GraphQL response. In that scenario, AppSync will add the success response to the expected GraphQL field and add the error to the context.
To solve your issue, instead of using $util.appendError use $util.error in line 10. With that, if your call failed, AppSync will add the error information and halt the VLT execution instead of try to perform the next steps to yield the result.
Related
I would like to make a successful API call, then print the values in order to see if it works. My main goal is to analyze the data, after I can make a successful API call, and build a systematic strategy for trading.
System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)
namespace marketstacktest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var options = Options.Create(new MarketstackOptions() { ApiToken = "secretTokenHere" });
var marketstackService = new MarketstackService(options, NullLogger<MarketstackService>.Instance);
var appleSymbol = "AAPL";
var fromDate = DateTime.Now.AddDays(-200);
var toDate = DateTime.Now;
//error at the await System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)."
List<Marketstack.Entities.Stocks.StockBar> stock = await marketstackService.GetStockEodBars(appleSymbol, fromDate, toDate);
foreach (var stock_i in stock)
{
Console.WriteLine($"close: {stock_i.Close}");
}
}
}
}
In the API manual, which is directly linked from the github, it gives information about all of the error codes. The relevant ones here are these two:
Code
Type
Description
403
https_access_restricted
HTTPS access is not supported on the current subscription plan.
403
function_access_restricted
The given API endpoint is not supported on the current subscription plan.
Their class library on github is just wrapping a json REST api. Every call to the API is just an http request, returning data as json objects. The 403 error indicates that your request was accepted as a valid request, but intentionally rejected by the server for some reason. And according to the docs, the error was because your account is not allowed access to either https or to the type of request.
Their free-tier subscription only includes end-of-day data, which is what you requested, so it wouldn't make sense for that not to be allowed. So, your app is almost certainly making an https call.
I went to the examples at the very beginning of their quick start guide, and chose the end-of-day example to match your app, and clicked on the link. It worked, and gave a bunch of json records. But, the request they made was using 'http' not 'https'.
Changing the requst to 'https' elicited a 403 response with this content (formatted for readability):
{
"error":
{
"code": "https_access_restricted",
"message": "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."
}
}
At this point we have enough to be almost certain that this is your issue. The final thing is to go look up how to turn https requests off in their class library. To avoid having to go through the code, I checked the help at the bottom of the page one more time, and found this (formatted for readability):
var options = Options.Create(new MarketstackOptions(){
ApiToken = apiKey,
MaxRequestsPerSecond = 3,
Https = true
});
Welp. This should probably be in their first example, since that's what people are most likely to try first, but it's not. So, to stop trying to make http requests, you just need to set the Https option to false in your code. You just need to add that to the options in your code, like so:
var options = Options.Create(new MarketstackOptions(){
ApiToken = "secretTokenHere",
Https = false
});
I will leave the testing to you, but from the browser test, we know that the request should work, unless there's a bug in their library. Given the information that was available, this is almost certainly the issue.
Start up a new ASP.NET Core Web API project in Visual Studio.
Now change the ValuesController.Get() action to be this:
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
var results = new[] {"hi"}.Select<string, string>(x => throw new ArgumentException());
return Ok(results);
}
When you hit this you get a 200 response with a response body of just [
Now if you now change it to enumerate the erroring Select before passing to Ok() it will raise an error correctly and return 500 with details of the error as expected in the default ASP.NET API template:
var results = new[] {"hi"}.Select<string, string>(x => throw new ArgumentException());
results.ToList();
return Ok(results);
What is happening here?
In the first example, the status code and response headers are sent to the client before the JSON serialisation starts. Giving the JSON serialiser an IEnumerable<string> results in deferred creation of the collection, which ends up being performed during the serialisation process. This means that the 200 status code and response headers are sent before the exception is thrown. Because the status code has already been sent, it cannot be changed from 200. The response cannot be "undone" either - it's a forward-only stream of data.
In the second example, the collection is created before the JSON serialisation process runs. In this case, the exception is thrown before the call to return Ok(results) can be reached. Whatever you're using for global exception handling catches this exception and writes out a response with a status code of 500.
I'm using AspNetCore 1.1.3 to create some endpoints and swagger to check them.
When using Resonse codes:
Status401Unauthorized
Status403Forbidden
Swagger tells me the response code is 401/403 like i would expect.
But when i use Status404NotFound swagger shows 0 as the response code and body is:
{
"error": "no response from server"
}
I'm using the following lines to return status code and body. There is no other change.
Response.StatusCode = StatusCodes.Status404NotFound; // or Status403Forbidden
return new JsonResult("{\"statusCode\":404}"); // 403
Is this expected behaviour? I would like to use the response codes in my application for error handling and 404 returning empty statuscode/body is not really useful.
I've confirmed that I have permissions to perform the request.
According to amazon's Cloud Search Dev Troubleshooting Guide the error I'm experiencing is likely due to the .net sdk using the wrong api version. I don't see a way to specify the api version explicitely.
I want to avoid having to manually create the http request.
I want to make the request through the SDK.
I've tried all the available versions of the SDK and all of them give me this error.
I've also tried specifying the request properties in various combinations. Nothing works.
Can anybody give me direction as to how I can resolve this issue?
Expected behavior: return info for all index fields
Actual behavior:
error -
"Result Message:
Amazon.Runtime.AmazonUnmarshallingException : Error unmarshalling response back from AWS. Response Body: {
"message": "Request forbidden by administrative rules",
"__type": "CloudSearchException"
}"
----> System.Xml.XmlException : Data at the root level is invalid. Line 1, position 1.
Code sample:
var _configClient = new AmazonCloudSearchClient(
WebConfigurationManager.AppSettings["CloudSearchAccessKey"],
WebConfigurationManager.AppSettings["CloudSearchSecretKey"],
new AmazonCloudSearchConfig
{
RegionEndpoint = RegionEndpoint.USWest2,
ServiceURL = WebConfigurationManager.AppSettings["CloudSearchUrl"]
});
await _configClient.DescribeIndexFieldsAsync(new DescribeIndexFieldsRequest())
CloudSearch is returning json, which you can see in your response body, and the SDK is trying to unmarshal that into xml. When you make a query directly, you can add &format=xml to get xml results. There should be an analogous option in the SDK.
I create controllers using entity. There are severel models in my project and for every model in context "Get method" works fine, but this one, which is the same like others, did'nt.
This is simple code:
// GET: api/Proizvodi
public IQueryable<Proizvodi> GetProizvodi()
{
return db.Proizvodi;
}
I tested with fidler and this is message:
{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Self referencing loop detected with type 'System.Data.Entity.DynamicProxies.Proizvodi_B322A16527536C491FCFE47A9DC60617BBB3A2AAF1FABD41D99F924F0D8FE589'. Path '[0].JediniceMjere.Proizvodi'.","ExceptionType":"Newtonsoft.Json.JsonSerializationException",...
I know there are severel same question and im looking for answer but can't find. Is there problem with entity freimwork, problem with serialization or something else. ??
Maybe this help: when i delete all records from database for this model/class, "Proizvodi", i get "HTTP/1.1 200 OK".
Add thhe following to
Global.asax
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;