Reputation: 599
I'm using Axios / promises to make AJAX requests, but the structure is a bit confusing. Basically I want this to happen:
masterlist.xml
.category.xml
.manifest.xml
and parse data.Example structure:
masterlist.xml
<master>
<category>action</category>
<category>romance</category>
</master>
Category XMLs (e.g. action.xml and romance.xml)
<manifestUrls>
<manifest>foo/bar/manifest.xml</manifest>
<manifest>alice/bob/manifest.xml</manifest>
<manifest>hello/world/manifest.xml</manifest>
</manifestUrls>
Manifest XMLs
<manifest>
<data>Blah blah blah</data>
<manifest>
I'm a bit stuck on how to structure this as an Axios request with then
. I'd like to have three functions, getMaster()
, getCategory(url)
, and getManifest(url)
that are preferably independent (e.g. getMaster
doesn't have to call getCategory
directly), but it seems like it might be necessary.
How would this be structured in Axios?
Upvotes: 1
Views: 288
Reputation: 101738
One of the main benefits of promises is that they allow you to easily avoid interdependence between your methods.
Here is a rough outline of how you could do this.
// put it all together
getMaster()
.then(parseMaster)
.then(function (categories) {
return Promise.all(categories.map(getAndParseCategory));
})
.then(flatten) // the previous then() resolves to an array-of-arrays
.then(function (manifestUrls) {
return Promise.all(manifestUrls.map(getManifest));
})
.then(function (manifests) {
// manifests is an array of all manifests
});
// Examples of what each of the functions used above would do
function getMaster() {
return axios.get('masterUrl')
.then(function (response) { return response.data; });
}
function parseMaster(masterContent) {
// parse and return an array of categories
}
function getCategory(name) {
var url = // ... build the URL based on the name
return axios.get(url)
.then(function (response) { return response.data; });
}
function parseCategory(categoryContent) {
// parse and return an array of URLs synchronously for one category
}
function getAndParseCategory(name) {
return getCategory(name).then(parseCategory);
}
function getManifest(url) {
return axios.get(url)
.then(function (response) { return response.data; });
}
function flatten(arrayOfArrays) {
return [].concat.apply([], arrayOfArrays);
}
If you're using Bluebird or something else that gives promises a .map()
method, then you can tidy that pipeline up a bit:
// using Promise.resolve() at the beginning to ensure
// the chain is based of the desired kind of promise
Promise.resolve()
.then(getMaster)
.then(parseMaster)
.map(getCategory)
.map(parseCategory)
.then(flatten) // previous line resolves to an array-of-arrays
.map(getManifest)
.then(function (manifests) {
// manifests is an array of all manifests
});
Of course, you could also define your own .map
method if you don't want to import a whole third party promise library:
if (!Promise.prototype.map) {
Promise.prototype.map = function (func) {
return this.then(function (result) {
return Promise.all(result.map(func));
});
};
}
Edit: To respond to your question in the comments below. If you wanted to pass the category text along so that it could be included in the manifest URLs, I think a clean way to do this would be to include that in the data returned from getCategory()
so that parseCategory
can make use of it. Everything else could stay the same.
Example:
function getCategory(name) {
var url = // ... build the URL based on the name
return axios.get(url)
.then(function (response) {
return {
name: name,
data: response.data
};
});
}
function parseCategory(categoryContent) {
var urls = // parse URLs from categoryContent.data
return urls.map(function (url) {
return categoryContent.name + '/' + url;
});
}
Upvotes: 3