npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sketch-fetch

v0.0.13

Published

Util library for sketch plugins handeling async HTTP requests

Downloads

43

Readme

sketch-fetch

NPM version

Util library for sketch plugins handling async HTTP requests

NOTE: This library is still very experimental, and ideally the API will completely change. However, to get things going, I encourage everyone to think about solutions for the problems described below, as well as play with and use this package, you should use it on a fixed version though, for your own sanity, in the very likely case of braking changes in the API 😉

The problem

In Sketch plugins we are not within a browser environment, so the usual AJAX libraries like fetch don't work. However, I really like the syntax and easy usage of such libraries, and I'd like to be able to make HTTP Requests in Sketch plugins (or any other cocoascript project really) just as easy as in the browser.

The problem is, that asynchronous requests run on different threads, and therefore we loose the current application context when we get the HTTP Response.

I am working on ideas around that, not really successful as of now, so there is a current and an ideal solution to this problem.

Current usage

Under the hood this libtary is just an abstraction of NSMutableURLRequest that gets executed using NSURLSession's method:

[session dataTaskWithRequest:NSMutableURLRequest completionHandler:Block]

The first currrent problem is that cocoascript doesn't allow you to define blocks (ObjC's equivalent to closures), so there is currently the need for an ObjC framework to be loaded to be able to use this library.

Also, due to the context issues described above, the workflow of asynchronous HTTP requests is not as intuitive as I hope it will be in the end just yet.

1. Load the framework

Either copy the framework files into your project or use the util function provided in your node build process, like so:

var fetch = require('sketch-fetch/lib/node');
fetch.copyFrameworks(targetPath);

Then you have to load the framework before any of your requests, so to make sure this happens just include this snippet in your plugin in the beginning of every call of your plugin.js file:

import { FetchCore } from 'sketch-fetch';

function initWithContext (context) {
  FetchCore.initWithContext(context);
  // Do your stuff...
}

function myAwesomePluginEndpoint (context) {
  initWithContext(context);
  // Do whatever your plugin should do...
}

It is good practise in general to have such an initWithContext method to be able to prepare your context for every initiation of a Sketch instance / new thread.

2. Do your requests

This is as simple as this:

import fetch from 'sketch-fetch';

const options = { /* See available options */ };
fetch('https://awesome.url', options);

3. Handle the response

You currently need to define a plugin entrypoint to be able to handle the responses. You can do that as follows:

import { handleResponses } from 'sketch-fetch';

function handleHttpResponse (context) {
  initWithContext(context);
  handleResponses((callback, response) => {
    switch (callback) {
      case 'myCallback.ALWAYS':
        // Do something...
      break;
      default:
        log('ERROR: Callback unknown');
      break;
    }
  });
}

For every key (in this case myCallback), there will be two responses fired, one for [KEY].ALWAYS, and the other one [KEY].SUCCESS or [KEY].FAILURE, depending on the response.

The entry point handleHttpResponse as of now has to be manually mapped into your manifest.json, handleHttpResponse being both handler and identifier.

Bringing it all together

import fetch, { FetchCore, handleResponses } from 'sketch-fetch';

function initWithContext (context) {
  FetchCore.initWithContext(context);
  // Do your stuff...
}

function myAwesomePluginEndpoint (context) {
  initWithContext(context);
    
  // Fetch data from url
  const options = {
    callback: 'myCallback',
    // See available options...
  };
  fetch('https://awesome.url', options);
}

function handleHttpResponse (context) {
  initWithContext(context);
  handleResponses((callback, response) => {
    switch (callback) {
      case 'myCallback.SUCCESS':
        // Do something...
      break;
      default:
        log('ERROR: Callback unknown');
      break;
    }
  });
}

Available options

{
  callback: 'something', // string, identifier for the response handling
  headers: {}, // object, key value pairs for the request header
  args: {}, // object, key value pairs for normal string parameters
  files: { // object, file paths to be sent (for any request type but GET)
    varName: 'filepath'
  },
  method: 'GET', //string, GET|POST|PUT|DELETE|..., default is GET
}

The ideal world

This is all still not ideal. In a perfect world, we could handle requests just like we can with fetch in a browser environment, like so:

import fetch from 'sketch-fetch';

fetch(url, options)
  .then(json => {
    // Do something
  })
  .catch(() => {
    // Handle any errors
  })
  .send(); // we would need that, cause we need to define the callbacks before we actually send the request...

The only problem with this is that we loose the current context. We could save (a serialized version of) the callbacks on the main thread and retrieve these on response, but we would need to make sure that all contexts will be saved and retrieved as well, such as already imported helper functions or other external libraries...

I am currently working on some ideas for that and will update this repo when I find something worth sharing 😊