4

(sorry for the newbie question, but can't find it easily in documentation)

I want to have a document store with a few models, and then use some of the attributes as parameters in queries, in my Foxx services. Say I have a db for movies and series episodes:

{
    'type':'movie',
    'year':'1997',
    'director':'xxxxxxx',
    ...
},
{
    'type':'series_episode',
    'season':'1',
    'episode':'3',
    ...
}
...

I need to be able to search on

Of course what I would like to do is to have a single router that would support both GET /?type=movie&year=x&director=y.. GET /?type=series&season=x&episode=y Is that possible? Easy to do?

I couldn't find out, so I started thinking that I have to have different routers for each of the types, like this:

router.get('/movies', function (req, res) {
        const data = db._query('FOR entry IN mystore FILTER entry.type == @type, entry.year == @year RETURN entry ', 
        {'type':'movie', .....});
                res.json({
                    result: data
                })
});


router.get('/series', function (req, res) {
        const data = db._query('FOR entry IN mystore FILTER entry.type == @type, entry.season == @season, entry.episode == @episode, RETURN entry ', 
        {'type':'series', .....});
                res.json({
                    result: data
                })
})

That would be heavy work to maintain. Ideally I would just update the models and use one single router.

Even for this last option I had a question: How do i pass more than one parameters to the query? I can't find the syntax.

Any help is appreciated. I am learning ArangoDB and I am very interested in the potential, but I can't navigate around the documentation I saw or examples.

Thank you

1 Answers1

2

This question is meanwhile covered in the Foxx Manual and in detail in the endpoints documentation.

Query parameters can accessed by specifying queryParam(...)s to the JOI-router definition, and later on in the function body they can be accessed via req.queryParams.yourQueryParam.

Please note that you can use the API-Tab in the webinterface to use swagger to explore your API interactively.

A very simple Foxx service accepting two query parameters could look like this:

'use strict';

const joi = require('joi');

const router = require('@arangodb/foxx/router')();
module.context.use(router);
router.get('/hello/', function (req, res) {
    res.send(JSON.stringify({hello: `world of FirstName: ${req.queryParams.fname} LastName: ${req.queryParams.lname}`}));
})
.queryParam('fname', joi.string().required(), 'First Name to greet.')
.queryParam('lname', joi.string().required(), 'Last Name to greet.')
.response(['text/plain'], 'A personalized greeting.')
.summary('Personalized greeting')
.description('Prints a personalized greeting.');

An invocation could look like this:

curl -X GET "http://127.0.0.1:8529/_db/_system/myfoxx/hello?fname=Joe&lname=Smith"
...
{"hello":"world of FirstName: Joe LastName: Smith"}

In Path parameters could be achieved like this:

'use strict';

const joi = require('joi');

const router = require('@arangodb/foxx/router')();
module.context.use(router);
router.get('/hello/:fname/:lname', function (req, res) {
    res.send(JSON.stringify({hello: `world of FirstName: ${req.pathParams.fname} LastName: ${req.pathParams.lname}`}));
})
.pathParam('fname', joi.string().required(), 'First Name to greet.')
.pathParam('lname', joi.string().required(), 'Last Name to greet.')
.response(['text/plain'], 'A personalized greeting.')
.summary('Personalized greeting')
.description('Prints a personalized greeting.');

And an invocation could be done like this:

curl -X GET "http://127.0.0.1:8529/_db/_system/myfoxx/hello/Joe/Smith" 
...
{"hello":"world of FirstName: Joe LastName: Smith"}
dothebart
  • 5,972
  • 16
  • 40
  • Thanks, this answers the question. One more thing - my goal is to use these parameters in filters. How do I support optional parameters? e.g. i want to filter on first name OR last name ` router.get('/people', function (req, res) { const keys = db._query(aql' FOR entry IN ${foxxColl} FILTER entry.firstName == ${req.queryParams.fname} FILTER entry.lastName == ${req.queryParams.lname} RETURN entry '); res.send(keys); }) .queryParam('fname', joi.string().optional(), 'First Name.') .queryParam('lname', joi.string().optional(), 'Last Name.') ...` – costateixeira May 12 '19 at 18:48
  • 2
    @costateixeira you could either do something like `FILTER !${req.queryParams.fname} || entry.firstName == ${req.queryParams.fname}` (i.e. explicitly check if the param is even set) or you could build the filters using the aql helper methods (nesting aql templates and using aql.join): https://www.arangodb.com/docs/stable/appendix-java-script-modules-arango-db.html#the-aqljoin-helper – Alan Plum May 14 '19 at 14:40
  • thanks @AlanPlum but if i do `FILTER !${req.queryParams.fname} || entry.firstName == ${req.queryParams.fname}` i get unexpected or operator near '|| entry.firstName == \n\t\tFILTER ...' at position 3:12 (while parsing) - i guess if the parameter is null, the line in not syntactically correct..? The aql.join would be good if i can make it work. is there any example of how to conditionally define a filter? again, sorry for the noob question. thanks! – costateixeira May 14 '19 at 17:05
  • 2
    @costateixeira Ah, sorry, I misread. Undefined values will be ignored. Try defaulting the value to `null`. E.g. `const {fname = null} = req.queryParams;` and then using `fname` instead of `req.queryParams.fname`. With joi `joi.string().optional().default(null)` should also work, I think. – Alan Plum May 15 '19 at 09:32