admin管理员组

文章数量:1355528

I'm relatively new to Javascript and Node and I like to learn by doing, but my lack of awareness of Javascript design patterns makes me wary of trying to reinvent the wheel, I'd like to know from the munity if what I want to do is already present in some form or another, I'm not looking for specific code for the example below, just a nudge in the right direction and what I should be searching for.

I basically want to create my own private IFTTT/Zapier for plugging data from one API to another.

I'm using the node module request to GET data from one API and then POST to another.

request supports streaming to do neat things like this:

request.get('')
  .pipe(request.put(''));

In between those two requests, I'd like to pipe the JSON through a transform, cherry picking the key/value pairs that I need and changing the keys to what the destination API is expecting.

request.get('')
  .pipe(apiToApi2Map)
  .pipe(request.put(''));

Here's a JSON sample from the source API:

And this is what I'd like to send forward:

The transformed JSON in this case takes the keys from the value of each objects "attribute" key and the value from each objects "value" key.

So my questions:

  • Is there a framework, library or module that will make the transform step easier?

  • Is streaming the way I should be approaching this? It seems like an elegant way to do it, as I've created some Javascript wrapper functions with request to easily access API methods, I just need to figure out the middle step.

  • Would it be possible to create "templates" or "maps" for these transforms? Say I want to change the source or destination API, it would be nice to create a new file that maps the source to destination key/values required.

Hope the munity can help and I'm open to any and all suggestions! :) This is an Open Source project I'm working on, so if anyone would like to get involved, just get in touch.

I'm relatively new to Javascript and Node and I like to learn by doing, but my lack of awareness of Javascript design patterns makes me wary of trying to reinvent the wheel, I'd like to know from the munity if what I want to do is already present in some form or another, I'm not looking for specific code for the example below, just a nudge in the right direction and what I should be searching for.

I basically want to create my own private IFTTT/Zapier for plugging data from one API to another.

I'm using the node module request to GET data from one API and then POST to another.

request supports streaming to do neat things like this:

request.get('http://example./api')
  .pipe(request.put('http://example./api2'));

In between those two requests, I'd like to pipe the JSON through a transform, cherry picking the key/value pairs that I need and changing the keys to what the destination API is expecting.

request.get('http://example./api')
  .pipe(apiToApi2Map)
  .pipe(request.put('http://example./api2'));

Here's a JSON sample from the source API: http://pastebin./iKYTJCYk

And this is what I'd like to send forward: http://pastebin./133RhSJT

The transformed JSON in this case takes the keys from the value of each objects "attribute" key and the value from each objects "value" key.

So my questions:

  • Is there a framework, library or module that will make the transform step easier?

  • Is streaming the way I should be approaching this? It seems like an elegant way to do it, as I've created some Javascript wrapper functions with request to easily access API methods, I just need to figure out the middle step.

  • Would it be possible to create "templates" or "maps" for these transforms? Say I want to change the source or destination API, it would be nice to create a new file that maps the source to destination key/values required.

Hope the munity can help and I'm open to any and all suggestions! :) This is an Open Source project I'm working on, so if anyone would like to get involved, just get in touch.

Share Improve this question asked May 14, 2015 at 15:45 greglgomezgreglgomez 431 silver badge3 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

Yes you're definitely on the right track. There are two stream libs I would point you towards, through which makes it easier to define your own streams, and JSONStream which helps to convert a binary stream (like what you get from request.get) into a stream of parsed JSON documents. Here's an example using both of those to get you started:

var through = require('through');
var request = require('request');
var JSONStream = require('JSONStream');
var _ = require('underscore');

// Our function(doc) here will get called to handle each
// ining document int he attributes array of the JSON stream
var transformer = through(function(doc) {
    var steps = _.findWhere(doc.items, {
        label: "Steps"
    });
    var activeMinutes = _.findWhere(doc.items, {
        label: "Active minutes"
    });
    var stepsGoal = _.findWhere(doc.items, {
        label: "Steps goal"
    });

    // Push the transformed document into the outgoing stream
    this.queue({
        steps: steps.value,
        activeMinutes: activeMinutes.value,
        stepsGoal: stepsGoal.value
    });
});

request
    .get('http://example./api')
    // The attributes.* here will split the JSON stream into chunks
    // where each chunk is an element of the array
    .pipe(JSONStream.parse('attributes.*'))
    .pipe(transformer)
    .pipe(request.put('http://example./api2'));

As Andrew pointed out there's through or event-stream, however I made something even easier to use, scramjet. It works the same way as through, but it's API is nearly identical to Arrays, so you can use map and filter methods easily.

The code for your example would be:

DataStream
   .pipeline(
       request.get('http://example./api'),
       JSONStream.parse('attributes.items.*')
   )
   .filter((item) => item.attibute)  // filter out ones without attribute
   .reduce((acc, item) => {
       acc[item.attribute] = item.value;
       return acc;
   .then((result) => request.put('http://example./api2', result))
;

I guess this is a little easier to use - however in this example you do accumulate the data into an object - so if the JSON's are actually much longer than this, you may want to turn it back into a JSONStream again.

本文标签: javascriptTransforming JSON in a node stream with a map or templateStack Overflow