1
\$\begingroup\$

This is my module TweetResolver (tweet-resolver.js) :

import Tweet from '../../models/Tweet';
import { requireAuth } from '../../services/auth';

export default {
    getTweet: async (_, { _id }, { user }) => {
        try {
            await requireAuth(user);
            return Tweet.findById(_id);
        } catch (error) {
            throw error;
        }
    },
    getTweets: async (_, args, { user }) => {
        try {
            await requireAuth(user);
            return Tweet.find({}).sort({ createdAt: -1 });
        } catch (error) {
            throw error;
        }
    },
    createTweet: async (_, args, { user }) => {
        try {
            await requireAuth(user);
            return Tweet.create(args);
        } catch (error) {
            throw error;
        }
    },
    updateTweet: async (_, { _id, ...rest }, { user }) => {
        try {
            await requireAuth(user);
            Tweet.findByIdAndUpdate(_id, rest, { new: true });
        } catch (error) {
            throw error;
        }
    },
    deleteTweet: async (_, { _id }, { user }) => {
        try {
            await requireAuth(user);
            await Tweet.findByIdAndRemove(_id);
            return {
                message: 'Tweet has been deleted'
            }
        } catch (error) {
            throw error;
        }
    }
}

It is used in my graphql project like this:

import GraphQLDate from 'graphql-date';
import TweetResolvers from './tweet-resolvers';
import UserResolvers from './user-resolvers';

export default {
    Date: GraphQLDate,
    Query: {
        getTweet: TweetResolvers.getTweet,
        getTweets: TweetResolvers.getTweets
    },
    Mutation: {
        createTweet: TweetResolvers.createTweet,
        updateTweet: TweetResolvers.updateTweet,
        deleteTweet: TweetResolvers.deleteTweet,
        signup: UserResolvers.signup,
        login: UserResolvers.login
    }
}

Correct me if I am wrong, but I feel there is a lot of code duplication in my tweet-resolver.js module.

Almost every method signature on this module is identical (as I only want authenticated users to be able to do anything via graphql).

Every execution is inside a try/catch block.

Is there a way to remove code duplication in this. Or is this style of coding acceptable?

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$
  1. If all your catch is doing is re-throwing the error, there is no reason to have the try/catch in the first place.
  2. If you find yourself using export default {}; to export an object, it is a huge sign that you should be using named exports instead, since you're essentially emulating them. This means you'll want to do import * as Foo from instead of import Foo from on these "bag of functions" modules.
  3. You can make a wrapper function to remove the repetitive requireAuth call.
  4. A wrapper function also allows you to remove the params you don't care about in the implementation, like the first and third parameters to these functions.

To update your code with these, I'd do

import Tweet from '../../models/Tweet';
import { requireAuth } from '../../services/auth';

let withAuth = callback => async (_, args, data) => {
    await requireAuth(data.user);
    return callback(args);
};

export const getTweet = withAuth(({ _id }) => Tweet.findById(_id));
export const getTweets = withAuth(() => Tweet.find({}).sort({ createdAt: -1 }));
export const createTweet = withAuth((args) => Tweet.create(args));
export const updateTweet = withAuth(({ _id, ...rest }) => Tweet.findByIdAndUpdate(_id, rest, { new: true }));
export const deleteTweet = withAuth(async ({_id}) => {
    await Tweet.findByIdAndRemove(_id);
    return {
        message: 'Tweet has been deleted'
    };
});

with

import GraphQLDate from 'graphql-date';
import * as TweetResolvers from './tweet-resolvers';
import UserResolvers from './user-resolvers';

export const Date = GraphQLDate;
export const Query = {
    getTweet: TweetResolvers.getTweet,
    getTweets: TweetResolvers.getTweets,
};
export const Mutation = {
    createTweet: TweetResolvers.createTweet,
    updateTweet: TweetResolvers.updateTweet,
    deleteTweet: TweetResolvers.deleteTweet,
    signup: UserResolvers.signup,
    login: UserResolvers.login,
};
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.