DigitalOcean.API icon indicating copy to clipboard operation
DigitalOcean.API copied to clipboard

Point in time restore call fails with status code 422 - unprocessable_entity

Open shrayasr opened this issue 3 years ago • 2 comments

Hi,

At the outset, thank you for such a great client. Clients make interacting with APIs so seamless and quick.

Problem

A few days ago, I was using this client in order to do a point in time restore of a managed DB on our account. Here is the API documentation for that particular call.

My request looked like this:

	var restoreDBRequest = new DatabaseBackup
	{
		Name = "db-restored-from-API",
		Engine = "pg",
		Version = "10",
		Size = "db-s-1vcpu-2gb",
		Region = "blr1",
		NumNodes = 2,
		Tags = new List<string>(),
		BackupRestore = new DatabaseBackupRestore
		{
			DatabaseName = "existing-db",
			CreatedAt = new DateTime(2021, 02, 20, 16, 45, 0)
		}
	};

Which constantly threw the error with a status code 422:

{"message":"invalid json body","id":"unprocessable_entity","request_id":"XXXXX"}

Using this information, I contacted digital ocean's support for a resolution and after much back and forth it has been solved. As per them

  1. The name of the restored db cannot contain capital letters.
  2. The timestamp should be in ISO8601 format.

I made these 2 changes and executed the request:

	var restoreDBRequest = new DatabaseBackup
	{
-		Name = "db-restored-from-API",
+		Name = "db-restored-from-api",
		Engine = "pg",
		Version = "10",
		Size = "db-s-1vcpu-2gb",
		Region = "blr1",
		NumNodes = 2,
		Tags = new List<string>(),
		BackupRestore = new DatabaseBackupRestore
		{
			DatabaseName = "existing-db",
-			CreatedAt = new DateTime(2021, 02, 20, 16, 45, 0)
+			CreatedAt = new DateTime(2021, 02, 20, 16, 45, 0, DateTimeKind.Local)
		}
	};

And I was successfully able to restore my DB to the point in time that I wanted.

Issue

  1. Do you think it makes sense to run a .ToLower() on the DatabaseBackup.Name field?
  2. Do you think it makes sense to throw an exception if the Kind property of DatabaseBackupRestore.CreatedAt is Unspecified?

shrayasr avatar Feb 25 '21 05:02 shrayasr

Issue

  1. Do you think it makes sense to run a .ToLower() on the DatabaseBackup.Name field?

I think if we can point to public documentation mentioning this very important bit, it absolutely makes sense. However I've found non-documented "features" like these tend to just as easily change in the future. Maybe they will support both upper/lowercase, and then we'd have to change back anyways. Barring any actual documentation from DO on this, perhaps best to add it into the function's documentation notes.

  1. Do you think it makes sense to throw an exception if the Kind property of DatabaseBackupRestore.CreatedAt is Unspecified?

I see this more as developer error, you should always specify your timezone for DateTimes. As unlike point #1 this doesn't result in the request failing, does it? I'd have to check to see how the serialization occurs, but I am guessing it will merely assume "Local" and serialize as is. So one might not get the backup at the time expected, but that's from not sending the correct time.

I don't think the library has too many other DateTime uses, best to see if we've already applied a check like that, or just forcing UTC conversion always (probably the best result).

nicholi avatar Jul 06 '21 21:07 nicholi

I think if we can point to public documentation mentioning this very important bit, it absolutely makes sense.

IIRC I couldn't find any documentation regarding this. I got clarity after talking to them for quite a while via support tickets.

However I've found non-documented "features" like these tend to just as easily change in the future. Maybe they will support both upper/lowercase, and then we'd have to change back anyways. Barring any actual documentation from DO on this, perhaps best to add it into the function's documentation notes.

I agree with you on this. +1 to add it to the function's notes.

I see this more as developer error, you should always specify your timezone for DateTimes.

Righto. Throwing an argument exception would be a good way to account for all those times where this isn't done?

As unlike point #1 this doesn't result in the request failing, does it?

IIRC it does with the same unprocessable_entity error. But its been a while and I don't exactly 100% remember if it does.

I'd have to check to see how the serialization occurs, but I am guessing it will merely assume "Local" and serialize as is. So one might not get the backup at the time expected, but that's from not sending the correct time.

Maybe because if a Kind isn't specified, the default is "Unspecified" which doesn't add a timezone marker to what is expected to be a ISO8601 timestamp? Here's json.net's deserialization:

image

shrayasr avatar Jul 08 '21 10:07 shrayasr