Data binding failed - incompatibletypeerror

I created a new Ballerina type as below.
const string GENERAL="GENERAL";
const string SECURITY="SECURITY";
type INCIDENT_TYPE GENERAL|SECURITY;
public type incidentNotification record {
string title;
INCIDENT_TYPE incidentType;
};
Once I send a POST request to create a new incidentNotification, sendIncident method is executed.
public function sendIncident (http:Request req, incidentNotification sendIncidentBody) returns http:Response {}
The json payload that is sent with the request body as follows.
{
"title":"title",
"incidentType": "SECURITY"
}
But when I send that json with http request, it gives the error
data binding failed: Error in reading payload : error while mapping
'incidentType': incompatible types: expected
'janaka/incident-reporting-service:0.0.1:$anonType$4|janaka/incident-reporting-service:0.0.1:$anonType$5',
found 'string'
How to solve this error?

It's a bug in the JSON to Record conversion and it is fixed in the ballerina latest release(v1.0.0-alpha)
import ballerina/http;
import ballerina/log;
const string GENERAL="GENERAL";
const string SECURITY="SECURITY";
type INCIDENT_TYPE GENERAL|SECURITY;
public type IncidentNotification record {
string title;
INCIDENT_TYPE incidentType;
};
service hello on new http:Listener(9090) {
#http:ResourceConfig {
methods: ["POST"],
body: "notification"
}
resource function bindJson(http:Caller caller, http:Request req,
IncidentNotification notification) {
var result = caller->respond(notification.title);
if (result is error) {
log:printError(result.reason(), err = result);
}
}
}
Above sample resource works fine for following request
curl -v http://localhost:9090/hello/bindJson -d '{ "title": "title" , "incidentType" : "SECURITY"}' -H "Content-Type:application/json"
Response:
< HTTP/1.1 200 OK
< content-type: text/plain
< content-length: 5
<
* Connection #0 to host localhost left intact
title

Related

Uber Eats API - Fail to collect reports (Could not parse json: readObjectStart: expect { or n, but..)

We are facing an error when we are trying to request UberEats API to collect report about our restaurants based on the Ubereats documentation here.
The error :
'{"error":"Could not parse json: readObjectStart: expect { or n, but found \x00, error found in #0 byte of ...||..., bigger context ...||..."}'
We tried to run the query in python and postman and still facing the same error.
Need help to understand where we failed.
Here the python code run in VSC
import requests
import json
payload = {
"report_type": "FINANCE_SUMMARY_REPORT",
"store_uuids": "xxx",
"start_date": "2022-09-01",
"end_date": "2022-09-15"
}
headers = {
"authorization": "Bearer xxx"
}
report_response = requests.post('https://api.uber.com/v1/eats/report', data=payload, headers=headers)
report_response.text
'{"error":"Could not parse json: readObjectStart: expect { or n, but found \x00, error found in #0 byte of ...||..., bigger context ...||..."}'
Best regards,
You have to convert the payload to valid JSON string and send the request.
headers = {
"Authorization" : "*********",
"Content-Type" : "application/json"
}
import json
response = requests.post("https://api.uber.co/v1/eats/report", data = json.dumps(payload), headers=headers)

Rest Client gives Bad Request for HTTP PUT request

I'm new to Rest Client development. Need your help in figuring out how to get a proper response for below rest service.
curl --location --request PUT 'sandbox-url/TokenGeneratorAPI/v1/update_pay_status' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {{token}' \
--data-raw '{
"pay_id":000000000,
"status":1,
"amount":0.00,
"pay_method":0,
"pay_sys_ref":"test"
}'
I created a class in client side for request object like below.
public class PaymentRqBean {
#XmlElement(name="pay_id")
String pay_id;
#XmlElement(name="status")
String status;
#XmlElement(name="amount")
String amount;
#XmlElement(name="pay_method")
String pay_method;
#XmlElement(name="pay_sys_ref")
String pay_sys_ref;
public String getPay_id() {
return pay_id;
}
public void setPay_id(String pay_id) {
this.pay_id = pay_id;
}
}
......and getters setters for other attributes
And created a method for calling the web service in another class like below.
public PaymentRsBean callWS(PaymentRqBean pReq) {
PaymentRsBean prs = new PaymentRsBean();
Client client = ClientBuilder.newClient();
client.register(new Authenticator(com.boc.conf.Configurations.objProperty.getProperty("ikUserName"), com.boc.conf.Configurations.objProperty.getProperty("ikPassword")));
WebTarget webTarget = client.target(url);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.accept(MediaType.APPLICATION_JSON).put(Entity.json(pReq));
I'm getting HTTP 400 BAD REQUEST for above. I would be so thankful for any help given in solving this.
(Is it because #XmlRootElement? )
The problem is the way you are defining the attributes of your PaymentRqBean class.
The variables 'pay_id', 'status', 'amount' and 'pay_method' must be of numeric type (int, double...), since the request you launch indicates that they are numeric, not Strings.
"pay_id":000000000,
"status":1,
"amount":0.00,
"pay_method":0

RESTful client in Unity - validation error

I have a RESTful server created with ASP.Net and am trying to connect to it with the use of a RESTful client from Unity. GET works perfectly, however I am getting a validation error when sending a POST request. At the same time both GET and POST work when sending requests from Postman.
My Server:
[HttpPost]
public IActionResult Create(User user){
Console.WriteLine("***POST***");
Console.WriteLine(user.Id+", "+user.sex+", "+user.age);
if(!ModelState.IsValid)
return BadRequest(ModelState);
_context.Users.Add(user);
_context.SaveChanges();
return CreatedAtRoute("GetUser", new { id = user.Id }, user);
}
My client:
IEnumerator PostRequest(string uri, User user){
string u = JsonUtility.ToJson(user);
Debug.Log(u);
using (UnityWebRequest webRequest = UnityWebRequest.Post(uri, u)){
webRequest.SetRequestHeader("Content-Type","application/json");
yield return webRequest.SendWebRequest();
string[] pages = uri.Split('/');
int page = pages.Length - 1;
if (webRequest.isNetworkError || webRequest.isHttpError){
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
else{
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
}
}
I was trying both with the Json conversion and writing the string on my own, also with the WWWForm, but the error stays.
The error says that it's an unknown HTTP error. When printing the returned text it says:
"One or more validation errors occurred.","status":400,"traceId":"|b95d39b7-4b773429a8f72b3c.","errors":{"$":["'%' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."]}}
On the server side it recognizes the correct method and controller, however, it doesn't even get to the first line of the method (Console.WriteLine). Then it says: "Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'".
Here're all of the server side messages:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://localhost:5001/user application/json 53
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
Route matched with {action = "Create", controller = "User"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Create(TheNewestDbConnect.Data.Entities.User) on controller TheNewestDbConnect.Controllers.UserController (TheNewestDbConnect).
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ValidationProblemDetails'.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
Executed action TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect) in 6.680400000000001ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'TheNewestDbConnect.Controllers.UserController.Create (TheNewestDbConnect)'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 11.3971ms 400 application/problem+json; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
I have no idea what is happening and how to solve it. Any help will be strongly appreciated!
Turned out I was just missing an upload handler. Adding this line solved it: webRequest.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(JsonObject));

Missing request header 'authToken' calling RestAPI method

I have this RestAPI method
#GetMapping(path = "/menus",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<MenuPriceSummary>> allMenus(HttpServletRequest request, #RequestHeader(value="Authorization: Bearer") String authToken) {
String username = jwtTokenUtil.getUsernameFromToken(authToken);
User user = userService.findByUserName(username);
return ResponseEntity.ok(menuService.allMenus(user));
}
which I call from curl
curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJsb3Blei5hbnRvbmlvODVAZ21haWwuY29tIiwiZXhwIjoxNTk0MTkzNDYwLCJpYXQiOjE1MzM3MsM0NjB9.9pXvdiRMM5fjE4Ur5nqKvwvRLmNWyn6tY6y5fPXOg_BWEW2sJ8vnrLTXPfiA-Sc6Qk2XTwi6FhlIhFEQKip4aQ" "http://127.0.0.1:1133/canPeris/api/v1/users/menus"
But I got this error:
"status":400,"error":"Bad Request","message":"Missing request header 'Authorization: Bearer' for method parameter of type String"'authToken' for method parameter of type String","tr....
You can't use #RequestHeader that way. The values from the headers get split up by : and added to a Map, so every value containing a : is impossible.
You will have to change your annotation to #RequestHeader(value="Authorization") and then remove the Bearer from the authToken.
Spring MVC provides annotation #RequestHeader that can be used to map controller parameter to request header value .
Can you please change your method to
#GetMapping(path = "/menus",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<MenuPriceSummary>> allMenus(
#RequestHeader(value="Authorization") String authToken,
HttpServletRequest request) {
String username = jwtTokenUtil.getUsernameFromToken(authToken);
User user = userService.findByUserName(username);
return ResponseEntity.ok(menuService.allMenus(user));
}
You can also make use of Interceptors to validate headers so that other rest endpoints in your application can make use of it .

send msg to Azure service bus que via REST

The Azure Queues are exposed to REST API.To make the REST call works. I ran a sample test on POSTMAN. The POST call
https://yournamespace.servicebus.windows.net/yourentity/messages
Also, Passing below 2 headers and values.
Header 1:
Authorization: SharedAccessSignature sr=https%3A%2F%2F.servicebus.windows.net%2Fyourentity&sig=yoursignature from code above&se=1529928563&skn=KeyName
Example:
SharedAccessSignature sr=https%3A%2F%2Fservicebussoatest1.servicebus.windows.net%2Fpublishque&sig=a0wmRklbCGFCYoSCViij9gagtZV9Bg+vU=&se=1529928563&skn=testpolicy
Header 2:
Content-Type: application/json
But even though I have passed the correct Authorization value, I am getting the error below:
401:Invalid Authorization Token signature
401:Invalid Authorization Token signature
According to the 401 error meanings that the token is not vaild.
Firstly please make sure that your policy has access to send the message.
Secondly, if you want to use the azure service bus Send Message Rest APi. The format should be following.
POST https://<yournamespace>.servicebus.windows.net/<yourentity>/messages
Authorization: SharedAccessSignature sr=https%3A%2F%2F<yournamespace>.servicebus.windows.net%2F<yourentity>&sig=<yoursignature from code above>&se=1438205742&skn=KeyName
ContentType: application/atom+xml;type=entry;charset=utf-8
We also could get more information about Service Bus access control with Shared Access
Signatures from this article.
I also do a demo with postman. It works correctly on my side.
I use the following code to get the SAS token.
public static string GetSasToken(string resourceUri, string keyName, string key, TimeSpan ttl)
{
var expiry = GetExpiry(ttl);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
private static string GetExpiry(TimeSpan ttl)
{
TimeSpan expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
}
string queueUrl = "https://tomtestsb.servicebus.windows.net/" + "queue" + "/messages";
string token = GetSasToken(queueUrl,"Key", "value", TimeSpan.FromDays(1));
We could get the key and value with Azure portal
Test it with Postman.
Headers:
Authorization:SharedAccessSignature sr=https%3a%2f%2fyournamespace.servicebus.windows.net%2fqueuename%2fmessages&sig=SyumAUNnqWFjW2MqjwlomU%2fbblqZljq6LPJp3jpfU%2b4%3d&se=1529478623&skn=KeyName
Content-Type:application/xml
Body
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">This is a message.</string>
Test Result:
Simple 2 step process:
First you can import the below Curl in postman:
curl --location --request POST '{{topicQueueForAzureServiceBusUri}}' \
--header 'ContentType: application/atom+xml;type=entry;charset=utf-8' \
--header 'Authorization: {{SasTokenForAzureServiceBus}}' \
--header 'Content-Type: application/json' \
--data-raw '{"YOUR JSON"}'
Copy All the key generation script to the prerequisite step of Postman Request and replace first four variable values from your topic/queue config:
var namespace = "YOUR Namespace";
var topicQueueName = "YOUR TOPIC/QUEUE Name";
var sharedAccessKeyName = "YOUR sharedAccessKeyName";
var sharedAccessKey = "YOUR sharedAccessKey";
var topicQueueForAzureServiceBusUri = "https://" + namespace + ".servicebus.windows.net/" + topicQueueName + "/messages";
pm.collectionVariables.set("topicQueueForAzureServiceBusUri", topicQueueForAzureServiceBusUri);
var sasToken = createSharedAccessToken(topicQueueForAzureServiceBusUri, sharedAccessKeyName, sharedAccessKey);
pm.collectionVariables.set("SasTokenForAzureServiceBus", sasToken);
function createSharedAccessToken(uri, saName, saKey) {
if (!uri || !saName || !saKey) {
throw "Missing required parameter";
}
var encoded = encodeURIComponent(uri).toLowerCase();
var now = new Date();
var week = 60*60*24*7;
var ttl = Math.round(now.getTime() / 1000) + week;
var signature = encoded + '\n' + ttl;
var hash = CryptoJS.HmacSHA256(signature, saKey);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
return 'SharedAccessSignature sr=' + encoded + '&sig=' +
encodeURIComponent(hashInBase64) + '&se=' + ttl + '&skn=' + saName;
}
This worked for me:
The url to POST to: https://[ServiceBusNamespace].servicebus.windows.net/[QueueName]/messages
Authorization: use code provided by Tom Sun - MSFT
Content-Type: application/json