Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support http.source configuration in datasources.json templates. #20

Closed
ctotheameron opened this issue Oct 28, 2014 · 6 comments
Closed

Comments

@ctotheameron
Copy link

Currently when reading the operations[template] from datasources.json, rest-connector.js hardcodes the source value to "query". I have many use-cases where I would like to configure the source value of my params without having to write custom code.

See:
https://github.com/strongloop/loopback-connector-rest/blob/master/lib/rest-connector.js#L56

My proposal would be to extend the variable definition syntax to include param source. Something like:
'{x=100:number#path}'

Happy to take a crack at this and submit a PR if you think it's worth implementing.

@raymondfeng
Copy link
Contributor

The primary purpose of the operation template is to define the structure of the REST request and extract variables as parameters for the proxy method in Node. How to map the proxy method into a new REST api is a separate concern. There are a few potential ways to derive the source:

  1. Based on where the variable is defined for the request template. For example, if a variable is in the path, map it to path. I see two issues here:
    • Need to find out what sections a var is defined
    • Sometimes, the same var can be used in more than one sections
  2. Map to query params by default, you can always redefine the remote metadata by calling MyModel.remoteMethod()
  3. Extend the variable syntax. See https://github.com/strongloop/loopback-connector-rest/blob/master/test/request-template.json#L17.

Patches are welcome.

@ctotheameron
Copy link
Author

Raymond,

Thanks for your response. I want to preface, that I am just getting started playing around with Loopback so it is VERY possible that I have no idea what I am doing :P.

Say I have defined a datasource as follows:

{
    "customRest": {
        "name": "customRest",
        "connector": "rest",
        "operations": [
            {
                "template": {
                    "method": "POST",
                    "url": "http://custom.com/api/{pathFoo}",
                    "headers": {
                        "accept": "application/json",
                        "content-type": "application/json"
                    },
                    "body": {
                        "bodyFoo": "{bodyFoo}"
                    },
                    "query": {
                        "queryFoo": "{queryFoo}",
                    }
                },
                "functions": {
                    "doSomething": ["pathFoo", "bodyFoo", "queryFoo"]
                }
            }
        ]
    }
}

The apparent behavior is

Desired Backend Call:
=====================
    POST --> custom.com/api/:pathFoo?queryFoo=:queryFoo
                {
                     "bodyFoo" : ":bodyFoo"
                }

In order to execute the previous HTTP request, an API is automatically created that defines:

Currently:
=======
POST -> localhost/api/myModel/doSomething?pathFoo=:pathFoo&queryFoo=:queryFoo&bodyFoo=:bodyFoo

In my ideal situation, I would like to hit my loopback server as follows.

Ideally:
========
    POST -> localhost/api/myModel/doSomething/:pathFoo?queryFoo=:queryFoo
                {
                    "bodyFoo" : ":bodyFoo"
                }

Based on your response (option 2), I tried modifying my 'myModel.js' as follows:

module.exports = function(myModel) {
    myModel.remoteMethod('doSomething', {
        shared: true,
        accepts: [
            { arg: 'bodyFoo',  http: { source: 'body'  } },
            { arg: 'queryFoo', http: { source: 'query' } },
            { arg: 'pathFoo',  http: { source: 'path'  } },
        ],
        http: { verb: 'put', path: '/:path' }
    });
};

I do not see the corresponding 'doSomething' endpoint changes represented in the explorer (they still show as 'query' source params.

Note: I have been able to work around this on my own by excluding the 'function' argument from datasources.json and manually attaching a function to my 'myModel' like:

myModel.doSomething = function() { //boilerplate };
myModel.doSomething.shared = ...
myModel.doSomething.accepts = ... 
etc.

But this seems like a lot of boilerplate to achieve (what seems to me) as a common usecase.

Apologies in advance if this is just a newbie error.

@raymondfeng
Copy link
Contributor

It's a timing issue. The remoteMethod is called too early inside the model extension js file. You can either move the code to be an event listener of dataSourceAttached or use a boot script. See: http://docs.strongloop.com/display/LB/App+logic+via+boot+scripts

@ctotheameron
Copy link
Author

Thanks Ray,

I was unable to get it to work using,

module.exports = function(myModel) {
    // Override the api definitions from datasources.json
    myModel.on('dataSourceAttached', function() {
        myModel.remoteMethod('doSomething', {
            shared: true,
            accepts: [
                { arg: 'bodyFoo',  http: { source: 'body'  } },
                { arg: 'queryFoo', http: { source: 'query' } },
                { arg: 'pathFoo',  http: { source: 'path'  } },
            ],
            http: { verb: 'put', path: '/:pathFoo' }
        });
    });
};

but the following did work:

module.exports = function(myModel) {
    // Override the api definitions from datasources.json
    myModel.on('dataSourceAttached', function() {
        myModel.doSomething.shared = true;
        myModel.doSomething.accepts = [
            { arg: 'bodyFoo',  http: { source: 'body'  } },
            { arg: 'queryFoo', http: { source: 'query' } },
            { arg: 'pathFoo',  http: { source: 'path'  } }
        ];
        myModel.doSomething.http = { verb: 'post', path: '/:pathFoo' };
    });
};

I'm unblocked for now. Would still like to see either better documentation around the default api's that are created from the templates (and maybe some guidelines on doing what I'm trying to do) or the functionality originally requested in this issue.

Thanks for the help!

@mayurarora0903
Copy link

How do I set dynamic / custom headers in the data source file ? I've observed, they work only if if put them in the data source file.

@richardpringle
Copy link

@aroramayur, please ask your question in one of the following locations:

Hopefully you will actually get an answer when you post in there 😃.

@ctotheameron, I assume that you have figured this out from your last comment. I will now close the issue but please feel free to re-open if need be (just make sure your mention me in a comment so I can tend to it right away).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants