Skip to content

Nested Services or Nested Configuration #1471

Open

Description

@mtraynham

I've seen multiple posts about this (#139, #413, #585, #1254, #1381), but none of those provide a concrete solution. I think it really stems from the fact that some ReST API's just don't abide by the same rules throughout the path hierarchy. id fields are different, responses/post body may be wildly different.

Let's take for instance an example resource:
/api/cars/{modelId}/wheels/{wheelId}

So far we have two different ID fields. From the documentation, it seems like this is should be the approach:

Restangular.withConfig(RestangularConfigurer =>
    RestangularConfigurer
        .setRestangularFields({id: 'modelId', route: 'cars'})
        .setRestangularFields({id: 'wheelId', route: 'wheels', parentResource: 'cars'})

But this does not work. Per the FAQ documentation, we need to set the getIdFromElem method.

If the ReST API also expects different information for the post body and returns different things for get/getList, the implementation starts to get unwieldy as shove everything under the top parent resource, like so:

.addResponseInterceptor((data, operation, what, url) => {
    if (what === 'cars') {
        if (operation === 'getList') {
            return data.map(name => ({name}));
        }
        if (operation === 'get') {
            const urlSplit = url.split('/');
            const name = urlSplit[urlSplit.length - 1];
            return {name, descriptor: data};
        }
    }
    if (what === 'wheels') {
        if (operation === 'getList') {
            return data.map(name => ({name}));
        }
        if (operation === 'get') {
            const urlSplit = url.split('/');
            const name = urlSplit[urlSplit.length - 1];
            return {name, descriptor: data};
        }
    }
    return data;
})

Realistically, it would make the most sense if you could create a Restangular configuration and use that to create a service under a parent.

const carWheelConfig = Restangular.withConfig(RestangularConfigurer =>
    RestangularConfigurer
        .setRestangularFields({id: 'wheelId', route: 'wheels'})
        .addResponseInterceptor((data, operation, url) => {
            if (operation === 'getList') {
                return data.map(name => ({name}));
            }
            if (operation === 'get') {
                const urlSplit = url.split('/');
                const name = urlSplit[urlSplit.length - 1];
                return {name, descriptor: data};
            }
            return data;
        });

const carConfig = Restangular.withConfig(RestangularConfigurer =>
    RestangularConfigurer
        .setRestangularFields({id: 'modelId', route: 'cars'})
        .addResponseInterceptor((data, operation, url) => {
            if (operation === 'getList') {
                return data.map(name => ({name}));
            }
            if (operation === 'get') {
                const urlSplit = url.split('/');
                const name = urlSplit[urlSplit.length - 1];
                return {name, descriptor: data};
            }
            return data;
        })
        .addElementTransformer(element, false, element => 
            Object.assign(element, {
                wheels: carWheelConfig.service(element)
            }));

The addElementTransformer for adding a wheel service to car, seems like it should work, but invoking Restangular.service(parent) removes all the prior configuration of wheelConfig.


Is there anyway to create a nested configuration/service that does not directly inherit (in this broken use case override) any configuration from the parent resource, except maybe the path building aspect?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions