1

I'm building an APP in React where I would like to consume an API for comments which allows crud rules. What I'm trying to build is a modular fetch that is implemented once and all the CRUD rules use the same fetch in one place where the base URL of the API is defined. Via the CRUD functionalities, I will just pass the endpoint I need and the related params and method. That will make life easier to use it around the APP when need it.

What I built first was my BaseAPI functionality as follow:

import { COMMENT_USER, COMMENT_PASS } from "./ConstAPI";

export const createCommentAPIQUery = urlGenerator => async (...params) => {
  try {
    const url = urlGenerator(...params);
    const token = btoa(COMMENT_USER + ":" + COMMENT_PASS);
    const credentials = {
      method: "GET",
      headers: new Headers({
        Authorization: "Basic " + token,
        "Content-Type": "application/json",
        Accept: "application/json"
      })
    };
    const response = await fetch(url, credentials);
    const json = response.json();
    return {
      success: true,
      ...json
    };
  } catch {
    return {
      success: false,
      result: [],
      message:
        "There is an issue to get data from server. Please try again later."
    };
  }
};

The issue above is that that will work when I use the GET but for the other CRUD will not as I need to pass a method and in case of a POST and PUT also stringify(). So the following CRUD functionalities were my attempt but as you will see that works only for the GET method and I need to find a solution for the rest of the methods:

import { createCommentAPIQUery } from "./BaseCommentAPI";
import { COMMENT_URL } from "./ConstAPI";

export const getAllComments = createCommentAPIQUery(
  asin => `${COMMENT_URL}/comments/${asin}`
);

export const addComment = createCommentAPIQUery(body => {
  `${COMMENT_URL}/comments`, (this.credentials.method = "POST");
  this.credentials.body = JSON.stringify(body);
});

export const updateComment = createCommentAPIQUery((id, body) => {
  `${COMMENT_URL}/comments/${id}`, (this.credentials.method = "PUT");
  this.credentials.body = JSON.stringify(body);
});

export const deleteComment = createCommentAPIQUery(id => {
  `${COMMENT_URL}/comments/${id}`, (this.credentials.method = "DELETE");
});

What I need is a good idea to make that work as I thought about it but actually I stack in it.

As it is now is generating an error as:

Expected an assignment or function call and instead saw an expression  no-unused-expressions

So I need to figure out a good way to complete this idea and to avoid issues and bugs.

3
  • Arrow functions break the this binding. Try replacing the arrow functions with function declarations: Instead of this : ()=>{} write your functions like this: function(){} Commented Nov 30, 2019 at 0:45
  • Also, you need to add the await keyword on the json response line too: const json = await response.json(); Commented Nov 30, 2019 at 0:49
  • @KostasX OP isnt dealing with an instance object so use of this is wrong either way Commented Nov 30, 2019 at 1:23

2 Answers 2

1

Pass your body and method as arguments not part of your url generator code, method with the outer function and body with the inner

export const createCommentAPIQUery = (urlGenerator,method='GET') => async (body,...params) => {
  try {
    const url = urlGenerator(...params);
    const token = btoa(COMMENT_USER + ":" + COMMENT_PASS);
    const credentials = {
      //use passed method and body accordingly
      method: method,
      body:body,
      headers: new Headers({
        Authorization: "Basic " + token,
        "Content-Type": "application/json",
        Accept: "application/json"
      })
    };

Example use:

export const getAllComments = createCommentAPIQUery((asin)=>{ 
  return `${COMMENT_URL}/comments/${asin}`; 
});
//calling, pass null as no body is needed, and 'theAsin' will become part of 'params'
getAllComments(null,theAsin).then(...);

export const addComment = createCommentAPIQUery(()=>{ 
  return `${COMMENT_URL}/comments`; 
},"POST");
//calling, pass in body, and no other arguments are needed for 'params'
addComment(JSON.stringify(body)).then(...);

export const updateComment = createCommentAPIQUery((id)=>{ 
  return `${COMMENT_URL}/comments/${id}`; 
},"PUT");
//calling, pass in body, and 'theId' will end up as part of 'params'
updateComments(JSON.stringify(body),theId);
Sign up to request clarification or add additional context in comments.

1 Comment

Could you please explain to me the usage of then(...)? Does that mean other operations regarding the GET and the other methods?
1

Here's a (reduced for size) solution I came up with at work that might help you out. It mirrors your existing code pretty well but adds exported functions for the rest methods that call the main API function createCommentAPIQUery. You then import those functions into the files that need them and use them instead of importing the createCommentAPIQUery.

Note: this code is simply an example, reduced code for brevity. You'll have to adapt the key points to your existing code.

export async function createCommentAPIQUery(params) {

  // Extract the endpoint, method, body etc from the params
  const { endpoint, method, body } = params;
  const headers = {...};
  try {
    const response = await fetch(endpoint, { method, headers, body });
    if (!response.ok) throw new Error();
  } catch (err) {
    console.log(err);
  }
};

// For each rest method that accepts a params object,
// define the rest method then call `createCommentAPIQUery` with
// that method and the params
export function GET(params) {
  const method = 'GET';
  return createCommentAPIQUery({ ...params, method });
}

export function POST(params) {
  const method = 'POST';
  return createCommentAPIQUery({ ...params, method });
}

// Import those functions into the file where your actions are
import { DELETE, GET, PATCH, POST } from "./BaseCommentAPI";

// Define a function for your action
// Set the endpoint, body etc (whatever you need to pass into
// `createCommentAPIQUery`, and then call the imported function
function getAllComments(asin) {
  const endpoint = `${COMMENT_URL}/comments/${asin}`;
  return GET({ endpoint });
};

function addComment(body) {
  const endpoint = `${COMMENT_URL}/comments`;
  return POST({ endpoint, body: JSON.stringify(body) });
});

Hope this is of some use.

2 Comments

I tried this version but is not doing anything no console errors and no data fetched from API I do not really understand that. I used as it is but seems is not been working
You'll have to adapt it to your code. This code is just an example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.