Sketch data-plugin with real API endpoints

Sketch data-plugin with real API endpoints

Objective

As designers, 'forging' data is just part of the job, whether its lorem-ipsem (please stop doing that!) or somewhat realistic data coming from the existing application. But wouldn't it be better and more realistic to use production or development level APIs usually available to the software team directly within the designs?

Content informs design decisions – and helps you convey your purpose

Data are relentless – so digital products must be designed for robustness

It's fun 🎉 – seeing your design evolve with meaningful data is motivating and rewarding

Existing Solutions

  1. Pre-filled JSON files - weak alternative since it provides persistency however still forged in a way.
  2. Sketch-Data-Faker - DataProvider that provides a large amount of fake data from Faker.js, same problem ... its forged / fake.
  3. Data-Populator - Probably the most updated and best existing solution using 'handlebars' and quite comprehensive, however personally i've found it not very persistent for my use-case ... also woulda been nice to have this support native sketch DataProvider

Architecture

Dependencies
1.  Sketch
2.  NPM / NodeJS
3.  SKPM (Sketch Plug-in Manager)
4.   CocoaScript (JS -> Objective-C Wrapper)

Sketch's DataProvider Handlers
So each type of Data Model has its set of handlers or functions which:
1.  Request data from an api endpoint
2.  Manipulate the data-set if required
3.  Fill it in the appropriate text layer or text override

For this example, let's assume we have this model:
Application
And it has several properties:
Name
Response Time
Error Rate

Note that this is specific the 'Application Performance Monitoring' industry

Let's first create the boilerplate with the help of skpm:

skpm create my-data-provider-plugin

Update the manifest.json to make sure its a dataprovider plugin (Full manifest shown for reference)

{
  "version": "1.0.0",
  "compatibleVersion": 52,
  "bundleVersion": 1,
  "icon": "icon.png",
  "author": "ShyGuy",
  "description": "Data provider plugin to bring consistency to designs ;)",
  "suppliesData": true,
  "commands": [
    {
      "script": "index.js",
      "handlers": {
        "actions": {
          "Startup": "onStartup",
          "Shutdown": "onShutdown",
          "SupplyApplications": "onSupplyApplications"
        }
      }
    }
  ]
}

Now for each 'command' we need a equal handler in index.js as follows:

export function onStartup () {
  dataMapping.forEach(d => {
    DataSupplier.registerDataSupplier('public.text', d.displayName, d.handler)
  })
}

export function onShutdown () {
  // Deregister the plugin
  DataSupplier.deregisterDataSuppliers()
}

export function onSupplyApplications (context) {
  let dataKey = context.data.key;
  let wrappedItems = util.toArray(context.data.items).map(sketch.fromNative);
  UI.message('Fetching application names from API');

  setValuesToLoading(wrappedItems);

  getApplications()
    .then(apps => {
      const minApps = getMinArray(apps).map(app => app.name);
      wrappedItems.forEach((wi, index) => {
        DataSupplier.supplyDataAtIndex(dataKey, getTruncatedText(wi, minApps[index]), index)
      })
    })
    .then(() => { UI.message('Success!') })
    .catch(err => { UI.message(err) })
}

Let's also take a look at dataMapping which is essentially telling Sketch to register these functions as data suppliers:

export const dataMapping = [
  // use '_' for nested data menu in sketch
  {
    displayName: 'application_application-name',
    handler: 'SupplyApplications'
  }
];

And finally, the getApplications() api call function:

const { getApiUrl } = require('../api.js');

export async function getApplications () {
	const api = getApiUrl('applications', null);
	return await fetch(api.url, {
        headers: api.headers
    }).then(response => {
        return response.json()._value.slice(0,500);
    }).catch(error => {
        console.log(error)
    });
}

What does this look like in sketch?

This is showing a ton more, but you get the idea of how it goes ...

And then this type of behavior can be used for almost any endpoint and data-set!
For overrides or directly on any text layer

Truncation and Number Formatter

Will cover soon!

Show Comments