For some reason, I am able to call the Jira Server search API and get data back using Postman, but that exact same call on my Express API returns the following error:
400 - {"errorMessages":["The value 'RCA' does not exist for the field 'project'."],"errors":{}}
RCA does in fact exist and again, it works with Postman.
In both cases, I send a POST with the following JSON payload:
{ jql: 'project = RCA' }
I'm also passing the JSESSIONID header with the token returned by the auth API.
So I'm at a loss here... I have no idea why one it working and the other isn't.
The Jira Server API documentation currently suggests using request headers or Oauth tokens to maintain a session. But that is completely misleading and wrong.
The API requires the presence of a JSESSIONID cookie with the session token that is returned by the API.
Here is an example of my working code:
const request = require('request-promise-native');
exports.syncIssues = (req, res) => {
// Create a cookie jar using request.jar API
const jar = request.jar();
// I call the session API and store the returned object
// on the browser side cookies (jira-login). In every single
// other calls, I parse that cookie to include it in a cookie
// jar inside the request options.
const jiraCookie = JSON.parse(cookies['jira-login']).value;
// I create the cookie using the request.cookie API
const cookie = request.cookie(`JSESSIONID=${jiraCookie}`);
const url = 'https://<jira endpoint here>';
// I set the cookie in the cookie jar
jar.setCookie(cookie, url);
const options = {
method: 'POST',
uri: 'https://<jira endpoint here>/rest/api/2/search',
body: {
jql: 'updated <= now()',
startAt: 0,
maxResults: 1,
},
json: true,
// Add the jar to the request options.
jar,
};
request(options)
.then((body) => {
res.json(body);
})
.catch((err) => {
res.status(err.statusCode).json(err);
});
};
@Thomas Deiler, I was able to find a solution. It actually had nothing to do with angular, server configs, etc.
I believe the Jira API documentation is very misleading (or plain wrong). Everything I read about the Authentication API mentioned 2 ways of maintaining a session: Through request headers or through an Oauth token.
Because using headers was the simplest implementation, I went with that, but it turns out that the Jira API does NOT use the JSESSIONID header what so ever. It uses cookies.
The reason it worked with Postman, is that Postman saves cookies returned/set by the API much like a browser would. And so it would submit the cookies along with the calls.
That said, my ExpressJS API would only send headers as the Jira documentation suggested. After fiddling around with many other ideas, I figured out that all I needed to do it send the JSESSIONID cookie along every call and it worked fine.
Here is a snippet of my NodeJS, ExpressJS code to help others:
const request = require('request-promise-native');
exports.syncIssues = (req, res) => {
// Create a cookie jar using request.jar API
const jar = request.jar();
// I call the session API and store the returned object
// on the browser side cookies (jira-login). In every single
// other calls, I parse that cookie to include it in a cookie
// jar inside the request options.
const jiraCookie = JSON.parse(cookies['jira-login']).value;
// I create the cookie using the request.cookie API
const cookie = request.cookie(`JSESSIONID=${jiraCookie}`);
const url = 'https://<jira endpoint here>';
// I set the cookie in the cookie jar
jar.setCookie(cookie, url);
const options = {
method: 'POST',
uri: 'https://<jira endpoint here>/rest/api/2/search',
body: {
jql: 'updated <= now()',
startAt: 0,
maxResults: 1,
},
json: true,
// Add the jar to the request options.
jar,
};
request(options)
.then((body) => {
res.json(body);
})
.catch((err) => {
res.status(err.statusCode).json(err);
});
};
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
What is Express API? Can you increase the verbosity level? What's the error message, when you search for a project, that doesn't exist?
If you are familiar with wireshark you could catch both request on network level and compare. I doubt, that they are similar ...
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I'm building an internal Angular / NodeJS app for reporting that will pull in data from many data sources. ExpressJS is the framework that makes it dead easy to create APIs on NodeJS.
I can give you the whole response I get from Jira, but it is quite a lot of bullshit text (and I believe contains some ExpressJS specific data as well).
Here is it.
What is returned to the browser by my API (and you'll see it's got some Angular specific junk in there which is normal)
{ "data": null, "status": -1, "config": { "method": "POST", "transformRequest": [ null ], "transformResponse": [ null ], "jsonpCallbackParam": "callback", "url": "\/api\/jira\/search", "headers": { "JSESSIONID": "AFF1F52ABA75217C577382C923C07FE4", "Accept": "application\/json, text\/plain, *\/*", "Cache-Control": "no-cache", "Content-Type": "application\/json;charset=utf-8" }, "data": { "jql": "project = RCA", "startAt": 1490, "fields": [ "timespent" ] } }, "statusText": "", "xhrStatus": "abort" }
And here is the same error but from the API:
{ "name": "StatusCodeError", "statusCode": 400, "message": "400 - {\"errorMessages\":[\"The value 'RCA' does not exist for the field 'project'.\"],\"errors\":{}}", "error": { "errorMessages": [ "The value 'RCA' does not exist for the field 'project'." ], "errors": { } }, "options": { "method": "POST", "uri": "<hiding the jira host>\/rest\/api\/2\/search", "body": { "jql": "project = RCA", "startAt": 1490, "fields": [ "timespent" ] }, "headers": { "JSESSIONID": "AFF1F52ABA75217C577382C923C07FE4" }, "json": true, "resolveWithFullResponse": true, "simple": true, "transform2xxOnly": false }, "response": { "statusCode": 400, "body": { "errorMessages": [ "The value 'RCA' does not exist for the field 'project'." ], "errors": { } }, "headers": { "date": "Thu, 24 Jan 2019 16:59:56 GMT", "content-type": "application\/json;charset=UTF-8", "transfer-encoding": "chunked", "connection": "close", "server": "nginx\/1.10.3 (Ubuntu)", "x-arequestid": "1019x549174x1", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "x-frame-options": "SAMEORIGIN", "content-security-policy": "frame-ancestors 'self'", "x-asen": "SEN-10463924", "set-cookie": [ "atlassian.xsrf.token=BKB6-5CSC-155L-OS04_dbc3e26ad7629d2d7961bcdc802f5bd50d3a1d2d_lout;path=\/;Secure" ], "x-ausername": "anonymous", "cache-control": "no-cache, no-store, no-transform" }, "request": { "uri": { "protocol": "https:", "slashes": true, "auth": null, "host": "<hiding the jira host>", "port": 443, "hostname": "<hiding the jira host>", "hash": null, "search": null, "query": null, "pathname": "\/rest\/api\/2\/search", "path": "\/rest\/api\/2\/search", "href": "<hiding the jira host>\/rest\/api\/2\/search" }, "method": "POST", "headers": { "JSESSIONID": "AFF1F52ABA75217C577382C923C07FE4", "accept": "application\/json", "content-type": "application\/json", "content-length": 61 } } } }
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
But what you send with Postman as payload ist not the same you send with your Angular app. What are the two headers like displayed on your screenshot?
Btw: the upper json search request seems much to complicated. I recommend simple using a:
GET /search?jql=project=RCA
And if you make usage of POST cross-site referencing could be an issue. Please read this article.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The problem and response is the same. I just copied the wrong one.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
And in this case, it isn't the browser that is calling Jira directly. The browser is calling an internal API, and that API calls Jira and does get a response. But a response that the queried project does not exist.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Dear @Justin Ledoux,
I know how exhausting development against the rest api can be. I did in Java with Apaches HTMLClient and I got gray hairs while doing it. Anyhow in your situation I would point out following topics for the source of the problem:
For the first, I recommend checking out your API implementation against something completely different. For example code against http://www.jsontest.com/ just to ensure the request are built in the right way.
The second one can be verified by analyzing the network traffic. First increase verbosity log level on Jira side an compare the entries between Postman and Angular. One level deeper, use wireshark.
The third, easiest to proof. Just repeat the requests form another client.
The REST API of Jira itself will not be the root cause. It is available for a very long time and has convince with its stability. This is valid for Jira 7.12. or greater. In earlier versions beyond V6 this is probably not the case.
Let me know how I can help you further.
So long
Thomas
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Thomas Deiler, I was able to find a solution. It actually had nothing to do with angular, server configs, etc.
I believe the Jira API documentation is very misleading (or plain wrong). Everything I read about the Authentication API mentioned 2 ways of maintaining a session: Through request headers or through an Oauth token.
Because using headers was the simplest implementation, I went with that, but it turns out that the Jira API does NOT use the JSESSIONID header what so ever. It uses cookies.
The reason it worked with Postman, is that Postman saves cookies returned/set by the API much like a browser would. And so it would submit the cookies along with the calls.
That said, my ExpressJS API would only send headers as the Jira documentation suggested. After fiddling around with many other ideas, I figured out that all I needed to do it send the JSESSIONID cookie along every call and it worked fine.
Here is a snippet of my NodeJS, ExpressJS code to help others:
const request = require('request-promise-native');
exports.syncIssues = (req, res) => {
// Create a cookie jar using request.jar API
const jar = request.jar();
// I call the session API and store the returned object
// on the browser side cookies (jira-login). In every single
// other calls, I parse that cookie to include it in a cookie
// jar inside the request options.
const jiraCookie = JSON.parse(cookies['jira-login']).value;
// I create the cookie using the request.cookie API
const cookie = request.cookie(`JSESSIONID=${jiraCookie}`);
const url = 'https://<jira endpoint here>';
// I set the cookie in the cookie jar
jar.setCookie(cookie, url);
const options = {
method: 'POST',
uri: 'https://<jira endpoint here>/rest/api/2/search',
body: {
jql: 'updated <= now()',
startAt: 0,
maxResults: 1,
},
json: true,
// Add the jar to the request options.
jar,
};
request(options)
.then((body) => {
res.json(body);
})
.catch((err) => {
res.status(err.statusCode).json(err);
});
};
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.