On demand request for external services

Can I create a method that will call on demand from the strapi project to get the data from external services?
Basically, I need to call a method when I route to some collection. This method will call the external source using Axios to get data from it.

Hi Sunnyson,

I didn’t understand your solution much.
But I have a requirement where I will use my local version link to call some route path, which will make call to external source which is being passed as a parameter in the link.

Basically, I want the steps that needs to be followed to accomplish my goal.

Oh, Got it. I got a bit confusing. My bad. So actually you want to make a route like this and pass a parameter with url?
http://localhost:1337/api/example?link=https://externalsource.com/api
And it should retrieve data from that url and add it to your collection type?

Create the controller (/controllers/controllerName.js)

const axios = require('axios');
module.exports = {
  async index(ctx) {
    let { link } = ctx.query;
    let { data } = await axios.get(link);
    //process data here and map it.
    await strapi.query('someCollection').create(data);
    return data;
  }
}

Create the route (/config/routes.json) and add the created controller function to handler

[
    {
      "method": "GET",
      "path": "/example",
      "handler": "controllerName.index",
      "config": {
        "policies": []
      }
    }
]

Now when you will send a request to http://localhost:1337/api/example?link=https://externalsource.com/api it will get the data from that source and store it in db.

Hi Sunnyson,

Thanks for the response. I understand everything in this code.
But I have to create a api path like http://localhost:1337?collection={collectionName}&extsrc={externalSourceLink/Name}.
So, Is it possible to create a query like this and get the collection data using {collectionName} and {externalSourceLink/Name}.

For your example, the code will look like this:

Create the controller (/controllers/controllerName .js)

const axios = require('axios');
module.exports = {
  async index(ctx) {
    let { collection, extsrc } = ctx.query;

    //hard-coding collection types, to avoid calls to inexistent collection, 
    //also you can write a function to retrieve the collectionTypes dynamically.

    let allowedCollectionTypes = ['collectionType1','collectionType2','collectionType3'];
    if (!allowedCollectionTypes .includes(collection)) {
      return {
        status: 'error',
        message: `<${collection}> type is not Pre-configured in the API. Please add it to allowedCollectionTypes. `,
      };
    }
    
    //fetching data from external source
    let { data } = await axios.get(extsrc);

    //you can add a service with multiple functions in it for each collectionType.
    //example: 
    await strapi.services.storeDataFromExtSrc[collection](data);

    return {
        status:'ok',
        message: `Data stored successfully in ${collection}`
    };
  }
}

In the service file (/services/storeDataFromExtSrc.js) create functions for each collectionType

module.exports = {
    collectionType1: async (data) => {    
         //some mapping/validations here for collectionType1, maybe it has different fields and etc.
         await strapi.query(collectionType1).create(data);
    },
    collectionType2: async (data) => {
         //some mapping/validations here for collectionType2, maybe it has different fields and etc.
         await strapi.query(collectionType2).create(data);
    },
    collectionType3: async (data) => {
         //some mapping/validations here for collectionType3, maybe it has different fields and etc.
         await strapi.query(collectionType3).create(data);
    }
}

Hi Sunnyson,

Thanks for the response.
Can we create a global routing. And can we also create global controller for the global routing handler?
Basically, I don’t want to navigate to any controller written inside ./api/{collectionName}/controller.
I just want to navigate based on custom routing that will call the collections to get the data.

Of course you can make a global route, just generate a new API using CLI:

strapi generate:api extsrc

Now navigate inside it to /extsrc/config/routes.json and change the default to “/”.

{
 "method": "GET",
 "path": "/",
 "handler": "extsrc.process",
 "config": {
   "policies": []
  }
 }

Now it will be accessible on http://localhost:1337?collection={collectionName}&extsrc={externalSourceLink/Name}. But make sure that you don’t have other routes that also have root path “/”.

In controller: /extsrc/controller/extsrc.js and /extsrc/services/extsrc.js: Write the logic I described in previous response.