Can I resolve the issue in JIRA?
I made some trials with REST API as;
var url = "https://hibernate.atlassian.net/rest/api/2/issue/WEBSITE-1/transitions";
var message = [{
"update": {
"comment": [
{
"add": {
"body": "some text for body"
}
}
]
},
"fields": {
"assignee": {
"name": "name1"
},
"resolution": {
"name": "Fix"
}
},
"transition": {
"id": "1"
}
}];
request({
url: url,
method: "POST",
json: true,
body: message,
}, function (error){});
Url(https://hibernate.atlassian.net/rest/api/2/issue/WEBSITE-1/transitions) gives me;
{"expand":"transitions","transitions":[]}
How can I resolve an issue in JIRA? Am I doing wrong?
You've got the right approach, but you need to authenticate your requests with a user that has permission to execute the transition.
Because you execute your requests anonymously, JIRA gives you a response that does not contain any transitions you can execute and will not allow you to perform a transition.
Take a look at the documentation for the request module or another example.
To get the full list of transitions, append the string ?expand=transitions.fields to your existing url. So in this case it would look like
var url = "https://hibernate.atlassian.net/rest/api/2/issue/WEBSITE-1/transitions?expand=transitions.fields";
Related
I have a test helper function createUser that makes an HTTP request to the backend API to create a user. The backend API calls a method on Auth0 client to create a user. The responses I have are set for Auth0 client URL path /api/v2/users.
I am testing a service that has two types of users - an owner of the account and the invitee user. I am calling a helper twice before all the tests:
const owner = await createUser('owner#email.com');
const invitee = await createUser('invitee#email.com');
And I expect owner to have owner#email.com as an email and an invitee#email.com email for invitee .
In order to return two different responses I used Wiremock scenarios. And currently I have the responses like this:
User #1
{
"scenarioName": "user-scenario",
"requiredScenarioState": "Started",
"newScenarioState": "owner-user",
"request": {
"method": "POST",
"urlPattern": "/api/v2/users"
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"email": "owner#email.com"
}
}
}
User #2
{
"scenarioName": "user-scenario",
"requiredScenarioState": "owner-user",
"request": {
"method": "POST",
"urlPattern": "/api/v2/users"
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"email": "invitee#email.com"
}
}
}
When I run the tests Wiremock returns the second response for both createUser calls. The second response was created after the first and Wiremock prioritizes the most recently created response. I decided to set the priority: 1 on the first response to force Wiremock to return it and therefore change the scenario state. That worked only on the first test run but not for the subsequent ones.
Sometimes if I delete the Wiremock Docker image and start the container from scratch it returns the responses as expected but then continues returning the second response for both calls.
What am I doing wrong and if it's not how I set up the scenarios what could be the possible reasons for such inconsistency?
Multiple ways to skin this cat - third (response templating) is probably best.
Understanding Scenarios
The first request moves the scenario into state owner-user, and after that all requests will return user #2 for the lifetime of the WireMock instance - in your case, the docker container - unless it is reset.
You can reset it as so: PUT /__admin/scenarios/user-scenario/Started.
The state of a scenario is held in memory, so restarting the container should also reset the state to Started.
See WireMock | Stateful Behaviour | Resetting a single scenario
Using better matching to avoid scenarios
You may not need to use scenarios at all. You can use the request body of the POST to decide which stub to call, based on the email address you are sending.
Assuming your request payload looks like this:
{
"email": "owner#email.com"
}
You can match on the request body as so:
User #1
{
"request": {
"method": "POST",
"urlPattern": "/api/v2/users",
"bodyPatterns": [
{
"matchesJsonPath": {
"expression": "$.email",
"equalTo": "owner#email.com",
}
}
]
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"email": "owner#email.com"
}
}
}
User #2
{
"request": {
"method": "POST",
"urlPattern": "/api/v2/users",
"bodyPatterns": [
{
"matchesJsonPath": {
"expression": "$.email",
"equalTo": "invitee#email.com",
}
}
]
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"email": "invitee#email.com"
}
}
}
See WireMock | Request Matching | JSON Path for details.
Using response templating to reduce number of stubs
You can use values passed to WireMock in the request in the response using response templating as so:
{
"request": {
"method": "POST",
"urlPattern": "/api/v2/users"
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"transformers": ["response-template"],
"jsonBody": {
"email": "{{jsonPath request.body '$.email'}}"
}
}
}
See WireMock | Response Templating | JSONPath helper for details.
There are also a variety of helpers for generating random data in various formats should you need each request to return some different value (e.g. a UUID) - see WireMock | Response Templating | Random value helper for details.
I have a task in autopilot that collects data from a caller then calls a function using a redirect.
I cant seem to access the post variables. please assist.
so when run this I get the following error
Error - 82002
Error on Twilio Function response
produced by this line of code
var first_name = memory.twilio.collected_data.lead_qual.lead_qual_first;
remove that line and it works fine just no access to the collected data.
following are the dependencies I have included, the task code and the function.
looks like this..
Dependencies......>
lodash 4.17.11
twilio 3.29.2
fs 0.0.1-security
got 9.6.0
moment-timezone 0.5.14
moment 2.29.1
xmldom 0.1.27
twilio/runtime-handler 1.0.1
util 0.11.0
request 2.87.0
Task......>
{
"actions": [
{
"collect": {
"name": "lead_qual",
"questions": [
{
"question": "What is your first name?",
"name": "lead_qual_first",
"type": "Twilio.FIRST_NAME"
},
{
"question": "What is your last name?",
"name": "lead_qual_last",
"type": "Twilio.LAST_NAME"
},
{
"question": "If we are disconnected what is the best phone number to reach you on??",
"name": "lead_qual_phone",
"type": "Twilio.PHONE_NUMBER"
},
{
"question": "What is your date of birth?",
"name": "lead_qual_dob",
"type": "Twilio.DATE"
},
{
"question": "Are you currently covered by disability, yes or no?",
"name": "lead_qual_disability",
"type": "Twilio.YES_NO"
},
{
"question": "Do you have any form of federal medicare, yes or no?",
"name": "lead_qual_medicare",
"type": "Twilio.YES_NO"
},
{
"question": "Do you have medicaid or another state sponsored insurance, yes or no?",
"name": "lead_qual_medicaid",
"type": "Twilio.YES_NO"
},
{
"question": "Finally, Are you currently insured, yes or no?",
"name": "lead_qual_insured",
"type": "Twilio.YES_NO"
}
],
"on_complete": {
"redirect": {
"method": "POST",
"uri": "https://health-agent-3097.twil.io/Evaluate-Answers"
}
}
}
}
]
}
Function ......>
// This is your new function. To start, set the name and path on the left.
exports.handler = function(context, event, callback) {
// Require the component used to post.
const got = require("got");
// Time zone for EST to check times with.
let moment = require('moment-timezone');
const now = moment().tz('America/New_York');
// initialize the return object
var responseObject = {};
var first_name = memory.twilio.collected_data.lead_qual.lead_qual_first;
responseObject =
{
"actions":[
{
"say":"Force Override result"
},
{
"redirect": {
"method": "POST",
"uri": "task://goodbye"
}
}
]
}
// This callback is what is returned in response to this function being invoked.
callback(null, responseObject);}
Twilio developer evangelist here.
memory is not one of the arguments passed to a Twilio Function. You are passed event, context and callback. You are using the callback correctly and the context includes your environment variables.
The event object is what you need here though. The event includes all the parameters sent to the Function. According to the documentation on the Autopilot request you will be sent a Memory parameter. That Memory will be a JSON string that needs parsing. So instead, try accessing:
const memory = JSON.parse(event.Memory);
const firstName = memory.twilio.collected_data.lead_qual.lead_qual_first;
Let me know how you get on with that.
In an AWS lambda written in Node.js, I want to extract the following part of a URL when I do a GET call through the API gateway:
/devices/{id} --> {id} will be replaced by a value, and that is the value I want!
I know that to get QueryStringParameters you just use
event.queryStringParameters.[parameter name]
But how will I do this for path parameters, like for {id} above.
Also is there a good place where I can comprehensively learn about writing lambdas for APIs in Node.js?
Short answer:
const { id } = event.pathParameters;
I recently released a short training video that demonstrates in detail how to create API Gateway REST APIs and integrate them with AWS Lambda (NodeJS). Please check it out here:
Serverless Architecture: AWS API Gateway & Lambda
I'm assuming you are using lambda proxy here i'm pasting the event object sample for lambda proxy.
{
"message": "Good day, John of Seattle. Happy Friday!",
"input": {
"resource": "/{proxy+}",
"path": "/Seattle",
"httpMethod": "POST",
"headers": {
"day": "Friday"
},
"queryStringParameters": {
"time": "morning"
},
"pathParameters": {
"proxy": "Seattle"
},
"stageVariables": null,
"requestContext": {
"path": "/{proxy+}",
"accountId": "123456789012",
"resourceId": "nl9h80",
"stage": "test-invoke-stage",
"requestId": "test-invoke-request",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": "123456789012",
"cognitoIdentityId": null,
"caller": "AIDXXX...XXVJZG",
"apiKey": "test-invoke-api-key",
"sourceIp": "test-invoke-source-ip",
"accessKey": "ASIXXX...XXDQ5A",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": "arn:aws:iam::123456789012:user/kdeding",
"userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_131)",
"user": "AIDXXX...XXVJZG"
},
"resourcePath": "/{proxy+}",
"httpMethod": "POST",
"apiId": "r275xc9bmd"
},
"body": "{ \"callerName\": \"John\" }",
"isBase64Encoded": false
}
}
the path can be extracted from "path" key in event object, it can be accessed from event.path and after that you can use string manipulation function to further manipulate it.
I hope it helps !
Use brackets in the resource path, as image above. Then in node.js user the code below:
exports.handler = async function(event) {
let serviceId = event.pathParameters.id;
}
The solution is very similar to what you mentioned in the first place. Just use event.pathParameters instead of event.queryStringParameters.
Here I'm using /api/test/{id} as my resource path and using Lambda Proxy integration. I'm getting the following event when I hit https://www.dummyapi.com/dev/api/test/id-123456
This has taken me awhile to figure out on my own so hoping this helps someone. After defining the Path Parameter on the Resource in API Gateway.
AWS Guide including PathParameter Steps: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-step-by-step.html
If using CloudFormation: https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-proxy-path-parameter-error/
My path /user/{userId}
My Path Parameter: userId
Then in my lambda function you can access the path via event.path which will have your parameters in object form: path: { userId: 9812 } }. Lots of documentation has it labeled as pathParameters but for whatever reason with this setup it doesn't come through that way.
export const getUser = async (event) => {
console.log(event);
const { userId } = event.path;
}
serverless.yaml
events:
- http:
path: user/{userId}
method: get
request:
parameters:
paths:
userId: true
integration: lambda
I have this post request to JIRA to create an issue:
require('isomorphic-fetch');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var summ = "Review Test Ticket";
var issue = {
"fields": {
"project":
{
"key": "ABC"
},
"summary": summ,
"description": "This is a test JIRA issue creation",
"issuetype": {
"name": "Story"
},
"assignee": {
"name": "myname"
},
"customfield_10902": [{ "value": "Red Team" }],
"customfield_10008": 1
}
};
var missue = JSON.stringify(issue)
fetch("https://my_jira_host/jira/rest/api/2/issue/", {
body: missue,
headers: {
"Authorization": "Basic my_auth_token",
"Content-Type": "application/json"
},
method: "POST"
})
.then(function( data ) {
console.log(data);
}).catch(function(data) {
alert(data);
});
If the above code is in a file called "my_file.js" if I run node my_file.js the ticket is successfully created.
However, if I move that code inside a function that runs on button click in my react app, and then run the app (on localhost or a server) then it fails. I get a 403. The alert displayed from my catch is: TypeError: NetworkError when attempting to fetch resource.
I have tried absolutely everything. Have no idea where to go from here. Any ideas?
I'm trying to send a transactional email via node using sendGrid. Below is an example of my code.
const subject = 'Email subject';
const templateId = 'templateId';
const sg = require('sendgrid')(secret);
const request = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: {
"personalizations": [
{
"bcc": userEmails,
"substitutions": {
"-userName-": userDetails.name,
"-productPrice-": productDetails.price,
"-productUrl-": productDetails.url,
"-productPercentageDrop-": productDetails.percentageDrop,
"-productName-": productDetails.name,
"-productOriginalPrice-": productDetails.origPrice,
"-productDroppedPrice-": productDetails.dropPrice,
"-productImageUrl-": productDetails.imageUrl
},
"subject": subject.substring(0, 75)
}
],
"from": {
"email": "myemail",
"name": "myname"
},
"content": [
{
"type": "text/html"
}
],
"template_id": templateId
}
});
sg.API(request, function (error, response) {
if (error) {
console.log('Error response received');
}
console.log(response.body.errors);
});
But every time I run the code I get the following error message.
400
message: 'Bad Request', field: null, help: null
Which isn't really that helpful when trying to find out why its erroring.
Body JSON being sent:
{
"host":"",
"method":"POST",
"path":"/v3/mail/send",
"headers":{
},
"body":{
"personalizations":[
{
"bcc":[
{
"email":"name1#hotmail.com",
"name":"name1"
},
{
"email":"name2#hotmail.com",
"name":"name2"
}
],
"substitutions":{
"-productPrice-":189.5,
"-productUrl-":"http://www.tesco.com/direct/humax-fvp-4000t500-m-smart-freeview-play-hd-digital-tv-recorder-with-wi-fi-500gb/483-1785.prd",
"-productName-":"Tesco direct: Humax FVP-4000T/500 (M) Smart Freeview Play HD Digital TV Recorder with Wi-Fi - 500GB"
},
"subject":"Product Tesco direct: Humax FVP-4000T/500 (M) Smart Freeview Play HD Digita"
}
],
"from":{
"email":"email#pricetracker.io",
"name":"Pricetracker"
},
"content":[
{
"type":"text/html"
}
],
"template_id":"XXXXXX"
},
"queryParams":{
},
"test":false,
"port":""
}
don't know if this could still be helpful for you, but I've had some similar issues when using substitutions with Sendgrid. I'm using the sendgrid-php library, but internally it sends the same format. What I found was that all substitution values should be converted to string. For instance your value for productPrice should be like this:
"-productPrice-": "189.5",
With quotes. In my case I had integers, and when I converted them to strings, all worked correctly.
If you are not passing string value to the template file then SendGrid will give you
{"errors":[{"message":"Bad Request","field":null,"help":null}]}
Convert your all non-string value to string before sending to the template file.
I got same issue, then I fix using this below syntax, change only you message format.
"value": "'.html_entity_decode((str_replace('"',"'",$message))).'"