When there are multiple headers in the interaction, pact-jvm-provider-maven_2.12 version 3.5.25 throws an exception when I run mvn pact:verify to verify the contract at the provider side
Caused by: java.lang.NullPointerException: Cannot set property 'text' on null object
at org.codehaus.groovy.runtime.NullObject.setProperty (NullObject.java:80)
at org.codehaus.groovy.runtime.InvokerHelper.setProperty (InvokerHelper.java:197)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.setProperty (ScriptBytecodeAdapter.java:484)
at au.com.dius.pact.provider.reporters.JsonReporter.finaliseReport (JsonReporter.groovy:49)
at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod (IndyInterface.java:232)
at au.com.dius.pact.provider.ProviderVerifier$_finialiseReports_closure32.doCall (ProviderVerifier.groovy:367)
My interaction is
"interactions": [
{
"description": "Consumer interaction of Put Person Algorithm",
"request": {
"method": "PUT",
"path": "model/v0/algorithm/person",
"headers": {
"Authorization": "Bearer ACCESS_TOKEN",
"Content-Type": "application/json"
},
"query": {
"crn": [
"TENANT_NAME"
]
},
"body": {
"standardizers": {},
"encryption": {},
"entity_types": {},
"locale": "en_us"
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
}
},
"providerStates": [
{
"name": "B Put Person Algorithm"
}
]
}
],
If I remove "Content-Type": "application/json" from the request headers, this error will be gone. Is this a bug in the plugin?
Absolutely it supports multiple headers. It may be a big with that specific version or some other artifact of the test process. Could you please file a bug report and ideally a reproducible example?
Worth checking you're on the latest version of the maven plugin also.
Related
I'm trying to use Klaviyo for the first time, and the natural starting point seems to be their new Node SDK. Unfortunately, their documentation seems to be an odd combination of extremely detailed, and laking any details.
I've set up my account and gotten my API key, but am failing to get a simple registration to succeed.
I thought I could do this:
import { ConfigWrapper, Profiles } from 'klaviyo-api';
import logger from '../utils/logger';
import requireEnvVariable from '../utils/requireEnvVariable';
export async function subscribe(profile) {
const apiKey = requireEnvVariable('KLAVIYO_PK');
ConfigWrapper(apiKey);
const user = Profiles.createProfile(profile)
.then(data => logger.debug({data}, 'Got profile data'))
.catch(error => {
logger.warn(error, 'Klaviyo error');
return error;
});
return true;
}
For profile, I'm passing in
{
"email": "me#example.com",
"phone_number": "",
"first_name": "Bob",
"last_name": "Smith"
}
but it responds with an error:
WARN: Klaviyo error
env: "development"
err: {
"type": "Error",
"message": "Bad Request",
"status": 400,
"response": {
"req": {
"method": "POST",
"url": "https://a.klaviyo.com/api/profiles/",
"data": {
"email": "me#example.com",
"phone_number": "",
"first_name": "Bob",
"last_name": "Smith"
},
"headers": {
"authorization": "Klaviyo-API-Key <my private key>",
"revision": "2022-10-17",
"user-agent": "klaviyo-api-node/1.0.2",
"content-type": "application/json",
"accept": "application/json"
}
},
"header": {
"date": "Wed, 28 Dec 2022 23:34:14 GMT",
"content-type": "application/vnd.api+json",
"content-length": "211",
"connection": "close",
"cf-ray": "780e1b056c3728f5-ORD",
"allow": "GET, POST, HEAD, OPTIONS",
"vary": "Cookie, Accept-Encoding",
"cf-cache-status": "DYNAMIC",
"cid": "UDiE82",
"ratelimit-limit": "700, 75;w=1, 700;w=60",
"ratelimit-remaining": "699",
"ratelimit-reset": "44",
"x-robots-tag": "noindex, nofollow",
"server": "cloudflare"
},
"status": 400,
"text": "{\"errors\":[{\"id\":\"5648779b-3e1a-4ccf-80c4-dc19b8b32a2c\",\"status\":400,\"code\":\"invalid\",\"title\":\"Invalid input.\",\"detail\":\"The payload provided in the request is invalid.\",\"source\":{\"pointer\":\"/data\"},\"meta\":{}}]}"
}
}
The various examples under Optional Parameters made me think that the above would Just Work; however, the docs also say, "For example values / data types, as well as whether parameters are required/optional, please reference the corresponding API Reference link," and "This SDK is a thin wrapper around our API. See our API Reference for full documentation on API behavior."
So looking at the Create Profile API Reference, I tried both
const user = Profiles.createProfile({attributes: profile})
and
const user = Profiles.createProfile({type: 'profile', attributes: profile})
but they both end up with the same error (except the reported data is updated appropriately, e.g.,
"status": 400,
"response": {
"req": {
"method": "POST",
"url": "https://a.klaviyo.com/api/profiles/",
"data": {
"type": "profile",
"attributes": {
"email": "me#example.com",
"phone_number": "",
"first_name": "Bob",
"last_name": "Smith"
}
},
What's the right way to use the new SDK? Or should I ignore this, and go back to creating manual fetch calls against their API?
I want to get the token information for ADP Client through Azure Logic App. I have the Client Certificate from ADP so I decided to use HTTP trigger from Logic App and selected authentication type "Client Certificate".
Since I cant directly use certificate in Logic app so I converted certificate into base64Encoded .pfx format, and certificate is not having any password.
below is the sample code for the request
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {},
"contentVersion": "1.0.0.0",
"outputs": {},
"triggers": {
"HTTP": {
"inputs": {
"authentication": {
"pfx": "convertedbase64string",
"type": "ClientCertificate"
},
"body": "grant_type=client_credentials&client_id=ClientId&client_secret=client_secret",
"headers": {
"content-type": "application/x-www-form-urlencoded"
},
"method": "POST",
"uri": "https://accounts.adp.com/auth/oauth/v2/token"
},
"recurrence": {
"frequency": "Month",
"interval": 15
},
"type": "Http"
}
}
},
"kind": "Stateful"
}
above request returns me bad request, can anyone help me what is going wrong here?
For converting into base64 I used below steps in power shell
$pfx_cert = get-content 'C:\sample\adpcertificate.pfx' -Encoding Byte
$output =[Convert]::ToBase64String($pfx_cert)
$output
I tried same request with client certificate using postman which is working fine, but not able to get succeed with Logic App.
Any help is much appreciated.
There are only few differences between the headers sent from Postman and the Logic App. The main difference is that Postman also sends the accept-header: "Accept": "*/*" and leaves out alle the x-ms-* headers from the logic app.
I created a Logic App with http-trigger, which I post to from Postman and Logic App to inspect the changes:
With Postman
{
"headers": {
"Connection": "keep-alive",
"Accept": "*/*",
"Accept-Encoding": "br,gzip,deflate",
"Host": "....westeurope.logic.azure.com:443",
"User-Agent": "PostmanRuntime/7.28.4",
"Postman-Token": "...-baea-4e89-9bf6-490a63968b5d",
"Content-Length": "76",
"Content-Type": "application/x-www-form-urlencoded"
},
"body": {
"$content-type": "application/x-www-form-urlencoded",
"$content": "Z3JhbnRfdHlwZT1jbGllbnRfY3JlZGVudGlhbHMmY2xpZW50X2lkPUNsaWVudElkJmNsaWVudF9zZWNyZXQ9Y2xpZW50X3NlY3JldA==",
"$formdata": [
{
"key": "grant_type",
"value": "client_credentials"
},
{
"key": "client_id",
"value": "ClientId"
},
{
"key": "client_secret",
"value": "client_secret"
}
]
}
}
With Logic App
{
"headers": {
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip,deflate",
"Accept-Language": "en",
"Host": "...westeurope.logic.azure.com",
"User-Agent": "azure-logic-apps/1.0,(workflow ...; version ...)",
"x-ms-trigger-callback-url": "https://....westeurope.logic.azure.com/ <...>",
"x-ms-trigger-type": "Http",
"x-ms-workflow-id": "...",
"x-ms-workflow-version": "...",
"x-ms-workflow-name": "myworkflowname",
"x-ms-workflow-system-id": "/locations/westeurope/scaleunits/...",
"x-ms-workflow-run-id": "...",
"x-ms-workflow-operation-name": "HTTP",
"x-ms-execution-location": "westeurope",
"x-ms-workflow-subscription-id": "...",
"x-ms-workflow-resourcegroup-name": "..",
"x-ms-tracking-id": "...",
"x-ms-correlation-id": "...",
"x-ms-client-request-id": "...",
"x-ms-activity-vector": "...",
"Content-Length": "76",
"Content-Type": "application/x-www-form-urlencoded"
},
"body": {
"$content-type": "application/x-www-form-urlencoded",
"$content": "Z3JhbnRfdHlwZT1jbGllbnRfY3JlZGVudGlhbHMmY2xpZW50X2lkPUNsaWVudElkJmNsaWVudF9zZWNyZXQ9Y2xpZW50X3NlY3JldA==",
"$formdata": [
{
"key": "grant_type",
"value": "client_credentials"
},
{
"key": "client_id",
"value": "ClientId"
},
{
"key": "client_secret",
"value": "client_secret"
}
]
}
}
Solution
My solution would be to manually add the Accept-Header in the post request in the Logic App.
"headers": {
"Accept": "*/*",
// ...
},
I sadly don't have an ADP account to verify this, but I've seen other APIs break when no accept header is sent.
I'm using Loopback4 as an Central API. I'm trying to call a method of the 3rd party API through a remote method in Loopback. I'm using Strapi as 3rd party API and communicate this to loopback4
With Loopback, I have a datasource which looks like the following:
const strapiConfig = {
name: 'strapi',
connector: 'rest',
baseURL: appConfig.strapi.host,
crud: false,
options: {
headers: {
"accept": "application/json",
"content-type": "application/json",
"cache-control": "no-cache",
"Authorization" : `Bearer ${appConfig.strapi.token}`
}
},
operations: [
{
"template": {
"method": "GET",
"url": `${strapiUrl}/pages/{pageId}`
},
"functions": {
"getOnePage": ["pageId"]
}
},
{
"template": {
"method": "GET",
"url": `${strapiUrl}/pages`
},
"functions": {
"getPages": ""
}
},
{
"template": {
"method": "GET",
"url": `${strapiUrl}/glossary/{id}`
},
"functions": {
"getOneGlossary": ['id']
}
},
{
"template": {
"method": "GET",
"url": `${strapiUrl}/glossary`
},
"functions": {
"getGlossary": ""
}
},
{
"template": {
"method": "GET",
"url": `${strapiUrl}/faq`
},
"functions": {
"getFaqs": ""
}
},
{
"template": {
"method": "GET",
"url": `${strapiUrl}/faq/{id}`
},
"functions": {
"getOneFaq": ['id']
}
}
]
};
the only endpoint that are working is the pages
Any advice is welcome. Thanks!
What kind of error/status code do you get when calling the other Endpoints?
Have you set the Roles & Permissions within Strapi?
Example (depending on the Strapi version):
Navigate to SETTINGS - Users & Permissions Plugin.
Click the Public Role.
Scroll down under Permissions, open the Application tab and find the collection type you want to edit.
i.e. Click the checkbox next to find and findone.
Click Save
Check: https://strapi.io/documentation/developer-docs/latest/getting-started/quick-start.html#_7-set-roles-and-permissions
I'm using NodeJS to upload panoramic images.
When I make #2 informed in the Google documentation, I get the following return:
Request
{
"url": "UPLOAD_URL",
"body": "/PATH_TO_PANO/pano.jpg",
"method": "POST",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "image/jpeg"
}
}
Response
{
"statusCode": 200,
"body": "",
"headers": {
"x-guploader-uploadid": "AEnB2UoJt4gvmmU6gXZvWDRu4b0DUCeT5vuPKLGcZqM4Tzo9HssCLoloTgAACRmxmP0U5DDYvHXpThCjRslW80bEKLZjUjJB3QNZ5w- j0jd8jdtVnH8X0c",
"content-length": "0",
"date": "Tue, 26 Sep 2017 21:05:17 GMT",
"server": "UploadServer",
"content-type": "text/html; charset=UTF-8",
"alt-svc": "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"",
"connection": "close"
},
"request": {
"uri": {
"protocol": "https:",
"slashes": true,
"auth": null,
"host": "streetviewpublish.googleapis.com",
"port": 443,
"hostname": "streetviewpublish.googleapis.com",
"hash": null,
"search": null,
"query": null,
"pathname": "/media/user/USER_ID/photo/PHOTO_ID",
"path": "/media/user/USER_ID/photo/PHOTO_ID",
"href": "https://streetviewpublish.googleapis.com/media/user/USER_ID/photo/PHOTO_ID"
},
"method": "POST",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "image/jpeg",
"content-length": 45
}
}
}
But when I upload the metadata of the photo, I get the following message:
Request
{
"url": "https://streetviewpublish.googleapis.com/v1/photo?key=YOUR_API_KEY",
"method": "POST",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json",
"Content-Length": 9385487
},
"data": {
"uploadReference": {
"uploadUrl": "UPLOAD_URL"
},
"pose": {
"heading": 110,
"latLngPair": {
"latitude": -29.937386,
"longitude": -60.996952
}
},
"captureTime": {
"seconds": 1506448064836
}
}
}
Response
{
"error": {
"code": 400,
"message": "Photo does not have upload reference.",
"status": "INVALID_ARGUMENT"
}
}
There are not many references to basing myself and finding the problem. For that reason I would like the help of someone who may have gone through something similar.
I have replicated your issue. I've encountered this error when I didn't specify the UPLOAD_URL in the request.
{
"error": {
"code": 400,
"message": "Photo upload url does not match required format.",
"status": "INVALID_ARGUMENT",
"details": [
{
...
}
]
}
}
Make sure that you have added the UPLOAD_URL in the request. Check this documentation for more information.
I tried to create a model, and connect to my API test server.
Here's the REST datasource configuration :
"postsREST": {
"name": "postsREST",
"connector": "rest",
"operations": [{
"template": {
"method": "GET",
"url": "http://localhost:3001/posts"
},
"functions": {
"find": []
}
}, {
"template": {
"method": "POST",
"url": "http://localhost:3001/posts",
"headers": {
"accept": "application/json",
"content-type": "application/json"
},
"query": {
"title": "{^title}",
"author": "{^author}"
},
"body": {
"title": "{^title}",
"author": "{^author}"
}
},
"functions": {
"create": [
"title",
"author"
]
}
}]
}
The problem is, that when I use the explorer, the generated request url is this:
http://localhost:3000/api/posts/create?title=f&author=f
Instead of:
http://localhost:3000/api/posts
What am I doing wrong? Maybe there is new documentation?
Thanks.
You should use form instead of req or body, if you want the params not to be part of the request-url. req or body will append your parameters to the request URL.
Using form will send your parameters just like a form is submitted using POST method and hence as part of the request body.
So, try the following way for the template section in your code:
"template": {
"method": "POST",
"url": "http://localhost:3001/posts",
"headers": {
"accept": "application/json",
"content-type": "application/json"
},
"form": {
"title": "{^title}",
"author": "{^author}"
}
},
Additionally, I do not see any point in adding the same parameters to the req and body attributes both.