Source: borzoo/client.js

// @flow

import { TaskInput } from './task-input.model';
import { ListInput } from './list-input.model';
import { LoginInput } from './login-input.model';
import { GraphQLError } from './graphql-response.model';
import { List } from './list.model';
import { Task } from './task.model';
import { AxiosInstance, AxiosResponse } from 'axios';
import { axiosForBorzoo } from '../config/axios';

import Winston from '../logging/app.logger';
import { prettyJson } from '../logging/format';


/**
 * This function checks an AxiosResponse for an Errors array
 * provided by GraphQL. If found, this function will throw.
 *
 * @param {AxiosResponse} axiosResponse
 */
function throwIfGraphqlErrorPresent(axiosResponse: AxiosResponse) {
    if (axiosResponse.data.errors) {
        const errs: GraphQLError[] = axiosResponse.data.errors;
        let msg = '';
        errs.forEach(e => {
            msg += `Message: ${e.message}\nPath: ${e.path.reduce((p, c) => p + c, '')}`;
        });
        throw new Error(msg);
    }
}


/**
 * A client for the Borzoo GraphQL API.
 *
 * @export
 * @class Client
 */
export class Client {
    client: AxiosInstance;

    constructor() {
        this.client = axiosForBorzoo();
    }

    /**
     * Adds a task to a chosen list for a user.
     *
     * @param {string} userId - The owner of the task.
     * @param {string} list - The list ID or name.
     * @param {TaskInput} task - Information about the task you wish to create.
     * @returns {Promise<Task>} A promise containing the created task.
     * @memberof Client
     */
    async createTask(userId: string, listId: string, task: TaskInput): Promise<Task> {
        const mutation = `
        mutation ZevereMutation($userId: String!, $listId: String!, $task: TaskInput!) { 
            createTask(ownerId: $userId, listId: $listId, task: $task) { 
                id title description due tags createdAt
            }
        }`;
        const response = await this.client.post('', {
            query: mutation,
            variables: { userId, listId, task }
        });


        Winston.debug('Response from #createTask:');
        response |> prettyJson |> Winston.debug;

        throwIfGraphqlErrorPresent(response);
        return response.data.data.createTask;
    }


    /**
     * Deletes a task for a Zevere user.
     *
     * @param {string} userId - The owner of the task.
     * @param {string} listId - The ID of the list that contains the task.
     * @param {string} taskId - The ID of the task you wish to delete.
     * @returns {Promise<boolean>} - A promise containing a boolean to denote whether the 
     * operation passed or failed.
     * @memberof Client
     */
    async deleteTask(userId: string, listId: string, taskId: string): Promise<boolean> {
        const mutation = `
        mutation ZevereMutation($userId: String!, $listId: String!, $taskId: String!) { 
            deleteTask(ownerId: $userId, listId: $listId, taskId: $taskId)
        }`;
        const response = await this.client.post('', {
            query: mutation,
            variables: { userId, listId, taskId }
        });

        Winston.debug('Response from #deleteTask:');
        response |> prettyJson |> Winston.debug;
        throwIfGraphqlErrorPresent(response);
        return response.data.data.deleteTask;
    }

    /**
     * Creates a list on Zevere and returns the created list if successful.
     *
     * @param {string} owner - The to-be owner of the list.
     * @param {ListInput} list - An object containing the fields you wish to populate for your new list.
     * @returns {Promise<List>} A promise of containing the new list you've created.
     * @memberof Client
     */
    async createList(owner: string, list: ListInput): Promise<List> {
        Winston.debug('Received list input in #createList:');
        list |> prettyJson |> Winston.debug;
        const mutation = `
            mutation CreateListMutation($owner: String! $list: ListInput!) { 
                createList(owner: $owner, list: $list) { 
                    id owner title description collaborators tags createdAt updatedAt
                }
            }`;
        const variables = {
            owner, list
        };
        try {
            const response = await this.client.post('', {
                query: mutation,
                variables
            });
            Winston.debug('Response data from #createList:');
            response.data |> prettyJson |> Winston.debug;
            throwIfGraphqlErrorPresent(response);
            return response.data.data.createList;
        } catch (err) {
            Winston.error('Error caught in #createList:');
            err |> Winston.error;
            throw err;
        }
    }

    /**
     * Retrieves a list from Zevere.
     *
     * @param {string} owner - The owner of the list.
     * @param {string} listId - The ID of the list you wish to retrieve.
     * @returns {Promise<List>} - A promise containing the list you are asking for.
     * @memberof Client
     */
    async getList(owner: string, listId: string): Promise<List> {
        const query = `
            query GetListQuery($owner: String!, $listId: String!){
                user(userId: $owner) {
                    list(listId: $listId) {
                        id title description owner createdAt updatedAt tasks {
                            id title description
                        }
                    }
                }
            }
        `;
        const response = await this.client.post('', {
            query,
            variables: { owner, listId }
        });
        Winston.debug('Response data from #getLists:');
        response.data |> prettyJson |> Winston.debug;
        throwIfGraphqlErrorPresent(response);
        return response.data.data.user.list;
    }

    /**
     * Returns the lists that the specified owner has.
     *
     * @param {string} owner - The one who you wish to get the lists for.
     * @returns {Promise<List[]>} A promise containing the owner's lists.
     * @memberof Client
     */
    async getLists(owner: string): Promise<List[]> {
        const query = `
            query GetListsQuery($owner: String!){
                user(userId: $owner) {
                    lists {
                        id title description owner createdAt updatedAt
                    }
                }
            }
        `;
        const response = await this.client.post('', {
            query,
            variables: { owner }
        });
        Winston.debug('Response data from #getLists:');
        response.data |> prettyJson |> Winston.debug;
        throwIfGraphqlErrorPresent(response);
        return response.data.data.user.lists;
    }


    /**
     * Deletes an owner's list by ID.
     *
     * @param {string} owner - The person who owns the list you wish to delete.
     * @param {string} listId - The ID of the list that will be deleted.
     * @returns {Promise<boolean>} A promise containing true if deleted, false if not.
     * @memberof Client
     */
    async deleteList(owner: string, listId: string): Promise<boolean> {
        const mutation = `
            mutation DeleteListMutation($owner: String!, $listId: String!) {
              deleteList(owner: $owner, list: $listId)
            }`;
        const variables = {
            owner, listId
        };

        const res = await this.client.post('', {
            query: mutation,
            variables
        });
        throwIfGraphqlErrorPresent(res);
        return res;
    }

    /**
     * Gets all of the tasks for a specified list.
     *
     * @param {string} owner - The owner of the list and tasks.
     * @param {string} listId - The ID of the list that contains the tasks you want.
     * @returns {Promise<Task[]>} A promise containing all of the tasks for the specified list.
     * @memberof Client
     */
    async getTasks(owner: string, listId: string): Promise<Task[]> {
        const query = `
            query GetTasksQuery($owner: String!, $listId: String!){
                user(userId: $owner) {
                    list(listId: $listId) {
                        tasks { id title description createdAt }
                    }
                }
            }
        `;
        const response = await this.client.post('', {
            query,
            variables: { owner, listId }
        });
        Winston.debug('Response data from #getTasks:');
        response.data |> prettyJson |> Winston.debug;
        throwIfGraphqlErrorPresent(response);
        return response.data.data.user.list.tasks;
    }

    /**
     * Gets the specified task in the specified list.
     *
     * @param {string} owner - The owner of the task.
     * @param {string} listId - The ID of the list that the task belongs to.
     * @param {string} taskId - The ID of the task.
     * @returns
     * @memberof Client
     */
    async getTask(owner: string, listId: string, taskId: string) { // eslint-disable-line no-unused-vars
        const tasks = await this.getTasks(owner, listId);
        Winston.info(`Tasks: ${JSON.stringify(tasks)}`);
        return tasks.find(t => t.id === taskId);
    }
}