/uploads API response different?

The API response from the uploads endpoint seems to have changed. It’s no longer responding with the response documented here

POST /uploads - Expected response:

{
  "data": {
    "type": "upload",
    "id": "666",
    "attributes": {
      "size": 444,
      "width": 30,
      "height": 30,
      "path": "/205/1565776891-image.png",
      "url": "https://www.datocms-assets.com/205/1565776891-image.png",
      "basename": "image",
      "format": "jpg",
      "alt": "Nyan the cat",
      "title": "My cat",
      "is_image": true,
      "author": "Mark",
      "copyright": "2020 DatoCMS",
      "default_field_metadata": {
        "en": {
          "alt": "Nyan the cat",
          "title": "My cat",
          "custom_data": {}
        }
      }
    }
  }
}

We’re receiving this as a response now:

{"data":{"id":"facf9248be977002c9bae231","type":"job"}}

hello @james sorry for this.

Yes, we have just released a new version of the API. Tomorrow we’ll send out a detailed report of what’s going on.

In your case you’ve been returned an async job, have a look here: https://www.datocms.com/docs/content-management-api/resources/job-result for more details.

Meanwhile if you can use one of our clients (JS: https://github.com/datocms/js-datocms-client/ or Ruby: https://github.com/datocms/ruby-datocms-client ) they should take care of everything for you.

Anyway, I’ll update this topic as soon as we have some docs available (likely tomorrow).

Thanks for the quick response! Much appreciated. :+1:

Unfortunately stuck using Python for this particular integration.

Is it possible to get a heads up in the event of similar changes in the future? Just so we’re not scrambling to fix. :grimacing:

Hi @james! We had a bunch of long standing image-related requests from our users:

This week we’re happy to announce we finally shipped a solution to all of these issues!

To do that, we had to make some non-backward compatible changes to our Content Management API (ouch!). For this reason we released version 3 of the API.

To avoid breaking everything on previous projects, CMA v1 and v2 still work, but only when you read data, not if you try to create/update records and assets.

I’ll try to cover every change in the next paragraphs :slight_smile:

What changed in Content Management API

Alt and title moved from assets into records

First of all, in CMA v2, this was the response of a GET /uploads/:id request:

GET https://site-api.datocms.com/uploads/777
X-Api-Version: 2

{
  "data": {
    "id": "777",
    "type": "upload",
    "attributes": {
      "path": "/342/813924224-my-image.png",
      ...
      "alt": "This is the alternate text",
      "title": "This is the title",
    }
  }
}

And this was the response of a GET /items/:id request, with a record that contains a file field, pointing to the same asset:

GET https://site-api.datocms.com/uploads/555
X-Api-Version: 2
{
  "data": {
    "id": "555",
    "type": "item",
    "attributes": {
      "title": "My awesome blog post",
      "cover_image": "777"
    },
    "relationships": {
      "item_type": { "data": { "id": "83", "type": "item_type" } }
    }
  }
}

So, as you can see, the asset was the one with alt and title, and a record field simply referenced the ID of an existing upload.

To customise alt and title based on the specific context of a single record, we clearly needed to move alt and title on the record level. But we also wanted to specify a (localised) default alt and title at the asset level!

So here’s how the same requests look on CMA v3:

GET https://site-api.datocms.com/uploads/777
X-Api-Version: 3

{
  "data": {
    "id": "777",
    "type": "upload",
    "attributes": {
      "path": "/342/813924224-my-image.png",
      ...
      "default_field_metadata": {
        "en": {
          "alt": "This is the alternate text",
          "title": "This is the title",
          "custom_data": {}
        },
        "it": {
          "alt": "Qui c'è il testo alternativo",
          "title": "Qui abbiamo il titolo",
          "custom_data": {}
        }
      }
    }
  }
}
GET https://site-api.datocms.com/uploads/555
X-Api-Version: 3

{
  "data": {
    "id": "555",
    "type": "item",
    "attributes": {
      "title": "My awesome blog post",
      "cover_image": {
        "upload_id": "777",
        "alt": "I want to overwrite alt in this particular record!",
        "title": null,
        "custom_data": {}
      }
    },
    "relationships": {
      "item_type": { "data": { "id": "83", "type": "item_type" } }
    }
  }
}

As you can see, assets "default_field_metadata" field is were you store, duh, the default metadata for the asset, while at the record’s level we’ve replaced the raw asset ID with an hash, so that you can overwrite the default values.

Furthermore, you now have a custom_data field both at the asset and record level, where you can store whatever you want!

Creating/updating an asset might return an asynchronous job

First let’s quickly recap whats the procedure to upload a new asset to DatoCMS:

  1. Send a POST request to the /upload-requests endpoint, to retrieve an AWS signed URL;
  2. Use the obtained URL to perform a PUT request directly to AWS, uploading the raw content of the file as the payload;
  3. Make a POST request to the /uploads endpoint with the upload path.

You might have never done these three steps manually, as our clients implement a much simpler interface… but they’re there nonetheless, and they help us making the uploading process super fast, as DatoCMS doesn’t need to be a middleman between you (the user) and AWS.

In v2 (and v1) the response of a POST /uploads request instantly returned the newly created asset. And v3 keeps on doing that, most of the time. But since you (or your API client) are in charge of performing the upload, something might go slightly wrong. For example, you can forget to set a proper Content-Type header in the PUT request to AWS. In this case, some browsers might refuse to load it. Ouch.

So what changed in v3? If we detect that the uploaded image needs to be fixed, we do that ourself. But it might take some time to do that (maybe the image is 60MB!), and we don’t want to have the CMA request hanging around for such a long time!

So in these cases, the POST /uploads will not return the upload, but an asynchronous job:

{
  "data": {
    "type": "job",
    "id": "facf9248be977002c9bae231"
  }
}

You can then check the status of the job calling the GET /job-results/:id endpoint. When the job is done, the status of the request will be 200, and you’ll get the result of the operation:

GET /job-results/facf9248be977002c9bae231
X-Api-Version: 3

{
  "data": {
    "type": "job-result",
    "id": "facf9248be977002c9bae231",
    "attributes": {
      "status": 200,
      "payload": {
        "id": "777",
        "type": "upload",
        "attributes": {
          "path": "/342/813924224-my-image.png",
          ...
        }
      }
    }
  }
}

The same applies also to PUT /uploads. If you ask us to rename the asset, or you want to completely replace the asset, we might return you an asynchronous job instead of the final result.

Our API Clients already support CMA v3!

If you’re using the latest versions of our Js or Ruby, we handle everything for you, so this still works as usual:

const { SiteClient } = require("datocms-client").SiteClient;
const client = new SiteClient("YOUR-API-KEY");

// upload using URL:

client
  .uploadFile("http://i.giphy.com/NXOF5rlaSXdAc.gif")
  .then(result => console.log(result))
  .catch(error => console.log(error));

But if you’re performing manual requests, well. Here’s how it works :slight_smile:

2 Likes