Jump to content

404 error on POST API calls


pbb72

Recommended Posts

After succesfully playing around a little with the Emby API (server v 4.6.7.0 on a QNAP NAS) reading information from Emby, I wanted to try changing the name of an item.

So I perform a POST to http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items/14622?X-Emby-Token=(...), with a body that contains the JSON data of the item but with the changed name, but in return I get a 404 error with the contents "Unable to find the specified file."

This 404 is really puzzling me. If I change the POST into a GET, then I get the current info on the item without any problem. So the item is there, it is found. I've tried both from client-side JavaScript in a webpage, and using the Postman application with identical results. I've studied the actual call that is sent to the server when using the GUI to change the name, and that seems to be the same call as I am using.

Is it some error caused by CORS? For as far as I know, that should not trigger a 404 error. Is there some fault in the call itself? Then I would have expected a 500-series error message, not a 404.

I hope someone can tell me what I am doing wrong...

Link to comment
Share on other sites

That's the call to update an item, not to retrieve information about items. So it just depends on what you're trying to do.

Link to comment
Share on other sites

Cheesegeezer
1 hour ago, pbb72 said:

That is exactly what I tried to do; I want to change the name of an item.

You would need to get all the itemDTO by id or other methods, edit it and post it back otherwise you will be missing all the other metadata.

 

Edited by Cheesegeezer
Link to comment
Share on other sites

The ID is probably incorrect.  As Cheese said, the proper way to accomplish what you want is to first retrieve the item, then change whatever you want and post it back.  How did you obtain/create the item you are trying to send?

Link to comment
Share on other sites

6 hours ago, ebr said:

The ID is probably incorrect.  As Cheese said, the proper way to accomplish what you want is to first retrieve the item, then change whatever you want and post it back.  How did you obtain/create the item you are trying to send?

What I did was the following:

First I just ran a GET request to http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items?X-Emby-Token=... to get a list of all root items, such as the "Video" group. From that I took the Id and ran a GET to http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items?parentId=09790ec4c9712e6dfb0961f34680b352&X-Emby-Token=... to get the list of all 2000+ files in the video group.

From that list I took the Id of the first video and ran another GET for http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items/14622?X-Emby-Token=... to get the details of that video. So far, everything is great and returns all data I need and expect.

Then I take the JSON data returned by the last request, change the value of the "Name" field in that object, stringify the object and put it in the body of a POST request with the exact same URL as the previous GET. I send out that request, and I get in return: 404 - Unable to find the specified file.

HTML code:

<!doctype html>
<html>
<head>
<title>Emby Playlists</title>
</head>
<body>
<script>

let server = 'http://192.168.1.10:8096';
let token = '...';
let user = '91926ad6a076424ba21dcf253983460e';

fetch(`${server}/Users/${user}/Items/14622?X-Emby-Token=${token}` )
.then( response => response.json() )
.then( data => {
	console.log(data);
	data.name = 'edited ' + data.name;
	fetch(`${server}/Users/${user}/Items/14622?X-Emby-Token=${token}`, {
		method: 'POST',
		body: JSON.stringify( data )
	} )
	.then( response => response.json() )
	.then( data => {
		console.log(data);
	})
})

</script>
</body>
</html>

Console log:

{
    "Name": "edited my_video",
    "ServerId": "c19462ef2dea471fbf131920d2156ba3",
    "Id": "14622",
    "Etag": "27e9d785c165c4f5a48d7c6904e0e4fc",
    "DateCreated": "2022-05-28T12:37:52.0000000+00:00",
	...
}

POST http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items/14622?X-Emby-Token=... 404 (Not Found)
(anonymous) @ playlist.html:18
Promise.then (async)
(anonymous) @ playlist.html:15
VM203:1 
        
       Uncaught (in promise) SyntaxError: Unexpected token 'U', "Unable to "... is not valid JSON
Promise.then (async)
(anonymous) @ playlist.html:23
Promise.then (async)
(anonymous) @ playlist.html:15

In the developer console, I right-click the failing request, and choose "Open in new tab". This converts the POST into a GET without any chance for me to mess up the numbers, and the URL resolves without problems and shows the information of the item.

I've also tried doing everything in the Emby interface manually and watching the POST request, and that seems to me to be the exact same as the POST request I am using.

I've also tried the POST in the Postman application, and also there I'm getting the same 404 error.

Edited by pbb72
Link to comment
Share on other sites

Cheesegeezer
50 minutes ago, pbb72 said:

What I did was the following:

First I just ran a GET request to http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items?X-Emby-Token=... to get a list of all root items, such as the "Video" group. From that I took the Id and ran a GET to http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items?parentId=09790ec4c9712e6dfb0961f34680b352&X-Emby-Token=... to get the list of all 2000+ files in the video group.

From that list I took the Id of the first video and ran another GET for http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items/14622?X-Emby-Token=... to get the details of that video. So far, everything is great and returns all data I need and expect.

Then I take the JSON data returned by the last request, change the value of the "Name" field in that object, stringify the object and put it in the body of a POST request with the exact same URL as the previous GET. I send out that request, and I get in return: 404 - Unable to find the specified file.

HTML code:

<!doctype html>
<html>
<head>
<title>Emby Playlists</title>
</head>
<body>
<script>

let server = 'http://192.168.1.10:8096';
let token = '...';
let user = '91926ad6a076424ba21dcf253983460e';

fetch(`${server}/Users/${user}/Items/14622?X-Emby-Token=${token}` )
.then( response => response.json() )
.then( data => {
	console.log(data);
	data.name = 'edited ' + data.name;
	fetch(`${server}/Users/${user}/Items/14622?X-Emby-Token=${token}`, {
		method: 'POST',
		body: JSON.stringify( data )
	} )
	.then( response => response.json() )
	.then( data => {
		console.log(data);
	})
})

</script>
</body>
</html>

Console log:

{
    "Name": "edited my_video",
    "ServerId": "c19462ef2dea471fbf131920d2156ba3",
    "Id": "14622",
    "Etag": "27e9d785c165c4f5a48d7c6904e0e4fc",
    "DateCreated": "2022-05-28T12:37:52.0000000+00:00",
	...
}

POST http://192.168.1.10:8096/Users/91926ad6a076424ba21dcf253983460e/Items/14622?X-Emby-Token=... 404 (Not Found)
(anonymous) @ playlist.html:18
Promise.then (async)
(anonymous) @ playlist.html:15
VM203:1 
        
       Uncaught (in promise) SyntaxError: Unexpected token 'U', "Unable to "... is not valid JSON
Promise.then (async)
(anonymous) @ playlist.html:23
Promise.then (async)
(anonymous) @ playlist.html:15

In the developer console, I right-click the failing request, and choose "Open in new tab". This converts the POST into a GET without any chance for me to mess up the numbers, and the URL resolves without problems and shows the information of the item.

I've also tried doing everything in the Emby interface manually and watching the POST request, and that seems to me to be the exact same as the POST request I am using.

I've also tried the POST in the Postman application, and also there I'm getting the same 404 error.


 

In your script, btw I’m no JS expert….

you are nesting to many functions and entering callback hell.

i would split them out 

create an async function that await calls the 3 seperate functions. Get, edit and post

fetch data and add to a global variable.

edit that variable (which is all the itemDTO)  with item.Name = “new name”

then add the post back function to the server.

the json looks like it doesn’t have time to return all the fetch data before it starts to edit and post

 

@chef help me out if I’m speaking BS

😉

 

Link to comment
Share on other sites

chef

Couple things,

First you're hitting a 404 at the Users endpoint.

What are you trying to do exactly there?

 

As far as the JSON error, I've seen this before.

I'd need to be sure but... if you do this to  your fetch data does it complete the JSON object, and the error go away?

body: "{" + JSON.stringify(data) + "}"

 

 

4 minutes ago, Cheesegeezer said:

 

you are nesting to many functions and entering callback hell.

i would split them out 

create an async function that await calls the 3 seperate functions. Get, edit and post

 

 

Yeah it might be better to create an async  functions for the fetch calls, and feed the data in there. But... it is personal taste I guess. 

 

this is untested, but...

const token, server;
async function Post(endpoint, data) {

    var result = await fetch(`${server}{endpoint}?X-Emby-Token=${token}`, {
		method: 'POST',
		body: JSON.stringify( data )
	};
    console.log(result.json());
}

 

Then you are just sending your endpoints to the method...

await Post("/Users/{id}", somedata);

 

 

But... and sorry to ramble... if you open the ApiClient.js for the emby dashboard, you could pretty much grab what you want from it.

Further more if you add the files from Javascript API, you can use them too.

I did this for the POSTERS app.

 

you could download that app, and take whatever you'd like from it. :)  If it helps.

 

Did I help here? I'm unsure.

  • Like 1
Link to comment
Share on other sites

Happy2Play

Little confused here as you are not using the endpoint you listed above  ItemUpdateService POST /Items/{ItemId}

You are showing us ItemsService /Users/{UserId}/Items (which has no POST)

/Users/91926ad6a076424ba21dcf253983460e/Items/14622

 

  • Like 2
Link to comment
Share on other sites

@Happy2Play you are amazing, thank you so much! To retrieve information about an item, one needs to be using the endpoint under /Users/, but for updating the item, the root of the endpoint is /Items/, I had not noticed this at all! I remember being confused as to why the ItemsService was located underneath /Users/, and then have been so aware of this that I didn't notice the ItemUpdateService was not underneath /Users/...

I'm not at home so I can't test right now, but I'm 90% certain this is what I was doing wrong.

To everybody else; thanks for all the help! I know my code was quite smelly, but it was an initial hack to study how the API is working, cutting away more and more code trying to find the source of my trouble.

  • Like 1
Link to comment
Share on other sites

Hi. Yeah, that's what Luke was trying to say in his first post.  The update is a different API call from the get.  Sorry that wasn't clear.

  • Like 1
Link to comment
Share on other sites

Can confirm now that this was indeed the cause of my problems. It is an uncommon situation, where the endpoint to change an item is another than the one to retrieve the item from. Also, that an Item endpoint is located underneath Users is uncommon, but my guess is this has something to do with access rights.

I discovered now that I can actually copy API requests from the web interface as complete `fetch` commands using Chrome's Developer Tools, so that will hopefully save me from missing small details in the future. 😉

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...