lingar
lingar

Reputation: 613

Global Services of getting data from server in React

I have some data services that I want to add to my app. I want those services will be accessible to use in few components and to avoid the need to rewrite "fetch functions" in each component. After some research about getting data from server, and asynchronous call behavior (like here ) I realize that there is not easy way to return data from those call, and the only way is to do the dependent execution is inside the callbacks.

So I get this solution- This work well, but my question is: Is it problematic solution ?

DataServices:

 static getDataTry2  (path, obj)  {

     fetch(path)
     .then(myResponse => myResponse.json())
     .then(arrivedData => {
       console.log("the arrived data ", arrivedData)
       obj.setState({
         try1 : arrivedData
       });

     });
   }


my other component:

componentDidMount() {

        DataServices.getDataTry2("ws/getEvents", this);


    }

Upvotes: 1

Views: 1154

Answers (3)

lakjeewa Wijebandara
lakjeewa Wijebandara

Reputation: 562

A solution with typescript,

interface HTTP_METHODS {
      POST: string;
      PUT: string;
      GET: string;
      DELETE: string;
    }

const HTTP_METHOD: HTTP_METHODS = {
  POST: 'POST',
  PUT: 'PUT',
  GET: 'GET',
  DELETE: 'DELETE',
};

const createHeaders = (headers: any) => {
  let commonHeaders = {
    ...headers,
    'Content-Type': 'application/json',
  };

  return commonHeaders;
};

const create = async (method: string, url: string, body?: any, headers?: any) => {
  return await fetch(url, {
    method: method,
    headers: createHeaders(headers),
    body: JSON.stringify(body),
  });
};

const API = {
  create,
  HTTP_METHOD,
};

export default API;

Then you can call,

import API from '../../services/api';
const resultRawTest = await API.create(API.HTTP_METHOD.GET,"https://reqres.in/api/unknown");

const resultTest = await resultRawTest.json();

console.log(" resultTestresultTest ", resultTest);

Upvotes: 0

Mosè Raguzzini
Mosè Raguzzini

Reputation: 15851

Make a request abstraction is a standard solution but for separation of concerns, your service should be able to make requests but it should return a promise that will be managed by the caller.

Usually the request abstraction manages also 400/401 errors (for refresh tokens/logout) but is agnostic about the logic of the caller.

This is how look like a common abstraction:

 /**
 * Parses the JSON returned by a network request
 *
 * @param  {object} response A response from a network request
 *
 * @return {object}          The parsed JSON from the request
 */
function parseJSON(response) {
  if (response.status === 204 || response.status === 205) {
    return null;
  }
  return response.json();
}

/**
 * Checks if a network request came back fine, and throws an error if not
 *
 * @param  {object} response   A response from a network request
 *
 * @return {object|undefined} Returns either the response, or throws an error
 */
function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 *
 * @return {object}           The response data
 */
export default function request(url, options) {
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON);
}

Then a service will look like this:

import request from 'shared/lib/request';
import { API } from 'shared/constants';

const create = (content) => request(
  {
    url: API.MY_ENDPOINT,
    method: 'POST',
    data: content,
  });

const get = (id) => request(
  {
    url: `${API.MY_ENDPOINT}/${id}`,
    method: 'GET',
  });

const put = (content) => request(
  {
    url: `${API.MY_ENDPOINT}/${content.id}`,
    method: 'PUT',
    data: content,
  });

const MyEndpointService = {
  create,
  get,
  put,
};

export default MyEndpointService;

Usage, wherever you want (also outside react scope):

import MyEndpointService from '/API/MyEndpointService'

MyEndpointService.create(payload)
    .then((data) => {
    // code
    })
    .catch((errors) => {
    // error code
    });

Upvotes: 4

Michele
Michele

Reputation: 809

I would rather use a state manager like redux to centralize data fetching across different components.

Specifically, you create actions performing the actual data fetching, so you can call them inside the ComponentDidMount hooks.

Take a look at this article: https://dev.to/markusclaus/fetching-data-from-an-api-using-reactredux-55ao

Upvotes: 0

Related Questions