How to send different RAML response with different input query parameters - api

I have a question related to RAML sending different response. In the below RAML, I want to send the response based on the query parameter. If my query parameter (flightId) is "F001", I should get a response only for the data F001. But I am getting the response with all the data specified in the response. May I know how to filter the unwanted data.
#%RAML 1.0
baseUri: https://mocksvc.mulesoft.com/mocks/9b7a0390-ecf4-4ff4-b307-0b7d87ed9495 # baseUri: https://mocksvc.mulesoft.com/mocks/b133e2e4-f0e3-49a0-b224-8f36358e04ca #
title: FlightApi-Rajesh
version: 1.0.1
/{flightId}:
description: Flight Id
get:
queryParameters:
flightId:
displayName: flightId
type: string
required: true
description: Flight name with its ID
example: F0001
description: Get the flight with `flightId = {flightId}`
responses:
200:
body:
application/json:
example: |
{
"F001":{
"flightName": "Ingido",
"Location": "Mumbai",
"flightId": "F001",
"Destination":"Delhi",
"timing":"19:55 HRS"
},
"F002":{
"flightName": "SpiceJet",
"Location": "Pune",
"flightId": "PNQ012",
"Destination":"Chennai",
"timing":"15:00 HRS"
}
}
404:
body:
application/json:
example: |
{"message": "Flight not found"}

RAML is a design specification for REST APIs. When you run the mock service based on RAML, it does not have the capability of generating dynamic responses, which is what you are trying to do. Please refer Mule forum which confirms this - https://forums.mulesoft.com/questions/60487/can-the-example-in-the-raml-be-dynamic.html
If your requirement is to create a mock service with dynamic responses, there are other ways to achieve implementing such mock services - SOAPUI, Dynatrace, etc.
http://blog.maheeka.me/2016/11/parasoft-virtualizer-tips-for.html
https://www.soapui.org/rest-testing-mocking/service-mocking-overview.html
If your requirement is to use RAML and try dynamic responses, you will have to create a Mule ESB project based off the RAML. You can then implement dynamic responses based on input received with Mule configurations.
http://workshop.tools.mulesoft.com/modules/module3_lab1#step-1-create-a-new-mule-project-and-import-raml-definition

You'll likely want to change your example to this. A mock endpoint will return your example response every time, so if you're only expecting one match, the example should reflect that. Keep this in mind, because you will not be able to modify the response of a mocked API based on user input:
/{flightId}:
description: Flight Id
get:
queryParameters:
flightId:
displayName: flightId
type: string
required: true
description: Flight name with its ID
example: F0001
responses:
200:
body:
application/json:
example: |
{
"F001":{
"flightName": "Ingido",
"Location": "Mumbai",
"flightId": "F001",
"Destination":"Delhi",
"timing":"19:55 HRS"
}
}
404:
body:
application/json:
example: |
{"message": "Flight not found"}
If you have received this data from the database connector, even with a single record returned, you'll get a list of results. You'll need to transform it like this:
%dw 1.0
%output application/json
%vars flight = (payload filter $.flightId == flowVars.flightId)[0]
---
{
(flowVars.flightId): flight
}

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.

Open API schema conditional response field based on the presence of a query parameter

I am working on providing a GET REST API where I would like to conditionally include the total_documents field (its an integer count of the total number of records present in the DB table).
The API signature and response payload will be something like:
GET /endpoint/?total_documents&.....
Response Payload:
{
documents: [....],
total_documents: 100
}
Now I would like the total_documents field to be appeared in the response payload if and only if the total_documents query parameter exists in the URL.
This is what I tried, based on my schema:
fastify.addSchema({
$id: 'persistence-query-params',
title: "PersistenceQueryParams",
type: 'object',
description: 'Persistence Service GET API URL query specification. Applicable for GET API only.',
properties: {
'total_documents': {
description: 'Total number of documents present in the collection, after applying filters, if any. This query paramater does not take any value, just pass it as the name (e.g. &total_documents).',
nullable: true,
},
},
}
querystring: {
description: 'Persistence Service GET API URL query specification. Applicable for GET API only.',
$ref: 'persistence-query-params#',
},
response: {
200: {
properties: {
'documents': {
description: 'All the retrieved document(s) from the specified collection for the specified service database and account.',
type: 'array',
items: {
$ref: 'persistence-response-doc#',
}
},
'total_documents': {
description: "If total_documents query paremeter is specified, gives the total number of documents present in the collection, after applying query paramaters, if any. If total_documents is not specified, this field will not be available in the response payload.",
type: 'number',
default: -1,
},
},
dependencies: {
'total_documents': { required: ['querystring/properties/total_documents'] },
},
},
'4xx': {
$ref: 'error-response#',
description: 'Error response.'
}
}
What is the way out here?
Thanks,
Pradip
JSON Schema has no notion of a request or response or HTTP.
What you have here is an OpenAPI specification document.
The OpenAPI specification defines a way to access dynamic values, but only within Link Objects or Callback Objects, which includes the query params.
Runtime expressions allow defining values based on information that
will only be available within the HTTP message in an actual API call.
This mechanism is used by Link Objects and Callback Objects.
https://spec.openapis.org/oas/v3.1.0#runtime-expressions
JSON Schem has no way to reference instance data, let alone data relating to contexts it is unaware of.

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" ...

How to check if ID in the URI is null and throw an error?

I tried to check if a specific URL doesn't specified an ID
This are what I've got so far:
http://localhost:8082/orders/1234 ---- Success!
http://localhost:8082/orders/ ---- URL not found!
I want to throw and error something like "Id not specified!" not a URL not found.
Look at Validation Module
Look at the "Matches Regex" section down.
I have not tried it
Hope it may help
the believe the best approach for you is to start using RAML. you can design the endpoint in RAML and specify what error to be thrown if the request is not a match.
/{order_id}:
get:
description: Get a Order by id
responses:
200:
body:
application/json:
type: Foo
example: !include examples/Order.json
400:
body:
application/json:
type: Error
example: !include examples/Error.json
in the above RAML definition if there is no orders/{order_id} you will get a http 400 returned.
Define a custom error handling and that will return error description alongside other required data
set status code 400 in a variable, map fields as per below example.
ex:
{
"error": {
"errorCode": "NOT_FOUND",
"errorDateTime": "2019-10-10T14:00:46",
"errorMessage": "The requested API cannot be found, ID is not specified",
"errorDescription": "Description: /orders"
}
}

RAML : How to require parameter A OR parameter B

I'm writing some REST documentation with RAML but I'm stuck.
My problem:
- I have a GET request used for search that can take a parameter "id" or (exclusive or) "reference". Having only one of them is required.
I know how to say "this param is required" but I don't know how to say "having one of these params is required". Is it even possible?
The following example written in RAML 1.0 defines two object types in Url and File then creates another object Item which requires Url OR File in ext. If you change the included examples (which currently validate), you'll see that they fail if the property does not conform to one or the other definition. Hope that helps! LMK if you have any other questions and I'll do my best.
[EDIT: hmm I think I am seeing your problem now, the final example I've just added, named should_fail, (which has one of each type together in the example) still validates and you want a way to make it fail validation.]
[UPDATE: OK I figured a mildly hacky way to do this. Use maxProperties: 1 in the object which should have properties appear alone, see updated code below which fails the final example during validation.]
#%RAML 1.0
types:
Url:
properties:
url:
type: string
example: http://www.cats.com/kittens.jpg
description: |
The url to ingest.
File:
properties:
filename:
type: string
example: kittens.jpg
description: |
Name of the file that will be uploaded.
Item:
description: |
An example of a allowing multiple types yet requiring
one AND ONLY one of two possible types using RAML 1.0
properties:
ext:
maxProperties: 1
type: File | Url
examples:
file_example:
content:
ext:
filename: video.mp4
url_example:
content:
ext:
url: http://heres.a.url.com/asset.jpg
should_fail:
content:
ext:
url: http://heres.a.url.com/asset.jpg
filename: video.mp4
I had the same problem. User can provide either a textual input OR a file input, but not both.
Both have different fields and I detect the request type from the field names. i.e if the request has [files and parameters], it is a FileInput. If the request has [texts and parameters], it is a TextInput. It is not allowed to provide both text and file within the same request.
I used the union property. See CatAndDog example in
Raml 200 documentation for a small example.
You can define your types as follows.
types:
FileInput:
properties:
parameters:
type: Parameters
description: (...)
files:
type: ArchiveCollection | FileCollection
description: (...)
TextInput:
properties:
parameters:
type: Parameters
description: (...)
texts:
type: TextCollection
description: (...)
Then in my POST request body:
/your_route:
post:
body:
multipart/form-data:
type: TextInput | FileInput
The fields in the body are defined with either TextInput or FileInput type.
In RAML 0.8 you can not describe queryParameters with only one parameter.
In RAML 1.0 you can do this. You should use oneOf in jsonschema for describing Type. Your queryParameters should use this type. Example:
api.raml
#%RAML 1.0
title: AUTH microservice
mediaType: application/json
protocols: [HTTPS]
types:
- example: !include schemas/example.json
/example:
get:
queryParameters:
type: example
schemas/example.json
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"id": "file://schemas/credentials.json",
"oneOf": [
{
"properties": {"key1": {"type": "string"}},
"additionalProperties": false
},
{
"properties": {"key2": {"type": "string"}},
"additionalProperties": false
}
]
}
Also you can use uriParameters. Maybe it will help in your case.
#%RAML 0.8
title: API Using media type in the URL
version: v1
/users{mediaTypeExtension}:
uriParameters:
mediaTypeExtension:
enum: [ .json, .xml ]
description: Use .json to specify application/json or .xml to specify text/xml