How should I handle an application/javascript response type in Swagger? - jsonp

I have a swagger app that works when JSON is returned, but not with JSONP. Success and fail cases are described further down.
It is worth noting that the exact controller code shown below works fine under vanilla node/express - the problem seems to occure when the response goes through the swagger response validator.
The snippet of controller code that handles the response is as follows:
retVal.success = true;
retVal.data = jsondata;
res.set('Content-Type', 'application/javascript');
res.jsonp(200, retVal);
swagger.yaml:
swagger: "2.0"
info:
title: sometitle
version: v1
host: localhost:3000
basePath: /
schemes:
- http
consumes:
- application/json
- application/javascript
produces:
- application/json
- application/javascript
- text/javascript
paths:
/loadallrepos:
x-swagger-router-controller: loadallrepos
get:
summary: summary here...
description: |
description here...
operationId: loadallrepos
parameters:
- name: callback
in: query
description: Passed by .ajax call for cross-domain requests
required: false
type: string
responses:
200:
description: Success
schema:
$ref: "#/definitions/loadallreposResponse"
definitions:
loadallreposResponse:
type: object
required:
- success
- data
properties:
success:
type: boolean
data:
type: object
required:
- nextrefresh
properties:
nextrefresh:
type: integer
If I make a request without the callback parameter, it works:
request: localhost:3000/loadallrepos
response:
{
"success": true,
"data": {
"nextrefresh": 3439704
}
}
If I turn it into a jsonp request though, it fails:
request: localhost:3000/loadallrepos?callback=jQuery111106460774131119251_1439402109118&_1439402109119
response:
{
"message": "Response validation failed: value expected to be an array/object but is not",
"failedValidation": true,
"originalResponse": "typeof jQuery111106460774131119251_1439402109118 === 'function' && jQuery111106460774131119251_1439402109118({
"success": true,
"data": {
"nextrefresh": 3442750
}
});"
}
Again, this works under vanilla node/express. Any help is greatly appreciated!

JSONP APIs return a string of JavaScript. Your Swagger definition says your API returns an object defined at #/definitions/loadallreposResponse which is of type object. What happens is swagger-node/swagger-tools sees a type of object and attempts to use JSON.parse on the response body and fails. To support JSONP with Swagger, you need to make your response schema be of type string to avoid response validation failure.

Related

Mule design centre defining 400 response but trying it does not return same response

I am defining my api contract in RAML in Mule Anypoint platform Design centre .
Here is the simple contract :
#%RAML 1.0
title: test_experiment
version: v1
mediaType: application/json
/test:
put:
headers:
trackingId:
type: string
description: "Track each request"
minLength: 3
responses:
200:
body:
application/json:
example:
{
"msg": "successfully done"
}
400:
body:
application/json:
example:
{
"msg": "something bad was submitted",
"id" : "001"
}
Next I am trying to 'test it' in Documentation tab and when I purposefully do not enter a trackingId I do get a 400 response code but the response payload is different.
I have defined the response payload as : ( expected payload )
{
"msg": "something bad was submitted",
"id" : "001"
}
However the payload response in 'try it' in design centre is :
{
"code": "REQUEST_VALIDATION_ERROR",
"message": "Error validating header: expected minLength: 3, actual: 0"
}
So why is the 400 response not being returned as I have it defined in my raml ?
Edit1 : This behaviour is all observed in Design Centre , I am not providing an implementation and then testing it , I am using design centre Documentation and 'Try it' feature as per image below :
Because it is a mock, not a real implementation. When you are testing in Design Center you are using the Mocking Service that simulates reponses. The error you are getting is because the request doesn't match with the specification. The Mocking Service usually uses only the first status code it finds in the API RAML. If you want it to return your error use a behavioral header like MS2-Status-Code to set the error code. For example set the header MS2-Status-Code to 200,400. Although I'm not sure it will work to override the validation error from the Mocking Service. You will need to try.

why i get apikit:router not found 404 error in mule eventhough it requests an already running and deployed api

i have created 2 apis: system and experience for a project. The system had already been deployed into the cloudhub and running successfully. The experience api needs to invoke the system api through a router using the URL:
http://demo-insurance-system-api.us-e2.cloudhub.io
and uriparam is :customer
and queryparams are:?fname=James&lname=Butt
Its working perfectly fine.
but when i want to hit the same url from experience api's requester it gives me
ERROR 2020-05-18 01:58:15,217 [[muleinsurance-exp-api].http.requester.requestConfig.04 SelectorRunner] [event: ] org.mule.runtime.core.internal.exception.OnErrorPropagateHandler:
********************************************************************************
Message : HTTP OPTIONS on resource 'http://demo-insurance-system-api.us-e2.cloudhub.io' failed: not found (404).
Error type : HTTP:NOT_FOUND
Element : muleinsurance-experience-api-main/processors/0 # muleinsurance-exp-api:muleinsurance-experience-api.xml:17
Element XML : <apikit:router config-ref="muleinsurance-experience-api-config"></apikit:router>
(set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
the onpremise testing is done in using postman and the experience url is:
http://localhost:8081/demoapi/customer?fname=James
the experience api raml is:
#%RAML 1.0
title: muleinsurance-experience-api
version: 1.0.0
traits:
client-id-required:
headers:
client_id:
type: string
client_secret:
type: string
responses:
401:
description: Unauthorized, The client_id or client_secret are not valid or the client does not have access.
404:
description: No Record found.
429:
description: The client used all of it's request quota for the current period.
500:
description: Server error ocurred
503:
description: Contracts Information Unreachable.
/demoapi:
/{searchString}:
get:
description: invokes either customer or policy request
queryParameters:
fname:
description: first name
example: Sumitra
required: false
type: string
lname:
description: Last name
example: Ojha
required: false
type: string
dob:
description: Date of Birth
example: 1/2/2003
required: false
type: string
customerID:
description: CustomerID
example: BU79786
required: false
type: string
policytype:
description: type of policy taken
example: Personal Auto
required: false
type: string
responses:
200:
body:
application/json:
example:
{"message": "connecting to System API"}
here i am adding the HTTP request xml snippet:
<choice doc:name="Choice" doc:id="444a5cd6-4aee-441a-8736-2d2fff681e2e" >
<when expression="#[attributes.uriParams.searchString == 'customer']">
<http:request method="GET" doc:name="Request" doc:id="30958d05-467a-41b1-bef3-83426359f2aa" url="http://demo-insurance-system-api.us-e2.cloudhub.io"><http:uri-params ><![CDATA[#[output application/java
---
{ customer : attributes.uriParams.searchString}]]]></http:uri-params>
<http:query-params ><![CDATA[#[output application/java
---
{ fname : vars.fname,
lname : vars.lname,
dob : vars.dob}]]]>
kindly point out where i need to improve. thanks in advance.
The problem is indicated in the error message: HTTP OPTIONS on resource 'http://demo-insurance-system-api.us-e2.cloudhub.io' failed: not found (404).
It looks like your HTTP Request in the experience API is using the HTTP Options method. The RAML indicates that the API only accepts the HTTP GET method. In the XML it should look like: <http:request method="GET" ...

Swagger Editor: How to define simple response string and redirect

Defining responses in swagger is easy:
responses:
# Response code
200:
description: Successful response
schema:
title: OK
type: array
items:
title: Person
type: object
properties:
name:
type: string
single:
type: boolean
How I can return simple string and not an array
What if API endpoint makes a redirect, actually in my case redirecting is the successful attempt.
Let's skip the fact that redirecting in an API is a non-professional thing!
Update: Responding with a string is easy too:
description: A simple string response
schema:
type: string

Crossdomain jQuery ajax request was not called and give error status "parsererror"

I am trying to call cross domain url. which has response text as below.and it is valid json response.
[{"LANG_CODE":"UK_EN","COU_ISO_CODE":"BGR"},
{"LANG_CODE":"UK_EN","COU_ISO_CODE":"HUN"},
{"LANG_CODE":"UK_EN","COU_ISO_CODE":"PRT"},
{"LANG_CODE":"UK_EN","COU_ISO_CODE":"UGA"}]
Jquery ajax code which i am using for calling cross.
$.ajax({
url: "http://someDomainName/restfulservice/Api/Countries/Get_Json",
dataType: 'jsonp',
crossDomain: true,
async: false,
success: function (data) {
alert("success >> "+data);
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error : "+errorThrown + ", textStatus >> "+textStatus);
}
});
every time it goes to error block. when i inspect this service in browser then it gives response text with valid json string.but through code i am getting error "jQuery18305917718204907095_1409810925309 was not called, status: parsererror".
while this code is working for the url "http://api.geonames.org/findNearbyPlaceNameJSON?lat=47.3&lng=9&username=demo".
what could be the issue for same ?
It is sending back JSON but you have said dataType: 'jsonp'. JSON is not JSONP.
Either change the service to support JSONP or change the client to expect JSON (which might require you to find some other way to circumvent the same origin policy)

Callback not getting called on Internet Explorer for Ajax JSONP call

I'm making an Ajax call using JSONP to fetch JSON data from a third-party (domain different from my site) and its working on Chrome and Firefox but failing on IE (9 & 10 are the versions I have tried). In the IE debugger I see the call is completing (with Http 200) but the callback I've specified for the JSONP call is not being invoked.
My code looks like this:
$.ajax({
url: 'http://api.yipit.com/v1/deals/?key=mykey&division=seattle&limit=1000',
dataType: 'jsonp',
contentType: "text/javascript",
async: false,
cache: false,
crossDomain: true,
jsonp: 'callback',
jsonpCallback: 'processResult',
error: function (xhr, textStatus, error) {
window.alert(error);
},
success: function (data) {
window.alert(JSON.stringify(data));
_yipit_deals = data.response.deals;
}
});
And the response body looks like this:
<html><body><pre>processResult({
... [valid JSON data]
});</pre></body></html>
When the call is made, the error function is getting invoked with error as: Error: processResult was not called and the IE debugger shows a script error caused when trying to parse the <html><body><pre> tags in the response. When running on Chrome and Firefox these html tags don't exist in the response body and I'm not sure why the response is different in the case of IE.
It appears that these tags are causing IE to barf and not be able to invoke the callback. I've tried specifying other values for contentType such as "text/html", "text", "application/javascript" and even not specifying it at all, but its not made any difference. I'm using JSONP to get around the cross-domain issue.
Any ideas? Thanks!
You have to pass an explicit format argument to the URL:
&format=json
Otherwise, it's just pretty-printing the output:
<html><body><pre>{
"meta": {
"code": 401,
"message": "Key not recognized",
"name": "AuthenticationFailed"
},
"response": {}
}</pre></body></html>
Also, I would set async back to true.