How to add beacon attachment programmatically with SWIFT?

#1

Hello! I am trying to add and delete beacon attachments via an Admin App that I have created. What is the best way to do this?

Thank you!

#2

It’s a slightly-annoying, multi-step process at the moment:

First, some theory: each beacon (e.g., ID “24657e878b4c1167862965f49f74092c”) may or may not have exactly one “attachment”, which is an object that looks like this:

 "id": 1,
 "created_at": "2017-10-06 14:24:00",
 "updated_at": "2017-10-06 14:24:00",
 "payload": {
   "key1": "123",
   "key2": "text"
 },
 "for": "device",
 "identifier": "24657e878b4c1167862965f49f74092c"

This example object is an attachment with its own ID (1), and two key-value pairs (key1 and key2).

With that in mind, there’s a few endpoints here:

  1. https://cloud.estimote.com/docs/#api-Attachments-CreateAttachment, which creates a new attachments for a particular beacon. This endpoint will fail (HTTP 400 Bad Request) if an attachment already exists for that beacon. So if you want to update an existing attachment, you need to use…

  2. https://cloud.estimote.com/docs/#api-Attachments-UpdateAttachmentPayload. Note that to use this endpoint, you (a) need to know the attachment’s ID, not the beacon ID.

    Also, this endpoint overwrites all the key-value pairs. So if you already have “key1” and “key2”, and want to append “key3”, you need to (b) include all three in the update request.

    Because of (a) and (b), another endpoint to talk about is …

  3. https://cloud.estimote.com/docs/#api-Attachments-GetAttachments, which allows you to get an existing attachment for a particular beacon (or beacons), e.g., GET /v3/attachments?for=device&identifiers=["BEACON_ID"]. This will include the attachment’s ID, and the attachment’s payload (= key/value pairs).

With THAT in mind, the general process of adding a new key-value to a beacon could be something like this:

  1. Use #3 (GetAttachments) to try to obtain an existing attachment for a given beacon.
  2. If GetAttachments returns no results, use #1 (CreateAttachment) to create a fresh attachment. The end.
  3. If GetAttachments succeeds, note down the attachment ID and the current payload. Add your new key-value pair to the payload. (Or if you want to remove a key-value pair, remove it from the payload.)
  4. Use #2 (UpdateAttachmentPayload) to overwrite the key-value pairs with the new payload from the previous step. You’ll also need to use the attachment ID here, also obtained in the previous step.

Here’s my Node.js code I’ve been using, could be a starting point for writing equivalent Swift code:

const request = require('request-promise-native');

const getAttachment = (req, deviceIdentifier) => {
  return req({
    method: 'GET',
    url: '/v3/attachments',
    qs: {identifiers: deviceIdentifier},
  });
};

const createAttachment = (req, deviceIdentifier, payload) => {
  return req({
    method: 'POST',
    url: '/v3/attachments',
    body: {
      data: {
        payload: payload,
        identifier: deviceIdentifier,
        for: 'device'
      }
    }
  });
};

const updateAttachment = (req, attachmentId, payload) => {
  return req({
    method: 'PATCH',
    url: `/v3/attachments/${attachmentId}`,
    body: {
      data: {
        payload: payload
      }
    }
  });
};

const addKeyValuesToBeacon = (appId, appToken, deviceIdentifier, keyValues) => {
  const req = request.defaults({
    baseUrl: 'https://cloud.estimote.com',
    json: true,
    auth: {user: appId, pass: appToken}
  });

  return getAttachment(req, deviceIdentifier).then((result) => {
    if (result.meta.total == 0) {
      return createAttachment(req, deviceIdentifier, keyValues);
    } else {
      const attachmentId = result.data[0].id;
      const currentKeyValues = result.data[0].payload;

      // merge keyValues into the currentKeyValues (overwriting if there's conflicts)
      const newKeyValues = Object.assign(currentKeyValues, keyValues);

      return updateAttachment(req, attachmentId, newKeyValues);
    }
  });
};