Chat: How do I "filli n the blanks" for uploading attachments?

Good afternoon,
So I've been following this tutorial in working toward setting up our app to support attaching images to... whatever the latest incarnation of your chatlike API is called (a collection of functions under the "ConversationsApi" grouping, neither chat nor web messaging I think... it's all "chat" to us internally :laughing: ). Whatever that catty API is called, so far everything seems to be working well... except that the tutorial assumes you've been implementing all the underlying API calls yourself. In this way, it appears to be a tad... "incomplete", for lack of a better word.

So I've gotten through step 1; short version:

// Where conversations = an instance of PlatformClientWHateverItIs.ConversationsApi();
var info = await conversations.getConversation(conversationID);

// According to the tutorial, the "communication ID" is the agent's first message's ID.
// getParticipantByPurpose is a function we wrote, because a lot of Genesys things
// require random bits and pieces from the "participants" sub-object.  It returns
// info.participants, the one with purpose=second parameter ("agent" in this instance).
var agent = getParticipantByPurpose(info.participants, "agent");

// And, as the tutorial showed, that sub-sub-object has an array called messages,
// and that array is not empty, and the first item in the array is an object with an "id".
// So everything is working well at this point.
var communicationID = agent.messages[0].id;

// Now comes the second request, to get the upload URL and an ID we can use in chat/messages
var media = await conversations.postConversationsMessageCommunicationMessagesMedia(conversationID, communicationID);

// This succeeds as well, returning an object with an ID and upload URL (and other stuff)

Next, the tutorial wants you to send the file to the upload URL... and there is no way to accomplish this using the SDK. Normally this would be a non-issue - I could do XHRs in my sleep, and the Fetch API makes it even a bit easier (since it supports await and all that vs. the usual callback-mania that is JS :laughing:). Buuuuuut..... "The request headers should include the Authorization header with the same bearer token that is used to make other API requests." Wellllllll........ohhhhh.....kay? So here we are. :laughing:

So what I need to do is discover how to calculate the "bearer" header for the raw fetch call. Now when the app starts, the access token is currently in a place where users can't find it, though I suppose I could leave it somewhere for this part of the code to reference (though that sounds a bit risky)... but even then, isn't "bearer" some hash or something? I can see it in the Network tab, but idk whether it's using something simple like base-64, or a one-way hashing algorithm like PHP's password_hash, or something more suited for transferring data like RSA or whatever... also if I remember like 2 years ago when I read up on the OAuth stuff I guess it wasn't just a hash of the access token... yeah, an SDK endpoint for this would have been super helpful... or am I just missing something, again? :laughing: That is most likely the case, I'm sure.

Thanks in advance. :smiley:

Hi @LighthouseMike you might want to view this page for some more information https://developer.genesys.cloud/authorization/platform-auth/use-authorization-code lower down in the page there is a section labeled Use the access token that seems like it's exactly what you need here. In your request to upload the file, you are just going to use "bearer {yourToken}" in the Authorization header. Hope this helps

Hey, got sidetracked by a different project. Sorry about that. So it's just the access token, in plain text? That sure would be easy enough. idk where I got base-64 or whatever. :laughing:

Quick update in case anyone is following this thread for future reference. I've got it sending the response (using standard JS tho, not jquery or dojo or react or vue or whatever the Framework of the Day is that has a $.ajax wrapper around Fetch/XHR lol... the tutorial seems to assume everyone uses it :laughing:).


async function uploadImage(file, conversationID) {
	// Get the conversation and communication IDs, as before.
	var info = await conversations.getConversation(conversationID);
	var agent = getParticipantByPurpose(info.participants, "agent");
	var communicationID = agent.messages[agent.messages.length - 1].id;

	// Get the upload URL (again, this works fine)
	var media = await conversations.postConversationsMessageCommunicationMessagesMedia(conversationID, communicationID);
	
	// Now we get into more tricky territory... "400 Bad Request".
	// No other information provided.  Request and response are empty, because...?
	// So clearly I've done something incorectly... and that's all I got. :-D
	var form = new FormData();
	form.append('file', file);
	fetch(media.uploadUrl, {
		method: 'POST',
		headers: { Authorization: "bearer " + _token },
		processData: false,
		contentType: false,
		mimeType: 'multipart/form-data',
		data: form
	});
}

// This prompts me to pick a file; I always choose a valid image that isn't too big.
function upload() {
	var i = document.createElement('input');
	i.type = "file";
	i.style.display = "none";
	i.onchange = function(e) {
		console.clear();
		uploadImage(e.target.files[0], "58ae1cec-acce-498d-9f57-1123254a4654");
	};
	i.click();
}

// And because browser are pesky when it comes to things other languages allow,
// I gotta have a button, so here ya go, Firefox. :-(
var b = document.createElement("button");
b.style = "position:absolute;left:0px;top:0px;width:100px;height:100px;z-index:99999"
b.innerText = "Test";
b.onclick = upload;
document.body.appendChild(b);

Anyway, I'm guessing my 400 errors are related to my other post regarding chat images in Genesys... but I don't see anything obviously wrong here. With exception of not using Framework of the Hour, my code is pretty much copy/pasted from their example. But, if anyone can see something then I'm open to suggestions. But, like so many things in Genesys, I find it's just another rabbit-hole of guesswork and network-tab-work that'll just have to come naturally as we gain more experience with it and insight into the inner workings of stuff that doesn't have a nice SDK wrapper. I know the SDK is on GitHub, so maybe I can glean some intel from there?

Another quick update on this:

  • I've ruled out it being the wrong HTTP method/verb (if I use "GET" instead of "POST", which I thought might make more sense for an image, I get "405 Method Not Allowed").
  • I've ruled out it being a typo in my header (I thought "bearer" might have to be "Bearer" capitalized)
  • I've ruled out it being a cross-browser issue (tried it in both Firefox and Chrome, same results). This one is especially annoying, since my last image-upload-related question turned out to be something Firefox-y. :laughing:
  • Still no clear indication on what exactly is "bad" about my request...

@LighthouseMike the error response will be in this format https://developer.genesys.cloud/platform/api/statuses you can see there you should have more than just the status code for a bad request response. Maybe your wrapper fetch method is concealing this info?
I would suggest you could try just to make the http request in curl or postman or another request tool. This could help you make sure the format you are passing the data in is correct, before you bring it into JS to try.

1 Like

Well unlike the tutorial (which relies on something called $.ajax), I'm not using a wrapper - I'm using plain old fetch. But in both Firefox and Chrome, if I go to the request in the Network tab, the request and response are blank/empty. It would sure be nice if there were JSON like in the link you gave me... does it only do that with the legacy XMLHTTPRequest or something funky like that?

At any rate, if you think the lack of info is due to the browsers "concealing it"... is there a setting or something I can use to turn that off? :laughing: That doesn't happen with SDK-based API calls, only with this oddball feature that doesn't have an SDK function/method. Don't get me wrong: I'd be willing to bet our server has curl on it (most servers, and even my Linux desktops, have it) and I kinda like having an excuse to learn to use it... but sooner or later I will need to use JS. And if something like this fails on the JS side, it would sure be nice to have some debugging info.

My suggestion was more about making sure your assumptions were correct. Your headers were formatted properly and the data you were passing was correct. It's just a pretty simple REST request to a Genesys Cloud api here. My thoughts are maybe something in your JS code is causing that conflict, OR maybe it's something else. If you can make that http request fine in curl or postman from you developer machine. That at least removes the possible issue that it's your token, org setting, or something else causing the 400 level error response. It removes a possible place for issues. Then it makes it just the JS code that is at fault at least :grinning:

1 Like

Well I know the access token is valid because I can make other API requests with it (using SDK functions). As far as headers, most of what's in my fetch call above was copied directly from a Genesys tutorial (except that I didn't download the $.ajax library and just used a regular fetch, and I replaced their dummy URL with the actual URL I got back from Genesys).

But before I dive into playing with curl (oh darn, a break from JS :laughing: ), you mentioned something about org settings? That, to me, sounds like it could very well be the problem. We were given a dev org, separate from our production one, but org settings have been an issue in a few other areas. Any idea which setting(s) affect an org's ability to allow users to upload images?

PS: Thanks for the quick response. :smiley:

I still don't see a situation where you won't get a message in your response body along with your 400 response code to help you know why the request failed. If you're unable to reproduce your bad request issue by manually trying the request yourself and figure out the issue. The response headers will contain a Correlation-Id with a value. You can take info and contact Genesys Customer Care and they can help you more by using that correlation id. If it's a bug with that 400 status code not containing a message, then they can file a ticket to fix that.

1 Like

oh darn, guess I have to learn curl. :laughing:

All joking aside, thanks for the info about the "correlation ID"; hope it doesn't come to that, but if it does, it's good to know that's another strategy we have available.