How to use APIKit router to use local raml and json file to show appropriate GET response in Postman? - anypoint-studio

I have created RAML and example JSON file inside Anypoint platform and have generated flow using RAML file that is the APIKit router. Here is my RAML file content:
#%RAML 0.8
---
title: TestEmployee API
version: v1
/employee:
get:
queryParameters:
id:
displayName: Employee id
required: true
name:
displayName: Employee name
required: false
responses:
200:
body:
application/json:
example: !include EmployeeExample.json
And example JSON is:
[{
"id": 1,
"name":"Charles",
"code": "C1ENU00",
"dateofjoining":"2019/06/24",
"domain":"ENU",
"address":"Hyderabad",
"phone": 9865458936,
"program": "WASE"
},
{
"id": 2,
"name":"John",
"code": "C2DIG00",
"dateofjoining":"2019/06/24",
"domain":"DIGITAL",
"address":"Chennai",
"phone": 9756359864,
"program": "ELITE"
}
]
I want to use a Choice router to route messages according to the condition so that 'id' and 'name' from query parameters would give JSON responses containing that 'id' and 'name' only. Please guide me in creating appropriate flows and Dataweave expressions if any.

You don't need a choice router just for that. APIKit is a router itself, which routes according to the method and endpoint from the URL. When you scaffold the flows using the RAML it creates a dummy flow for the GET employee endpoint. You just need to replace the contents of that flow with the logic to query the information from some where, probably using a connector.
Example:
The autogenerated flow by Studio will have a name like "get:\employee:application\json:myApp". You can replace the default content by a DataWeave transformation to return the list specified:
<flow name="get:\employee:application\json:myApp">
<ee:transform xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
[
{
id: 1,
name:"Charles",
code: "C1ENU00",
dateofjoining:"2019/06/24",
domain:"ENU",
address:"Hyderabad",
phone: 9865458936,
program: "WASE"
},
{
id: 2,
name:"John",
code: "C2DIG00",
dateofjoining:"2019/06/24",
domain:"DIGITAL",
address:"Chennai",
phone: 9756359864,
program: "ELITE"
}
]
]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>

Related

Where is id: { type: 'ID' } generated in in the featherjs models created by feathers-plus cli defined in the official jsonschema?

I have looked at the json schema docs and examples and do not see a type of ID as created in the json models by the generator. Example feathers-plus cli jsonschema
properties: {
// !code: schema_properties
id: { type: 'ID' },
email: {},
In the jsonschema official docs example id is defined like
"properties": {
"id": {
"type": ["string", "integer"],
This is not allowed by JSON Schema.
According to the docs at https://github.com/feathers-plus/generator-feathers-plus/tree/master/docs/json-schema
Feathers Models are based on JSON-schema.
This reads to me that their models are not quite JSON Schema.
If you want to know why, you should probably raise an issue on their github repo.

AWS Api Gateway proxy resource using Cloudformation?

I'm trying to proxy an S3 bucket configured as a website from an API Gateway endpoint. I configured an endpoint successfully using the console, but I am unable to recreate the configuration using Cloudformation.
After lots of trial and error and guessing, I've come up with the following CF stack template that gets me pretty close:
Resources:
Api:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: ApiDocs
Resource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
PathPart: '{proxy+}'
RootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !GetAtt Api.RootResourceId
RestApiId: !Ref Api
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: ANY
Type: HTTP_PROXY
Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/'
PassthroughBehavior: WHEN_NO_MATCH
IntegrationResponses:
- StatusCode: 200
ProxyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: ANY
ResourceId: !Ref Resource
RestApiId: !Ref Api
AuthorizationType: NONE
RequestParameters:
method.request.path.proxy: true
Integration:
CacheKeyParameters:
- 'method.request.path.proxy'
RequestParameters:
integration.request.path.proxy: 'method.request.path.proxy'
IntegrationHttpMethod: ANY
Type: HTTP_PROXY
Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/{proxy}'
PassthroughBehavior: WHEN_NO_MATCH
IntegrationResponses:
- StatusCode: 200
Deployment:
DependsOn:
- RootMethod
- ProxyMethod
Type: 'AWS::ApiGateway::Deployment'
Properties:
RestApiId: !Ref Api
StageName: dev
Using this template I can successfully get the root of the bucket website, but the proxy resource gives me a 500:
curl -i https://abcdef.execute-api.eu-west-1.amazonaws.com/dev/index.html
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 36
Connection: keep-alive
Date: Mon, 11 Dec 2017 16:36:02 GMT
x-amzn-RequestId: 6014a809-de91-11e7-95e4-dda6e24d156a
X-Cache: Error from cloudfront
Via: 1.1 8f6f9aba914cc74bcbbf3c57e10df26a.cloudfront.net (CloudFront)
X-Amz-Cf-Id: TlOCX3eemHfY0aiVk9MLCp4qFzUEn5I0QUTIPkh14o6-nh7YAfUn5Q==
{"message": "Internal server error"}
I have no idea how to debug that 500.
To track down what may be wrong, I've compared the output of aws apigateway get-resource on the resource I created manually in the console (which is working) with the one Cloudformation made (which isn't). The resources look exactly alike. The output of get-method however, is subtly different, and I'm not sure it's possible to make them exactly the same using Cloudformation.
Working method configuration:
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"methodIntegration": {
"integrationResponses": {
"200": {
"responseTemplates": {
"application/json": null
},
"statusCode": "200"
}
},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [
"method.request.path.proxy"
],
"requestParameters": {
"integration.request.path.proxy": "method.request.path.proxy"
},
"uri": "http://muybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
"httpMethod": "ANY",
"cacheNamespace": "abcdefg",
"type": "HTTP_PROXY"
},
"requestParameters": {
"method.request.path.proxy": true
},
"authorizationType": "NONE"
}
Configuration that doesn't work:
{
"apiKeyRequired": false,
"httpMethod": "ANY",
"methodIntegration": {
"integrationResponses": {
"200": {
"responseParameters": {},
"responseTemplates": {},
"statusCode": "200"
}
},
"passthroughBehavior": "WHEN_NO_MATCH",
"cacheKeyParameters": [
"method.request.path.proxy"
],
"requestParameters": {
"integration.request.path.proxy": "method.request.path.proxy"
},
"uri": "http://mybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
"httpMethod": "ANY",
"requestTemplates": {},
"cacheNamespace": "abcdef",
"type": "HTTP_PROXY"
},
"requestParameters": {
"method.request.path.proxy": true
},
"requestModels": {},
"authorizationType": "NONE"
}
The differences:
The working configuration has responseTemplates set to "application/json": null. As far as I can tell, there's no way to set a mapping explicitly to null using Cloudformation. My CF method instead just has an empty object here.
My CF method has "responseParameters": {},, while the working configuration does not have responseParameters at all
My CF method has "requestModels": {},, while the working configuration does not have requestModels at all
Comparing the two in the console, they are seemingly exactly the same.
I'm at my wits end here: what am I doing wrong? Is this possible to achieve using Cloudformation?
Answer: The above is correct. I had arrived at this solution through a series of steps, and re-applied the template over and over. Deleting the stack and deploying it anew with this configuration had the desired effect.

How to use 'Ignore or Validate' in JSON file (karate framework)?

I have to verify that each response is in correct format. I've put in my feature:
And match each response contains { id: '#string', name: '#string', phone: '#number' etc..}
But I would like to put this in a JSON file, beacuse I need it several times in different features.
When I use 'Ignore or Validate' tags in JSON file, it doesn't work. Is it possible to do this?
Yes why not. First place the following in a file called item-schema.json.
{ "id": "#string", "name": "#string", "phone": "#number" }
Now all you need to do is:
And match each response contains read('item-schema.json')
Please go through the documentation of Reading Files carefully.

Using $ref for jsonschema in Abao

Can someone help with schemas refs in abao? How to use --schemas option? Here is simple gist https://gist.github.com/SeanSilke/e5a2f7673ad4aa2aa43ba800c9aec31b
I try to run "abao api.raml --schemas fref.json" but got error " Missing/unresolved JSON schema $refs (fref.json) in schema".
By the way the server is mocked by osprey-mock-service.
You need add id field to your JSON schemas.
For run use: abao api.raml --server http://localhost:3000 --schemas=./*.json
Example files:
api.raml
#%RAML 0.8
title: simple API
baseUri: http://localhost:3000
/song:
get:
responses:
200:
body:
application/json:
schema: !include schema.json
example: |
{
"songId": "e29b",
"songTitle": "The song",
"albumId": "18310"
}
fref.json
{
"id": "fref.json",
"type": "string"
}
schema.json
{
"$schema": "http://json-schema.org/draft-03/schema",
"id": "schema.json",
"type": "object",
"properties":{
"songId": {"$ref": "fref.json"}
},
"required": ["songId", "albumId", "songTitle"]
}

splitting swagger definition across many files

Question: how can I split swagger definition across files? What are the possibilities in that area? The question details are described below:
example of what I want - in RAML
I do have experience in RAML and what I do is, for example:
/settings:
description: |
This resource defines application & components configuration
get:
is: [ includingCustomHeaders ]
description: |
Fetch entire configuration
responses:
200:
body:
example: !include samples/settings.json
schema: !include schemas/settings.json
The last two lines are important here - theones with !include <filepath> - in RAML I can split my entire contract into many files that just get included dynamically by the RAML parser (and RAML parser is used by all tools that base on RAML).
My benefit from this is that:
I get my contract more clear and easier to maintain, because schemas are not inline
but that's really important: I can reuse the schema files within other tools to do validation, mock generation, stubs, generate tests, etc. In other words, this way I can reuse schema files within both contract (RAML, this case) and other tools (non-RAML, non-swagger, just JSONschema-based ones).
back to Swagger
As far as I read, swagger supports $ref keyword which allows to load external files. But is that files fetched through HTTP/AJAX or can they just be local files?
And is that supported by the whole specification or is it just some tools that support it and some that don't?
What I found here is that the input for swagger has to be one file. And this is extremely inconvenient for big projects:
because of size
and because I can't reuse the schema if I want to use something non-swagger
Or, in other words, can I achieve the same with swagger, that I can with RAML - in terms of splitting files?
The specification allows for references in multiple locations but not everywhere. These references are resolved depending on where the specification is being hosted--and what you're trying to do.
For something like rendering a dynamic user interface, then yes you do need to eventually load the entire definition into "a single object" which may be composed from many files. If performing a code generation, the definitions may be loaded directly from the file system. But ultimately there are swagger parsers doing the resolution, which is much more fine grained and controllable in Swagger than other definition formats.
In your case, you would use a JSON pointer to the schema reference:
responses:
200:
description: the response
schema:
via local reference
$ref: '#/definitions/myModel'
via absolute reference:
$ref: 'http://path/to/your/resource'
via relative reference, which would be 'relative to where this doc is loaded'
$ref: 'resource.json#/myModel
via inline definition
type: object
properties:
id:
type: string
When I split OpenAPI V3 files using references, I try to avoid the sock drawer anti-pattern and instead use functional groupings for the YAML files.
I also make it so that each YAML file itself is a valid OpenAPI V3 spec.
I start out with the openapi.yaml file.
openapi: 3.0.3
info:
title: MyAPI
description: |
This is the public API for my stuff.
version: "3"
tags:
# NOTE: the name is needed as the info block uses `title` rather than name
- name: Authentication
$ref: 'authn.yaml#/info'
paths:
# NOTE: here are the references to the other OpenAPI files
# from the path. Note because OpenAPI requires paths to
# start with `/` and that is already used as a separator
# replace the `/` with `%2F` for the path reference.
'/authn/start':
$ref: 'authn.yaml#/paths/%2Fstart'
Then in the functional group:
openapi: 3.0.3
info:
title: Authentication
description: |
This is the authentication module.
version: "3"
paths:
# NOTE: don't include the `/authn` prefix here that top level grouping is
# in the `openapi.yaml` file.
'/start':
get:
responses:
"200":
description: OK
By doing this separation you can independently test each file or the whole API as a group.
There may be points where you repeat yourself, but by doing this you limit the chance of breaking changes to other API endpoints when using a "common" library.
However, you should still have a common definition library for some things such as:
errors
security
There is a limitation on this approach and that's the "Discriminators" (it may be a ReDoc issue though, but if you had types that have discriminators outside of the openapi.yaml ReDoc fails to render correctly.
See this answer for details on how to split your Swagger documentation across many files. This is done using JSON, but the same concept can apply to RAML.
EDIT: Adding content of link here
The basic structure of your Swagger JSON should look something like this:
{
"swagger": "2.0",
"info": {
"title": "",
"version": "version number here"
},
"basePath": "/",
"host": "host goes here",
"schemes": [
"http"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {}
}
The paths and definitions are where you need to insert the paths that your API supports and the model definitions describing your response objects. You can populate these objects dynamically. One way of doing this could be to have a separate file for each entity's paths and models.
Let's say one of the objects in your API is a "car".
Path:
{
"paths": {
"/cars": {
"get": {
"tags": [
"Car"
],
"summary": "Get all cars",
"description": "Returns all of the cars.",
"responses": {
"200": {
"description": "An array of cars",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/car"
}
}
},
"404": {
"description": "error fetching cars",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
}
}
Model:
{
"car": {
"properties": {
"_id": {
"type": "string",
"description": "car unique identifier"
},
"make": {
"type": "string",
"description": "Make of the car"
},
"model":{
"type": "string",
"description": "Model of the car."
}
}
}
}
You could then put each of these in their own files. When you start your server, you could grab these two JSON objects, and append them to the appropriate object in your base swagger object (either paths or definitions) and serve that base object as your Swagger JSON object.
You could also further optimize this by only doing the appending once when the server is started (since the API documentation will not change while the server is running). Then, when when the "serve Swagger docs" endpoint is hit, you can just return the cached Swagger JSON object that you created when the server was started.
The "serve Swagger docs" endpoint can be intercepted by catching a request to /api-docs like below:
app.get('/api-docs', function(req, res) {
// return the created Swagger JSON object here
});
You can use $ref but not have good flexibility, I suggest you process YAML with an external tool like 'Yamlinc' that mix multiple files into one using '$include' tag.
read more: https://github.com/javanile/yamlinc