How to set custom schema for custom remote methods on Strongloop
Asked Answered
B

5

12

I'm newbie on Strongloop and I can't find information for how to customize my response class (model schema for a object I built) and I don't know how to show on the API explorer the object with custom data.

Capture for strongloop api explorer

For example, I have a custom remote method called score

POST /Challenges/score

I want to show for the parameter data a custom model schema instead of single parameters, not the Model Schema for Challenge, the data on the body have all the parameters and show to the user on the Data Type: Model Schema, is this possible?

{
  "id": "string",
  "limit": 0,
  "order": "string",
  "userId": "string"
}

On the other side, in Response Class I want to show the schema for the response object. Something like this:

{
  "id":"string",
  "userId":"string",
  "user": {},
  "totalScore":0,
  "tags": []
}

I looked different questions (this and this), but can not find something to solve this issues.

Update

Here is the definition of the remote method

Challenge.remoteMethod('score', {
    accepts: { arg: 'data', type: 'object', http: { source: 'body' } },
    returns: {arg: 'scores', type: 'array'},
    http: {path: '/score', verb: 'post'}
});
Blackout answered 4/3, 2016 at 9:41 Comment(5)
Please show us how you defined the remote method.Pentlandite
@RaymondCamden I've update the question with the remote methodBlackout
Ok, so I'm having trouble parsing your exact question. Are you saying you return a custom set of data back and you want that documented? If so, can you show the code (score) you are using to generate the result? Are you also saying you want to define 'data' for the input?Pentlandite
Actually, for the 'accepts' part, do you really want an object called data, or do you want a set of key/value pairs? I think you just want key/vlaue pairs since you didn't define any othersPentlandite
Ok, maybe I haven't explained myself correctly. For the 'accepts' parts I want an object called data with a custom key/value pairs. Something like single parameters, but not parameters and inside the body of the object. For the response I want to show an approach for the object I build (with internal filters like include or order). In conclusion, I give the explorer api to external users, and then they use the custom service and they know what key/values put inside the data objects are to send and what is the api response object.Blackout
B
2

The way I found to solve this problem is to create a new model in this way, with the helper slc loopback: model

? Enter the model name: ArgChallenge
? Select the data-source to attach ArgChallenge to: (no data-source)
? Select model's base class PersistedModel
? Expose ArgChallenge via the REST API? No
? Common model or server only? server

And I continue putting properties, then on Challenge.js:

Challenge.remoteMethod('score', {
    accepts: { arg: 'data', type: 'ArgChallenge', http: { source: 'body' } },
    returns: {arg: 'scores', type: 'array'},
    http: {path: '/score', verb: 'post'}
});

And that works! If anyone knows a better way to do this, please share.

Blackout answered 19/4, 2016 at 7:44 Comment(0)
S
8

I believe you might have gone through the official docs of strongloop. If not, here is the link that explains the remote methods and their accepted data types. https://docs.strongloop.com/display/public/LB/Remote+methods

Assuming your custom object is Challenge, to show the object in response you have to specify the type( the type can be one of the loopback's data type or you custom model). So to return Challenge you have to add following code :

Challenge.remoteMethod('score', {
    accepts: { arg: 'data', type: 'object', http: { source: 'body' } },
    returns: {arg: 'scores', type: 'Challenge', root: true},
    http: {path: '/score', verb: 'post'}, 
});

The second arrow that you have specified is the default values that you want to try out with your API call. You can pass any custom string with default as the key. For example, if you want to pass some object :

Challenge.remoteMethod('score', {
    accepts: {
        arg: 'data',
        type: 'object',
        default: '{
            "id": "string",
            "userId": "string",
            "user": {},
            "totalScore": 0,
            "tags": []
        }',
        http: {
            source: 'body'
        }
    },
    returns: {
        arg: 'scores',
        type: 'Challenge'
    },
    http: {
        path: '/score',
        verb: 'post'
    }
});

So, for response you can not customize the model. But to pass default values you can put anything in the string format.

Sollars answered 15/4, 2016 at 9:52 Comment(1)
Sorry! At first I thought it was a simple idea but did not have time to try it. Yesterday I got to try it and to this day I could not answer you, when defining a default, loopback ignores it and continues to show the structure of the base modelBlackout
C
5

In loopback, remote arguments can identify data models which have been defined using ds.define('YourCustomModelName', dataFormat);

so for you case, write a function in a Challenge.js file which will have a remote method (in ur case score) defined.

const loopback = require('loopback');
const ds = loopback.createDataSource('memory'); 
module.exports = function(Challenge) {
  defineChallengeArgFormat() ;
 // remote methods (score) defined
};

let defineChallengeArgFormat = function() {
  let dataFormat = {
            "id": String,
            "userId": String,
            "user": {},
            "totalScore": Number,
            "tags": []
        };
  ds.define('YourCustomModelName', dataFormat);
};

Under remote arguments type use 'type': 'YourCustomModelName'

    Challenge.remoteMethod('score', {
        accepts: {
            arg: 'data',
            type: 'YourCustomModelName',
            http: {
                source: 'body'
            }
        },
        returns: {
            arg: 'scores',
            type: 'Challenge'
        },
        http: {
            path: '/score',
            verb: 'post'
        }
    });

You should see it reflecting on explorer after restarting server and refreshing :)

Conn answered 28/10, 2017 at 6:7 Comment(1)
This is the cleanest method but you do not need the datasource you can use "loopback.createModel();" and pass a model schema object, just as you would define model.jsonBanian
C
3

@jrltt, Instead of using default, use object structure pointing to type under accepts and it should work. Note, http source:body is needed.

With random object:

Challenge.remoteMethod('score', {
    accepts: {
        arg: 'data',
        type: {
            "id": "string",
            "userId": "string",
            "user": {},
            "totalScore": 0,
            "tags": []
          },
        http: {
            source: 'body'
        }
    },
    returns: {
        arg: 'scores',
        type: 'Challenge'
    },
    http: {
        path: '/score',
        verb: 'post'
    }
});

With a defined model which is available in model-config or create using loopback model generator, then that model name can be used to point type. So lets use User model to show in accepts parameter,

Challenge.remoteMethod('score', {
    accepts: {
        arg: 'data',
        type: 'User',
        http: {
            source: 'body'
        }
    },
    returns: {
        arg: 'scores',
        type: 'Challenge'
    },
    http: {
        path: '/score',
        verb: 'post'
    }
});
Conn answered 14/9, 2017 at 10:53 Comment(0)
B
2

The way I found to solve this problem is to create a new model in this way, with the helper slc loopback: model

? Enter the model name: ArgChallenge
? Select the data-source to attach ArgChallenge to: (no data-source)
? Select model's base class PersistedModel
? Expose ArgChallenge via the REST API? No
? Common model or server only? server

And I continue putting properties, then on Challenge.js:

Challenge.remoteMethod('score', {
    accepts: { arg: 'data', type: 'ArgChallenge', http: { source: 'body' } },
    returns: {arg: 'scores', type: 'array'},
    http: {path: '/score', verb: 'post'}
});

And that works! If anyone knows a better way to do this, please share.

Blackout answered 19/4, 2016 at 7:44 Comment(0)
D
0

I found a way to solve this problem by changing the type parameter in the accepts array. when we create remoteMethod; we provide accepts array. there is arg, type, required, http. then we can give our request object into type parameter.

Example code

UserModel.remoteMethod(
 'login',
  {
    description: 'Login a user with username/email and password.',
    accepts: [
      {
        arg: 'credentials',
        type: {'email': 'string', 'password': 'string'},
        required: true,
        http: {source: 'body'},
      },
      {
        arg: 'include', type: ['string'], http: {source: 'query'},
        description: 'Related objects to include in the response. ' +
          'See the description of return value for more details.',
      },
    ],
    returns: {
      arg: 'accessToken', type: 'object', root: true,
      description:
        g.f('The response body contains properties of the {{AccessToken}} created on login.\n' +
          'Depending on the value of `include` parameter, the body may contain ' +
          'additional properties:\n\n' +
          '  - `user` - `U+007BUserU+007D` - Data of the currently logged in user. ' +
          '{{(`include=user`)}}\n\n'),
    },
    http: {verb: 'post'},
  },
);
Dido answered 14/10, 2020 at 13:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.