Skip to content

Uploading Attachments

realVinayak edited this page May 24, 2023 · 5 revisions

Uploading Attachments via API

The below steps are followed to upload attachments. It is assumed that collection object attachments are being created for a new collection object resource. At the end, the additionally steps required to create an attachment for an existing resource are mentioned. Code snippets for Node.js are provided.

Additionally, it is assumed that authentication cookie has been obtained as described in API Documentation Demo

Step 1 - Getting asset specifics from the backend

Before a file is uploaded to the asset server, specify generated token and attachmentlocation that defines specs of the upload to the asset server are needed. To generate this, use the attachment_gw/get_upload_params/ endpoint which takes in the filename as a query parameter and returns the token and attachmentlocation.

The code snippet:

const {attachmentlocation, token} = await fetch("http://localhost/attachment_gw/get_upload_params/?filename=FILENAME", {
    "headers": {
      "accept": "application/json",
      "accept-language": "en-US,en",
      "sec-ch-ua": "\"Brave\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"",
      "sec-ch-ua-mobile": "?0",
      "sec-ch-ua-platform": "\"Windows\"",
      "sec-fetch-dest": "empty",
      "sec-fetch-mode": "cors",
      "sec-fetch-site": "same-origin",
      "sec-gpc": "1",
      "cookie": COOKIE,
      "Referer": "http://localhost/specify/view/collectionobject/new/",
      "Referrer-Policy": "strict-origin-when-cross-origin"
    },
    "body": null,
    "method": "GET"
  }).then((response)=>response.json());

Step 2 - Uploading file to the asset server

Next, the file is POSTed to the asset server as formData. To do so, formData instance needs to be created with some specific specs. Node.js provides external library form-data which can be used along with fetch as:

var FormData = require('form-data');
var fs = require('fs');

var formData = new FormData();
formData.append('file', FILENAME);
formData.append('token', token);
formData.append('store', attachmentlocation);
formData.append('type', 'O');
formData.append('coll', COLLECTION);

await fetch("http://ASSET_SERVER_URL/fileupload", {
    "headers": "POST",
    "body": formData
})

Step 3 - Making an attachment resource.

Define a new attachment resources using the following JSON format:

const attachmentResource0 = {
    "ordinal": 0,
    "attachment": {
        "attachmentlocation": attachmentlocation,
        "mimetype": mimeType,
        "origfilename": FILENAME,
        "title": FILENAME,
        "ispublic": true,
        "tableid": TABLEID 
    }
}

Step 4 - Post request for collection object

Define a Collection Object Resource with collectionobjectattachments as an array of attachments JSON defined previously. For example, if a new collection object is created with one collection object attachment, then the final JSON representation of collection object will look like:

const collectionobjectResource = {
    "collection": "/api/specify/collection/4/",
    "catalognumber": "#########",
    "altcatalognumber": null,
    "cataloger": "/api/specify/agent/1514/",
    "reservedtext": null,
    "text2": null,
    "guid": null,
    "determinations": [],
    "preparations": [],
    "collectionobjectattachments": [attachmentResource0],
    "dnasequences": [],
    "collectionobjectcitations": []
}

POSTing this JSON to /api/specify/collectionobject/ as following will create a new collection object with one new attachment.

await fetch("http://localhost/api/specify/collectionobject/", {
  "headers": {
    "accept": "application/json",
    "accept-language": "en-US,en",
    "content-type": "application/json",
    "sec-ch-ua": "\"Brave\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "sec-gpc": "1",
    "x-csrftoken": CSRFTOKEN,
    "cookie": COOKIE,
    "Referer": "http://localhost/specify/view/collectionobject/new/",
    "Referrer-Policy": "strict-origin-when-cross-origin"
  },
  "body": JSON.stringify(collectionobjectResource),
  "method": "POST"
});

If more than one attachment needs to created for a new collection object (say 3), then follow steps 1 through 3 to get three new attachment resources attachmentResource0, attachmentResource1, attachmentResource2 and the new collectionobject resource will then be:

const collectionobjectResourceMultipleAttachments = {
    "collection": "/api/specify/collection/4/",
    "catalognumber": "#########",
    "altcatalognumber": null,
    "cataloger": "/api/specify/agent/1514/",
    "reservedtext": null,
    "text2": null,
    "guid": null,
    "determinations": [],
    "preparations": [],
    "collectionobjectattachments": [attachmentResource0, attachmentResource1, attachmentResource2],
    "dnasequences": [],
    "collectionobjectcitations": []
}

POSTind this resource similar to before will create a new collection object with three new attachments.

Attachments to existing resources:

If the attachments need to be created for an existing resource, fetch that resource first using the /api/specify/{table}/{id} endpoint and then append new attachments (after step 3) to the {table}attachments list, and then PUT this resource