Power automate - Custom connector - Webhook trigger with dynamic schema properties - azure-logic-apps

I'm trying to create a webhook trigger in Power Automate via the OpenApi spec.
The webhook url must be in the body and it's required, but I also want to have dynamic properties in the body aswell. So far I have this:
"/webhook/triggers/{entityType}": {
"x-ms-notification-content": {
"description": "When a operation is performed on a entity",
"x-ms-summary": "When a operation is performed on a entity",
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"x-ms-dynamic-schema": {
"operationId": "GetDynamicSchema",
"parameters": {
"entityType": {
"parameter": "entityType"
}
}
}
},
"id": {
"type": "string"
},
"source": {
"type": "string"
},
"type": {
"type": "string"
},
"time": {
"format": "date-time",
"type": "string"
},
"dataSchema": {
"type": "string"
},
"dataContentType": {
"type": "string"
},
"extensionAttributes": {
"type": "object",
"additionalProperties": {
"type": "object"
}
}
}
}
},
"post": {
"description": "When a operation is performed on a entity",
"x-ms-trigger": "single",
"x-ms-visibility": "important",
"summary": "When a operation is performed on a entity",
"operationId": "RegisterTriggerWithEntity",
"consumes": ["application/json"],
"produces": ["application/json"],
"parameters": [
{
"name": "entityType",
"x-ms-summary": "Entity",
"description": "The entity",
"x-ms-url-encoding": "single",
"in": "path",
"required": true,
"type": "string",
"x-ms-dynamic-values": {
"operationId": "GetEntityTypes",
"value-path": "name",
"value-title": "description"
}
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"type": "object",
"properties": {
"webhookUrl": {
"type": "string",
"x-ms-notification-url": true,
"x-ms-visibility": "internal"
},
"data": {
"type": "object",
"x-ms-dynamic-schema": {
"operationId": "GetSchema",
"parameters": {
"entityType": {
"parameter": "entityType"
}
}
},
"x-ms-dynamic-properties": {
"operationId": "GetSchema",
"parameters": {
"entityType": {
"parameterReference": "entityType"
}
}
}
}
},
"required": [
"webhookUrl"
],
"x-ms-visibility": "important"
}
}
],
"responses": {
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
}
}
Which passes validation, I also have the schema properties prompted in the UI ready to be provided by the user, but on saving the flow, I get the following OpenApiOperationParameterValidationFailed:
Flow save failed with code 'OpenApiOperationParameterValidationFailed' and message 'Input parameter 'body' validation failed in workflow operation 'When_a_operation_is_performed_on_a_entity': The API operation 'RegisterTriggerWithEntity' requires the property 'body/data' to be set to one of its defined enum values '[]' but is set to '{ "firstProperty": "testValue" }'.'.
What might be the problem with this flow? What is the suggested way of having a webhook trigger with dynamic schema properties?

Related

How to validate dynamic API response (Schema validation) in Postman

Hello there I have a API that sends dynamic responses and I want to validate the schema of that response.following is the response I am trying to validate.
{
"Data": [
{
"CustomerName": "BeautyProductions",
"Websites": {
"storeone": {
"Keyone":"testvalueone",
"Keytwo":"testvalue two"
}
}
}
]
}
But the thing is the number of websites increases sometimes like following
{
"Data": [
{
"CustomerName": "BeautyProductions",
"Websites": {
"storeone": {
"Keyone":"testvalueone",
"Keytwo":"testvalue two"
},
"storetwo": {
"Keyone":"testvaluestoretwo",
"Keytwo":"testvaluestoretwonow"
}
}
}
]
}
I tried to validate schema as following
var schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Data": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"CustomerName": {
"type": "string"
},
"Websites": {
"type": "object",
"properties": {
"storeone": {
"type": "object",
"properties": {
"Keyone": {
"type": "string"
},
"Keytwo": {
"type": "string"
}
},
"required": [
"Keyone",
"Keytwo"
]
}
},
"required": [
"storeone"
]
}
},
"required": [
"CustomerName",
"Websites"
]
}
]
}
},
"required": [
"Data"
]
}
var json = pm.response.json()
pm.test('shcema is valid', function(){
pm.expect(tv4.validate(json, schema)).to.be.true;
})
But it fails when the number of website count is increasing. SO, I would liketo know how I can validate this?
Thankyou
I don't know if the "stored" field is required, but you can use the "additionalProperties". The "additionalProperties" field allows you to specify a schema for properties in the object that are not explicitly defined in the properties field.
Please try below schema if it works:
var schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Data": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"CustomerName": {
"type": "string"
},
"Websites": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"Keyone": {
"type": "string"
},
"Keytwo": {
"type": "string"
}
},
"required": [
"Keyone",
"Keytwo"
]
}
}
},
"required": [
"CustomerName",
"Websites"
]
}
]
}
},
"required": [
"Data"
]
}

Mock service worker with openApi backend

I am working with MSW and OpenAPI-backend package.
I want to mock the booth browser server and test server.
I have OpenAPI definition available form with I generate generated.ts for RTK Query (out of scope for this question). I want to use OpenAPI spec to use it with OpenAPI Backend and generate MSW rest worker for browser and for test.
Setup is next:
index.tsx
import worker from './mocks/browser';
if (process.env.NODE_ENV === 'development') {
worker.start();
}
mock/browser.ts
import { setupWorker, rest } from 'msw';
import { OpenAPIBackend } from 'openapi-backend';
import type { Document } from 'openapi-backend';
import definition from './api.json';
// create our mock backend with openapi-backend
const api = new OpenAPIBackend({ definition: definition as Document });
api.register('notFound', (c, res, ctx) => res(ctx.status(404)));
api.registerHandler('notImplemented', async (c, req, res) => {
const { status, mock } = await api.mockResponseForOperation(
c.operation.operationId as string
);
return res.status(status).json(mock);
});
api.register('validationFail', (c, res, ctx) =>
res(ctx.status(400), ctx.json({ error: c.validation.errors }))
);
const worker = setupWorker(
rest.get('/*', (req) =>
api.handleRequest({
...req,
path: req.url.pathname,
headers: req.headers.all(),
method: req.method,
body: req.body,
})
)
);
export default worker;
api.JSON
{
"openapi": "3.0.1",
"info": {
"title": "Fetch API",
"description": "Source of truth for Fetch dashboard",
"version": "0.1.5"
},
"paths": {
"/config": {
"get": {
"tags": [
"Configuration"
],
"summary": "Retreive configuration object",
"description": "Returns configuration object (map) containing configuration parameters for UI (Map<String, String>)",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Map serialized to json object.",
"example": {
"FA_COLOR": "red",
"FA_NAME": "fetch"
}
}
}
}
}
}
}
},
"/links": {
"get": {
"tags": [
"Notifications & Links",
"Walking Skeleton"
],
"summary": "List all defined links for hospital",
"description": "Retreives all defined links for hospital. Hospital ID is indirectly obtained from user identity.",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
}
}
}
}
},
"/kpis": {
"get": {
"tags": [
"KPIS"
],
"summary": "List all KPIs for hospital(s) that current user is managing.",
"description": "Retreives all KPIs available for hospitals that current user is managing.",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/KPI"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"KPI": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"revenue",
"labour"
]
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this KPI describes"
},
"goal": {
"type": "number",
"description": "full month goal"
},
"actual": {
"type": "number",
"description": "actual result"
},
"mtd_goal": {
"type": "number",
"description": "month to date goal, so that we can track projected fulfillment of goal."
},
"details": {
"type": "object",
"description": "Semi-structured way of describing details of calculation. Every KPI will potentialiy be described differently."
}
},
"required": [
"id",
"hospital_id",
"goal",
"actual",
"mtd_goal"
]
},
"Link": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "unique id of link"
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this Link is configured for"
},
"title": {
"type": "string",
"description": "human readable title for URL"
},
"description": {
"type": "string",
"description": "Description of current link (alt text , or tooltip)"
},
"url": {
"type": "string",
"description": "Location of external resource"
},
"urgent": {
"type": "boolean",
"description": "Is urgency of notification elevated?"
},
"count": {
"type": "number",
"description": "Actual notification value. How many 'tasks' are waiting manager in external system."
},
"updated_at": {
"type": "integer",
"description": "Date/time of last notification update",
"format": "int64"
},
"children": {
"type": "array",
"description": "Since notifications are possibly presented in hierarchy all children of this notification will be gathered here",
"items": {
"$ref": "#/components/schemas/Link"
}
}
},
"required": [
"id",
"hospital_id",
"title",
"url"
],
"example": [
{
"id": 1,
"hospital_id": "001",
"title": "Link1",
"description": "description of Link1",
"url": "https://www.example.com/link1",
"urgent": true,
"count": 1,
"updated_at": 1631113184221,
"children": [
{
"id": 2,
"hospital_id": "001",
"title": "Link2",
"description": "description of Link2",
"url": "https://www.example.com/link2",
"urgent": true,
"count": 1,
"updated_at": 1631113184221
}
]
},
{
"id": 3,
"hospital_id": "002",
"title": "Link3",
"description": "description of Link3",
"url": "https://www.example.com/link3",
"urgent": false,
"count": 2,
"updated_at": 1631113184221
}
]
}
}
}
}
component.tsx
const { data: links, error, isLoading } = useGetLinksQuery({});
Which is fethcing localhost:3000/links
Error I am getting is:
mockServiceWorker.js:222 [MSW] Uncaught exception in the request handler for "GET http://localhost:3000/links":
Error: Unknown operation
at OpenAPIValidator.validateRequest (http://localhost:3000/static/js/vendors~main.chunk.js:63911:13)
at OpenAPIBackend.<anonymous> (http://localhost:3000/static/js/vendors~main.chunk.js:54246:45)
at async OpenAPIBackend.handleRequest (http://localhost:3000/static/js/vendors~main.chunk.js:54152:22)
This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses
getResponse # mockServiceWorker.js:222
async function (async)
getResponse # mockServiceWorker.js:175
handleRequest # mockServiceWorker.js:113
async function (async)
handleRequest # mockServiceWorker.js:112
(anonymous) # mockServiceWorker.js:271
Network tabs give:
Request URL: http://localhost:3000/links
Request Method: GET
Status Code: 500 (from service worker)
Referrer Policy: strict-origin-when-cross-origin
All related to article: https://dev.to/epilot/testing-react-with-jest-and-openapi-mocks-8gc
and https://testing-library.com/docs/react-testing-library/example-intro/
Thank you.
In your OpenApi u don't have any operationId.
You need to setup a unique Id by route.
{
"openapi": "3.0.1",
"info": {
"title": "Fetch API",
"description": "Source of truth for Fetch dashboard",
"version": "0.1.5"
},
"paths": {
"/config": {
"get": {
"tags": [
"Configuration"
],
"operationId": "config",
"summary": "Retreive configuration object",
"description": "Returns configuration object (map) containing configuration parameters for UI (Map<String, String>)",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Map serialized to json object.",
"example": {
"FA_COLOR": "red",
"FA_NAME": "fetch"
}
}
}
}
}
}
}
},
"/links": {
"get": {
"tags": [
"Notifications & Links",
"Walking Skeleton"
],
"operationId": "links",
"summary": "List all defined links for hospital",
"description": "Retreives all defined links for hospital. Hospital ID is indirectly obtained from user identity.",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
}
}
}
}
},
"/kpis": {
"get": {
"tags": [
"KPIS"
],
"summary": "List all KPIs for hospital(s) that current user is managing.",
"description": "Retreives all KPIs available for hospitals that current user is managing.",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/KPI"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"KPI": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"revenue",
"labour"
]
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this KPI describes"
},
"goal": {
"type": "number",
"description": "full month goal"
},
"actual": {
"type": "number",
"description": "actual result"
},
"mtd_goal": {
"type": "number",
"description": "month to date goal, so that we can track projected fulfillment of goal."
},
"details": {
"type": "object",
"description": "Semi-structured way of describing details of calculation. Every KPI will potentialiy be described differently."
}
},
"required": [
"id",
"hospital_id",
"goal",
"actual",
"mtd_goal"
]
},
"Link": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "unique id of link"
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this Link is configured for"
},
"title": {
"type": "string",
"description": "human readable title for URL"
},
"description": {
"type": "string",
"description": "Description of current link (alt text , or tooltip)"
},
"url": {
"type": "string",
"description": "Location of external resource"
},
"urgent": {
"type": "boolean",
"description": "Is urgency of notification elevated?"
},
"count": {
"type": "number",
"description": "Actual notification value. How many 'tasks' are waiting manager in external system."
},
"updated_at": {
"type": "integer",
"description": "Date/time of last notification update",
"format": "int64"
},
"children": {
"type": "array",
"description": "Since notifications are possibly presented in hierarchy all children of this notification will be gathered here",
"items": {
"$ref": "#/components/schemas/Link"
}
}
},
"required": [
"id",
"hospital_id",
"title",
"url"
],
"example": [
{
"id": 1,
"hospital_id": "001",
"title": "Link1",
"description": "description of Link1",
"url": "https://www.example.com/link1",
"urgent": true,
"count": 1,
"updated_at": 1631113184221,
"children": [
{
"id": 2,
"hospital_id": "001",
"title": "Link2",
"description": "description of Link2",
"url": "https://www.example.com/link2",
"urgent": true,
"count": 1,
"updated_at": 1631113184221
}
]
},
{
"id": 3,
"hospital_id": "002",
"title": "Link3",
"description": "description of Link3",
"url": "https://www.example.com/link3",
"urgent": false,
"count": 2,
"updated_at": 1631113184221
}
]
}
}
}
}

Azure Logic App Partition key [X] is invalid with COsmos Db

I need to save JSON parsed data to Cosmos Db, HTTP trigger works as it should as well as parsing but getting Partition key [my_dynamic_key_value] is invalid.
Did anyone have a similar issue?
I have found this article link but still getting the same error.
Thanks
EDIT 1
This is the flow for adding item to DB
Schema:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"Groups": {
"type": "array",
"items": {
"type": "string"
}
},
"JobName": {
"type": "string"
},
"Link": {
"type": "string"
},
"MinSalary": {
"type": "string"
},
"MaxSalary": {
"type": "string"
},
"Hours": {
"type": "string"
},
"WorkPattern": {
"type": "string"
},
"Details": {
"type": "array",
"items": {
"type": "object",
"properties": {
"Name": {
"type": "string"
},
"Detail": {
"type": "string"
}
},
"required": [
"Name",
"Detail"
]
}
}
},
"required": [
"id",
"Groups",
"JobName",
"Link",
"MinSalary",
"MaxSalary",
"Hours",
"WorkPattern",
"Details"
]
}
}
Here is a response:
{
"code": "BadRequest",
"message": "Partition key [1bb2d44f-a066-4fa8-8a78-0cdcea1a756c] is invalid.\r\nActivityId: 345f9a99-534b-40cb-9dc0-9863dc8c90f5, \r\nRequestStartTime: 2020-04-28T08:04:46.8249255Z, RequestEndTime: 2020-04-28T08:04:46.8249255Z, Number of regions attempted:1\r\n, Microsoft.Azure.Documents.Common/2.10.0"
}
You need to set the partition key in the double quotes. Refer to sample screen shot below

Microsoft Flow Custom Connector webhook trigger definition and implementation : 404 not found after flow creation

I'm trying to create a custom connector for my API in Microsoft Flow so users can trigger flows based on a webhook implementation.
The authentication part seems to be working properly (I'm able to create connections). After creating a flow using my custom trigger, it never gets triggered. When checking the data on my end it seems that Flow was never able to register the subscription properly.
If I navigate to the management page for the flow, I get the following error message.
When I click on fix the trigger I get the following details where the Id parameter matches the id of the resource we're trying to subscribe to.
Here is the trigger definition:
{
"/AlertRules/{id}/webhooks": {
"x-ms-notification-content": {
"schema": {
"type": "object",
"properties": {
"Title": {
"type": "string",
"description": "Title"
},
"Text": {
"type": "string",
"description": "Text"
},
"Data": {
"type": "array",
"items": {
"$ref": "#/definitions/DataApi.Models.AlertEvent"
},
"description": "Data"
}
}
},
"description": ""
},
"post": {
"responses": {
"201": {
"description": "Created",
"schema": {
"type": "string"
}
}
},
"x-ms-trigger": "single",
"operationId": "NewAlertEvent",
"summary": "When a new Alert Event is created or updated",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string",
"x-ms-visibility": "important",
"x-ms-dynamic-values": {
"operationId": "AlertRules.AlertRule.ListAlertRule",
"value-path": "Id",
"value-collection": "value",
"value-title": "Description"
}
},
{
"name": "body",
"in": "body",
"required": false,
"schema": {
"type": "string",
"x-ms-visibility": "internal",
"title": "",
"x-ms-notification-url": true
},
"x-ms-visibility": "internal"
}
]
}
}
The description of my delete operation
{
"/AlertRuleSubscriptions({Id})": {
"delete": {
"tags": [
"AlertRuleSubscriptions.AlertRuleSubscription"
],
"summary": "Delete entity from AlertRuleSubscriptions",
"operationId": "AlertRuleSubscriptions.AlertRuleSubscription.DeleteAlertRuleSubscription",
"parameters": [
{
"in": "path",
"name": "Id",
"description": "key: Id",
"required": true,
"type": "string",
"format": "uuid",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
"x-ms-docs-key-type": "AlertRuleSubscription"
},
{
"in": "header",
"name": "If-Match",
"description": "ETag",
"type": "string"
}
],
"responses": {
"204": {
"description": "Success"
},
"default": {
"$ref": "#/responses/error"
}
},
"x-ms-docs-operation-type": "operation"
}
}
}
And my post operation does reply with a Location header which matches the format of the delete operation described above.
My questions are:
What is missing in my trigger declaration?
How can I get more details on the subscription creation and the error Microsoft Flow is generating?
After some internal discussions with Microsoft we found two main issues.
First I updated the body parameter of the POST request to create the subscription to this.
{
"name": "body",
"in": "body",
"required": false,
"schema": {
"type": "object",
"properties": {
"callbackUrl": {
"type": "string",
"required": true,
"description": "callbackUrl",
"x-ms-notification-url": true,
"x-ms-visibility": "internal"
}
}
}
}
That is because the connector definitions don't support sending the callback URL in the body without using JSON formatting and because Flow was implemented using the Open API callback specification.
Second I updated my API to support the specification mentioned above.

Send workflow information to custom connector

I need help with sending workflow information in header/body of calls to custom connector. I am trying to load a drop down list in one of the parameters of a logic app using values returned from an API call. The API end point requires basic workflow information such as the resource group and workflow name which are normally available in headers of http requests from logic app execution.
Normally when I use #{workflow().name} in logic app's json, it is substituted with the workflow name. In case of custom connector, the WDL syntax is passed as is without any transformation.
Here is a simplified swagger json with all relevant sections.
{
"swagger": "2.0",
"info": {
"title": "{{dynamicHostName}}",
"version": "1.0.0"
},
"host": "{{dynamicHostName}}",
"basePath": "/",
"schemes": [
"https"
],
"paths": {
"/sftpsource": {
"post": {
"operationId": "SftpSource",
"summary": "Sftp as source system",
"description": "Use Sftp as source system",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"parameters": [
{
"name": "params",
"in": "body",
"required": true,
"schema": {
"type": "object",
"properties": {
"hostName": {
"type": "string",
"x-ms-summary": "Host Name",
"x-ms-visibility": "advanced"
},
"portNumber": {
"type": "string",
"x-ms-summary": "Port Number",
"x-ms-visibility": "advanced"
},
"userName": {
"type": "string",
"x-ms-summary": "User Name",
"x-ms-visibility": "advanced"
},
"password": {
"type": "string",
"x-ms-summary": "Password",
"x-ms-visibility": "advanced"
},
"filePath": {
"type": "string",
"x-ms-summary": "File Path"
},
"system": {
"type": "string",
"x-ms-visibility": "advanced",
"x-ms-summary": "System",
"x-ms-dynamic-values": {
"operationId": "GetTaggedSystems",
"parameters": {
"workflow-name": "#{workflow().name}"
},
"value-path": "systemId",
"value-title": "systemName"
}
}
}
}
}
],
"responses": {
"202": {
"description": "Request is queued"
},
"500": {
"description": "Server Error"
}
}
}
},
"/taggedSystems" : {
"get": {
"operationId": "GetTaggedSystems",
"summary": "Tagged Systems",
"x-ms-visibility": "advanced",
"description": "Get all systems tagged to this flow",
"parameters": [
{
"name": "workflow-name",
"in": "header",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/TaggedSystems"
}
},
"202": {
"description": "Work is still in progress"
},
"500": {
"description": "An error occured while trying to fetch tagged systems."
}
}
}
}
},
"definitions": {
"TaggedSystems": {
"type": "array",
"items": {
"type": "object",
"properties": {
"systemId": {
"type": "string"
},
"systemName": {
"type": "string"
}
},
"required": [
"systemId",
"systemName"
]
}
}
}
}
You can have an internal parameter defined as header/body where you can pass dynamic expressions of what you need from the workflow environment at the time of execution of the flow.
For complete information regarding the flow, you can pass #{workflow()} as an internal parameter.
Hope it helps.

Resources