How to architect a react-redux app with grpc-web?
Asked Answered
P

2

7

I have a react-redux app and my team uses grpc-web. I'm wondering - what's the best way to design such system?

For now the plan is to create 3 abstraction levels:

  1. API module - promisified wrappers around grpc-web clients
  2. Redux thunks level - async action creators that deal with the API
  3. React components props - will ask for only what component needs

So components know nothing about grpc, they mess with action creators, action creators know nothing about grpc, they deal with an api module, and only api module uses with grpc-web stubbs.

Reasons why I want to go this way:

  • No grpc-specific code in action creators and components
  • My Promise-based API instead of a callback-based API of grpc-web

My questions are:

  1. Is it a good idea to have an abstraction level between Redux and grpc-web? Or it's better to keep that stuff inside action creators logic?
  2. Is there a common design pattern I should think of? (I am thinking about "Adapter")
  3. Is it a good idea to promisify grpc-web API? If yes, is it a good idea to write a function and do it on the fly?
  4. Can I say that my current plan is Adapter Pattern?
  5. If I want to use an Adapter pattern, am I have to map every element of data collection to my own interface? I know that my components (and maybe action-creators) should not depend on grpc-web API because this API may change in future
Peck answered 5/1, 2020 at 19:4 Comment(0)
I
1

IMHO, it does not matter which tech are you using to encode data over the web, it's always a good idea to encapsulate that in some kind of a service in your app. So answering your questions:

Is it a good idea to have an abstraction level between Redux and grpc-web? Or it's better to keep that stuff inside action creators logic?

Yes, it is definitely a good idea to decouple Redux-specifics from the network specifics. This way if your team decided to change the grpc to some other tech, you'd only need to change the code of your service (it actually never happened to me during my career, though).

Is there a common design pattern I should think of? (I am thinking about "Adapter")

Is it a good idea to promisify grpc-web API? If yes, is it a good idea to write a function and do it on the fly?

I am unsure of what are you referring as "on the fly" here, but I guess the code should look something like the following:

// client should probably exist in only instance, right? Consider using DI container for that
var client = new GreeterClient('http://' + window.location.hostname + ':8080', null, null);

// simple unary call
class ApiAbstractionService {
    construct(client) {
        this.client = client;
    }
    
    sayHello() => {
        return new Promise((resolve, reject) => {
            this.client.sayHello(request, {}, (err, response) => {
                if (err) {
                    reject(err.message);
                } else {
                    resolve(response.getMessage());
                }
            });
        })
    }
}

Can I say that my current plan is Adapter Pattern?

Adapter is usually used when you have 2 kind of services, for instance, with a different interface and you would like to unify it. I'd personally say - nope.

If I want to use an Adapter pattern, am I have to map every element of data collection to my own interface? I know that my components (and maybe action-creators) should not depend on grpc-web API because this API may change in future

Yet again - if you're not sure that the design pattern you chose fits perfectly your needs - just don't use it. Patterns are supposed to help you, not to force you into restrictions that you don't need.

Identification answered 31/1, 2022 at 14:41 Comment(0)
E
0

I am using grpc-web on redux thunk and below sample code is from action creator:

export const getStudentInfo = (id) => async dispatch => {

const request = new StudentRequest();
request.setId("555");
var metadata = { 'token': 'value1' };
var URL = "https://localhost:5001";
var client = new StudentClient(URL);
var call = client.getStudentInformation(request, metadata, function (err, response) {

    if (err) {
        console.log(err.code);
        console.log(err.message);
    } else {
        dispatch({ type: STUDENT_INFO, payload: response.getMessage() })
    }
});
call.on('status', function (status) {
    //console.log(status.details);
});

};
Ever answered 16/9, 2020 at 15:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.