Make apache avro schema of a simple API - data-modeling

I want to make schema of a simple API in Apache Avro, but issue is that my API has header field "Content-Type", and Avro disallows "-" in name.
Here is my JSON:
"headers": {"Content-Type": "application/x-www-form-urlencoded"}
Here is schema sample:
{
"name": "headers",
"type": {
"type": "record",
"name": "headers",
"fields": [
{ "name": "Content-type", "type": ["string", "null"] }
]
}
},

Represent the headers using an Avro map instead of record:
{
"name": "headers",
"type": {
"type": "map",
"values": "string"
}
},

Related

Custom policy does not maintain previous values on properties array

I am creating a custom policy following this documentation.
I created one, and it is working. The JSON schema for the policy is shown below:
{
"title": "ACME Custom Basic Auth Policy",
"description": "Basic Authentication policy which enforces security according with custom consumer credentials",
"type": "object",
"properties": {
"users": {
"title": "users",
"type": "array",
"items": {
"type": "object",
"required": [
"username",
"password"
],
"properties": {
"username": {
"title": "User Name",
"type": "string",
"default": []
},
"password": {
"title": "User Password",
"type": "string",
"#context": {
"#characteristics": [
"security:sensitive"
]
}
}
}
},
"minItems": 1
}
},
"#context": {
"#vocab": "anypoint://vocabulary/policy.yaml#",
"security": "anypoint://vocabulary/policy.yaml#"
},
"$id": "allow-dynamic-resources",
"$schema": "https://json-schema.org/draft/2019-09/schema"
}
When I go to API Manager, I can configure the values on first attempt, but when I go back to change the values, they do not appear.
This happens only when I configure an array. If I configure as an object, it works. How can I fix this?

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.

How to avoid loading attachments data from Gmail Rest API get message

How to avoid loading attachments data from Gmail Rest API with get message request.
Using the fields parameter at least we can avoid loading few fields but when I want to load message body, attachment data also coming along with body just like IMAP
You don't get the attachment like you do in IMAP. You get an attachmentId which you have to use in an additional request to get the attachment.
I just sent a message with an attached image to myself. This is what the response from the API looks like:
{
"id": "1573ec1aa0976b42",
"threadId": "1573ec1aa0976b42",
"labelIds": [
"SENT",
"INBOX",
"IMPORTANT",
"UNREAD"
],
"snippet": "",
"historyId": "939514",
"internalDate": "1474226662000",
"payload": {
"mimeType": "multipart/related",
"filename": "",
"headers": [ ... ],
"body": {
"size": 0
},
"parts": [
{
"mimeType": "multipart/alternative",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "multipart/alternative; boundary=94eb2c0d3cba8637a2053ccd2461"
}
],
"body": {
"size": 0
},
"parts": [
{ ... },
{
"partId": "1",
"mimeType": "image/png",
"filename": "Screen Shot",
"headers": [ ... ],
"body": {
"attachmentId": "ANGjdJ-bmCvsIaV-4KfALXzVV_D567w4i6ksLnwIZhLAl3VXCE335663UbmOLC_vbLrCFusNtnWVpdTv3i88uR482kFwLZqAcwmI7C5gFlamob2aK4-lqAPlCZs17jtCQR9y5Mt4nnpP_Kg64N9qgXbDF0E2vYnEw4xwtEKEo4fRIAbc94ZjjfynFD832mh1B37XFMt-bYw9wkNv24xBife0koBNYpKs-gGLJkfu2EoZouqunGDX9ry1jq2jW2AClWcFXPXvgRBMjUcoRDPtvb9LLLrBhDjU1hu6r1Ibc3c2BSoBogT8QyIp2VUCuFU",
"size": 1511996
}
}
]
},
"sizeEstimate": 1513185
}
As you can see, it just contains an attachmentId and no actual attachment data.

Why is attachmentId missing in payload/parts/body from certain emails?

I'm using the gmail API to first generate a list of all attachments, and then download the attachments on demand.
I'm basically calling GET https://www.googleapis.com/gmail/v1/users/me/messages/{ID}?key={YOUR_API_KEY} on all message ids that have an attachment, and then grabbing all the attachmentIds to use with the messages.attachments API later. This works for the majority of my attachments, but I notice for certain emails, the attachment ID is missing.
Heres an example response (with certain parts omitted) from such one of those emails:
{
"id": "114fda8b3fe57cb1",
"threadId": "114fda8b3fe57cb1",
"labelIds": [
"INBOX"
],
"snippet": "",
"historyId": "1027074",
"payload": {
"mimeType": "multipart/mixed",
"filename": "",
"headers": [
],
"body": {
"size": 0
},
"parts": [
{
},
{
"partId": "1",
"mimeType": "image/jpeg",
"filename": "IMG_3746.JPG",
"headers": [
{
"name": "Content-Type",
"value": "image/jpeg; name=\"IMG_3746.JPG\""
},
{
"name": "Content-Transfer-Encoding",
"value": "base64"
},
{
"name": "Content-Disposition",
"value": "attachment; filename=\"IMG_3746.JPG\""
},
{
"name": "X-Attachment-Id",
"value": "f_1ydodxn"
}
],
"body": {
"size": 447292 <------ Here is where I would expect attachmentId to be...
}
},
{
}
]
},
"sizeEstimate": 2873869
}
Here's what the parts/body looks like from a response from a message that has everything I expected:
"body": {
"attachmentId": "ANGjdJ9CRk8VcuxPzOMnGhFQdJpB6vc7xNAZTw5Gav3jZRQkEi3lRvELnjUTEqQtpiJDkKx8IR3qEOyT0wW6LD_tQ3NvPWDucURPaW0xUBJm8gwP-De9hOt7DbciRdfYCX79JWoHtGS2cooTzpAfZwYXc2lmcjCeL_SvgCZAtIEOVs45atTOsx9BCb02aJzNAvga2f3OdsBNbUkCyyZWQZGB0bHQf4q30BmoDFLrBhq67k3f5VOpOxsFl4QDLS5Md-JxhbQ1qsFk_usEUvcOqFsNgckmtj6y0zrKyDDc8g",
"size": 536
}
I can't use GET messages/attachments without the attachmentId... whats going on? What am I missing?
Looks like that was an issue with some older attachments. Should be resolved now.
In my case (using API in Python) the attachmentId was never in the body.
I went here:
https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get
to use "Try this method" window
and I found the attachmentId in parts[1].body

Resources