API gateway body mapper nested objects - amazon-dynamodb

I have an endpoint setup on API gateway that is talking directly to DynamoDB.
As a post request comes in I use the body mapper script to map my url request parameters to dynamoDB params.
My URL params
{
"name": "sdaf",
"location": "asdf",
"gender": "male"
}
Body Mapper Script
{
"TableName": "sample-table",
"Item": {
"firstName": {
"S": "$input.path('$.name')"
},
"location": {
"S": "$input.path('$.location')"
}
}
}
All of this works fine until I have to write a whole object to dynamo.
New URL Params
{
"name": "sdaf",
"location": "asdf",
"gender": "male",
"hobbies": {
"hobby1": {
"startedAt": "<some time>"
},
"hobby2": {
"startedAt": "<some time>"
},
}
}
I am not sure how the body mapper is supposed to look like for this situation?
I have tried this:
Body Mapper
{
"TableName": "sample-table",
"Item": {
"firstName": {
"S": "$input.path('$.name')"
},
"location": {
"S": "$input.path('$.location')"
},
"hobbies": {
"M": "$input.path('$.hobbies')"
}
}
}
But doesn't work. I wonder if there is a way to dump an object into a column in dynamo from the api gateway directly. I know this is possible with adding a lambda in between but I want to avoid that.

I don't think this can be made to work while passing hobbies as a URL parameter.
If you instead pass hobbies in the body, you can do something like this:
"M": {
#foreach( $elem in $input.path('$.hobbies'))
$elem
#if($foreach.hasNext),#end
#end
}

Related

Put Azure Key Vault value in parameter array

I am trying to deploy a App service webapp via ARM template and need to put a secret from a key vault into an app setting (env variable).
I have always simply used an array of values from a parameters file to populate these app settings, but now I am struggling to get a keyvault value into that array. Something like shown below in an ARM parameter file.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"someStringParam": {
"value": "stringLiteralValueHere"
},
"envVars": {
"value": [
{
"name": "envVarKeyName",
"value": "stringLiteralValueHere"
},
{
"name": "KVsecret1",
"value": ##KEY VAULT SECRET HERE##
}
]
}
}
}
I have tried using a reference to the keyvault for the value but that errors on deployment.
{
"name": "KVsecret1",
"reference": {
"keyVault": {
"id": "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.KeyVault/vaults/<vault_name>"
},
"secretName": "secret1"
}
}
I have also tried using a parameter inside of the parameter file, but that just used the literal string for the value.
"parameters": {
"KVsecret1": {
"reference": {
"keyVault": {
"id": "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.KeyVault/vaults/<vault_name>"
},
"secretName": "KVsecret1"
}
},
"envVars": {
"value": [
{
"name": "envVarKeyName",
"value": "stringLiteralValueHere"
},
{
"name": "KVsecret1",
"value": "[parameters('KVsecret1')]"
}
]
}
}
Is this possible??
EDIT: Adding some detail here.
I am also trying to shoe horn a reference to another resource to get put the app insights instrumentation key into an app setting. Below is what I would like to do, but the copy function needs to use the name of the property and that is dynamic in this case as it changes with the each member of the array from the parameter file.
{
"type": "Microsoft.Web/sites/config",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('backEndwebAppName'),'/appsettings')]",
"kind": "string",
"properties": {
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(concat('microsoft.insights/components/',parameters('appInsightsName')),'2020-02-02').InstrumentationKey]",
"secret1FromKeyvault": "[parameters('secret1FromKeyvault')]",
"copy": [
{
"name": "envVarsFromParams",
"count": "[length(parameters('backEndEnvVariables'))]",
"input": {
"name": "[parameters('backEndEnvVariables')[copyIndex('envVarsFromParams').name]]",
"value": "[parameters('backEndEnvVariables')[copyIndex('envVarsFromParams').value]]"
}
}
]
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('backEndwebAppName'))]"
]
},
This isn't possible today within the param file, but in your scenario (if it's as simple as your OP example) you can just union the two in your template. So in your parameter file, you have 2 params kvSecret (the reference) and envVars (all your other env vars) and then in the template use:
"variables": {
"keySecretObj": {
"name": "kvSecret",
"value": "[parameters('kvSecret')]"
},
"envVarsFinal": "[union(parameters(variables('kvSecretObj`), parameters(`envVars`))]"
That help?

Is there a way to expand references in Swashbuckle to provide inline schemas?

Is there a mechanism in Swashbuckle that can prevent definitions from being created with referencing to them in parameters/responses/etc.?
By default, you might get a path that looks like this:
"/profile": {
"get": {
"summary": "Get my profile details.",
"produces": [
"application/json",
],
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/ProfileModel"
}
}
}
}
}
But what I'd like is for it to expand the schema inline like this:
"/profile": {
"get": {
"summary": "Get my profile details.",
"produces": [
"application/json",
],
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "id"
},
"firstName": {
"type": "string",
"description": "firstName"
},
"surname": {
"type": "string",
"description": "surname"
},
"emailAddress": {
"type": "string",
"description": "emailAddress"
}
}
}
}
}
}
}
I reviewed this StackOverflow question and I don't think it's what I'm looking for (or maybe misinterpreted).
Taken a look through the Swashbuckle README to understand its capabilities but coming up short. Any help here would be most appreciated.
For additional context, looking at the Swashbuckle PDF documentation in section 1.7, I essentially want to bypass or revert the action they describe as
automatically generating a corresponding schema for user-defined reference types and reference the definition via the $ref keyword.
Digging into the codebase a little, it looks like it's not possible at the moment.
However, you can create a custom ISchemaGenerator from the one in source and alter the GenerateConcreteSchema method under the DataType.Object case to not return as reference and this solves the issue.

How to make a post request with a custom token document ref with firebase firestore Rest API

Here is my code below, I'm trying to send a post request using Firebase Firestore Rest API. It works, but it generates a random ref id token that links it to the post data (fields) I sent, which makes it difficult to relate to.
I want to be able to link my post data with a custom id token.
final String customIdToken9 = 'customIdToken9'
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers/$customIdToken9"
const _body = {
"fields": {
"androidNotificationToken": {
"nullValue": null
},
"fullname": {
"stringValue": "Custom"
},
"uid": {
"stringValue": "$customIdToken9"
},
"admin": {
"stringValue": ""
},
"email": {
"stringValue": "customer1#gmail.com"
},
"photo": {
"stringValue": ""
},
"coverPhoto": {
"stringValue": ""
},
"bio": {
"stringValue": ""
},
"role": {
"stringValue": "user"
},
"mobile": {
"stringValue": "092222"
}
}
}
http.post(url, body = _body);
When I run this code above it returns
{
"error": {
"code": 400,
"message": "Document parent name \"projects/MyAppId/databases/(default)/documents/customers\" lacks \"/\" at index 59.",
"status": "INVALID_ARGUMENT"
}
}
If I remove the customTokenId9, it works, but it generates a random token Id, which I don't want
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers/"
http.post(url, body = _body);
If you want to specify your own document name, you need to add a query paramater called documentId to your URL request. Here's how it should look like on your code:
final String customIdToken9 = 'customIdToken9'
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers?documentId=$customIdToken9"
const _body = {
"fields": {
"androidNotificationToken": {
"nullValue": null
},
"fullname": {
"stringValue": "Custom"
},
"uid": {
"stringValue": "$customIdToken9"
},
...
}
}
The client-assigned document ID to use for creating a document. It is optional. If not specified, a random ID will automatically be assigned by the service.
Full description is stated in this link and you'll see it in the Query Parameters section. You can also try to test out the API and expand it to see its curl equivalent.
Additionally, you can look up to this documentation to understand how a query parameter works. It applies on any REST API's offered by Firebase.
Why is your variable final String customIdToken but you are using $customIdToken9 it should be $customIdToken.

Query Firebase using Rest Call

I am querying firestore using query
https://firestore.googleapis.com/v1/projects/myproject/databases/(default)/documents/mycollection
I am getting following Json. Can someone please help me how can I filter my query based on Rate field. I am writing following query and it doesn't work
https://firestore.googleapis.com/v1/projects/myproject/databases/(default)/documents/mycolletion?Rate="15"
{
"documents": [
{
"name": "0C45nDuozgQDOwEx5xHR",
"fields": {
"Clinic": {
"stringValue": "American Hospital"
},
"Rate": {
"stringValue": "140"
},
,`enter code here`
"createTime": "2020-06-28T20:32:18.776123Z",
"updateTime": "2020-07-22T21:19:24.061647Z"
},
{
"name": "Jm3tNVWmk4Q1pk87KL1m",
"fields": {
"Clinic": {
"stringValue": "Cleaveland clinic"
},
"Rate": {
"stringValue": "150"
},
"createTime": "2020-06-28T20:28:03.726819Z",
"updateTime": "2020-07-22T21:19:05.073019Z"
}
}
The problem is that the Rate field is an object (inside another object to make it worse), so in order to achieve that you would either need to update you Firestore structure to do it all in the request URL, or you would have to use a structured query in the body of the request.
Change the structure:
In order to work with the request you already have, you will need to change the structure to (using the 1st document as an example):
{
"name": "0C45nDuozgQDOwEx5xHR",
"Clinic": "American Hospital",
"Rate": "140",
"createTime": "2020-06-28T20:32:18.776123Z",
"updateTime": "2020-07-22T21:19:24.061647Z"
}
which in my opinion makes it simpler although I don't have the full picture
Have a Structured query in your request body:
To keep the structure you already have you will need to use thisURL:
https://firestore.googleapis.com/v1/projects/myproject/databases/(default)/documents/:runQuery
And add this to the body of the request:
"structuredQuery": {
"from": [{
"collectionId": "mycollection"
}],
"where": {
"fieldFilter": {
"fields": {
"Rate": {
"stringValue": "15"
}
}
}
}
}
You can check more details by checking the runQuery Documentation and the structuredQuery Documentation for what else you can do with these options.

PACT jvm matching rules are being ignored when running test

I'm using PACT JVM https://github.com/DiUS/pact-jvm/tree/master/provider/pact-jvm-provider-junit
I don't know why the matching rules in my contact are being ignored.
My HTTP test
#RunWith(SpringRestPactRunner.class) // Say JUnit to run tests with custom Runner
#Provider("provDataTest")// Set up name of tested provider
#PactBroker(host="pact-broker.services", port = "80")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
properties = {"spring.profiles.active=dev"},
classes = Application.class)
public class ContractTesting {
private static String token;
#BeforeClass //Method will be run once: before whole contract test suite
public static void setUpService() {
//Run DB, create schema
//Run service
//...
System.out.println("Now service in default state");
}
#TargetRequestFilter
public void exampleRequestFilter(HttpRequest request) {
}
#State("Check correct data json structure in case code: 401")
public void checkDataInCaseUnauthorized() {
}
#TestTarget // Annotation denotes Target that will be used for tests
public final Target target = new HttpTarget(8082);
And my Contract file
{
"provider": {
"name": "provDataTest"
},
"consumer": {
"name": "test"
},
"interactions": [
{
"description": "Read all links_401",
"request": {
"method": "GET",
"path": "/v1/consumer/me/link_social_account",
"headers": {
"invalidAuth": "401"
}
},
"response": {
"status": 401,
"headers": {
"Content-Type": "text/json;charset=utf-8"
},
"body": {
"error": {
"code": 401,
"message": "session incorrect",
"errors": []
}
},
"matchingRules": {
"body": {
"$.error": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.error.code": {
"matchers": [
{
"match": "integer"
}
],
"combine": "AND"
},
"$.error.message": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.error.errors[*].message": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.error.errors[*].field": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
}
},
"header": {
"Content-Type": {
"matchers": [
{
"match": "text/json;charset=utf-8",
"regex": "regex"
}
],
"combine": "AND"
}
}
}
},
"providerStates": [
{
"name": "Check correct data json structure in case code: 401"
}
]
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.2.11"
}
}
}
And show error after run
Read all links_401 returns a response which has a matching body
Read all links_401 returns a response which has a matching
body=BodyComparisonResult(mismatches={/=[BodyMismatch(expected=[B#480e8a7a, actual=[B#10378c35, mismatch=Actual body '[B#10378c35' is not equal to the expected body '[B#480e8a7a', path=/, diff=null)]},
diff=[-{"error":{"code":401,"message":"session incorrect","errors":[]}},
+{"error":{"code":401,"message":"session incorrect, please login again (CR_A1004)","errors":[]}}])
I have tried to change regex but the problem is still happening.
It is only correct when message data correct.
Please help to give my point incorrect.
Thanks,
The problem is with your content-type header: "Content-Type": "text/json;charset=utf-8". The proper content type for JSON payloads should be application/json. That is why the matchers are not being applied, because the body is being treated as a text payload. Just change the content type and then the body will be parsed as a JSON document and the matchers will be applied to the fields.

Resources