micromata / http-fake-backend

Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
MIT License
311 stars 22 forks source link

feature: Support for query parameters #5

Open boochamoocha opened 7 years ago

boochamoocha commented 7 years ago

Hi. Thows error when url like this

module.exports = SetupEndpoint({
    name: 'v1',
    urls: [{
        params: '/read?cmd=on-enter&pid=1414-414-567-3636',
        requests: [{
            method: 'GET',
            response: '/json-templates/anotherExample.json'
        }]
    }]
    }]
});
mischah commented 7 years ago

Nope. This doesn’t work because hapi, the underlying server framework, handles path parameters different to query parameters. They are not part of the route.

We never needed different responses based on query params. So they aren’t configurable for the fake backend for now. The fake backend is pretty stupid and we don’t care if different query params deliver the same response.

Must say that I’m not sure about adding support for them. I would add support if

Just in case

Regarding your example I could imagine to configure the query params like that:

module.exports = SetupEndpoint({
    name: 'v1',
    urls: [{
        params: '/read',
        requests: [{
            method: 'GET',
            response: '/json-templates/anotherExample.json',
            query: {
                cmd: 'on-enter',
                pid: '1414-414-567-3636'
            }
        }]
    }]
});

I’m not sure about the expected behavior. Should it be analogous to the behavior of path params?

That means: http://localhost:8081/api/v1/read?cmd=on-enter&pid=1414-414-567-3636 would be the only successful url whereas the following examples would generate 404 errors:

More flexibility

So I guess query params should have the same flexibility like path parameters:

module.exports = SetupEndpoint({
    name: 'v1',
    urls: [{
        params: '/read',
        requests: [{
            method: 'GET',
            response: '/json-templates/anotherExample.json',
            query: {
                cmd: '{cmd}',
                pid: '{pid?}'
            }
        }]
    }]
});

That means: http://localhost:8081/api/v1/read would still generate a 404 error whereas the following would be valid urls returning the response:

anujshankar commented 7 years ago

Hey mischah!

We need support for query parameters! 🙂 It would be very useful if you implement what you have proposed.

Many thanks in Advance, Anuj

noobg1 commented 7 years ago

Hi Mischah,

I am using your project to mock backend and focus on my frontend work. Can you please implement query parameters in the urls if you get some time?

Thank you, Jeevan

mischah commented 7 years ago

Hej @noobg1 @anujshankar @boochamoocha,

challenge accepted. I just pushed a refactoring to master which hopefully improves maintainability and is a good start for adding this feature.

Can’t promise anything right now because of a constraint I mentioned before: I don’t want to add too much bloat the code base to implement a feature we (the project owners) don’t need.

… but I’m going to tackle this within the next couple of days.

Cheers, Michael

anujshankar commented 7 years ago

Thanks @mischah! Looking forward and excited about this.

anujshankar commented 7 years ago

Hey Michael!

We have our own implementation of handling query params for http-fake-server.

Details of the implementation:

  1. Created a mapURLs file which maps the APIs to the respective JSON responses.
  2. Checking if any query params were present in the query and if it endpoint matches in the hash map then we return the JSON response as mentioned in the hash map.

So basically if a user needs to handle query params then he/she just has to:

  1. Create route till the path params.
  2. Create a entry in the mapURLs file with the ‘endpoint(with query params): json file’

Example:

Contents of mapURLs.js

const urlMaps = {
    '/api/offer/{number}?filteredby=abc’: '/json-templates/abc.json',
    '/api/offer/{number}?filteredby=xyz’: '/json-templates/xyz.json'
};

Changes in the setup.js

const createRoutes = function (url) {

            const params = url.params || '';

            url.requests.forEach((proposedRequest) => {

                const method = proposedRequest.method || 'GET';
                const supportedMethod = {
                    method,
                    path: path + params,
                    handler: function (request, reply) {

// Added logic for picking up the mapped urls for understanding query parameters
                        let response, mapPath = path + params + '?';
                        const obj = request.query;

                        if (Object.keys(obj).length !== 0) {
                            Object.keys(obj).forEach((key) => {
                                mapPath += key + '=' + obj[key] + '&';
                            });
                            mapPath = mapPath.slice(0, -1);
                        }
                        console.log(mapPath, mapUrls.hasOwnProperty(mapPath));

                        if ( mapUrls.hasOwnProperty(mapPath)) {
                            response = require('../../..' + mapUrls[mapPath]);
                            console.log('resp');
                            return reply(response);
                        }
// End
                        else if (proposedRequest.statusCode && !proposedRequest.response) {
                            response = Boom.create(proposedRequest.statusCode);
                        }
                        else if (settings.statusCode && !proposedRequest.statusCode) {
                            response = Boom.create(settings.statusCode);
                        }
                        else {
                            server.log('info', 'Received payload:' + JSON.stringify(request.payload));

                            if (typeof proposedRequest.response === 'string') {
                                response = require('../../..' + proposedRequest.response);
                            }
                            else {
                                response = proposedRequest.response;
                            }

                        }

                        if (proposedRequest.statusCode && proposedRequest.response) {
                            return reply(response).code(proposedRequest.statusCode);
                        }
                        return reply(response);
                    }
                };
                routes.push(supportedMethod);
            });

Any suggestions to improve this approach?

Thanks, Anuj Shankar

JanLoebel commented 6 years ago

Any news? I wasn't able to get the version of @anujshankar up and running... :-/

mischah commented 6 years ago

The only news is, that this one isn’t on the top of my priority list. Just because we still don’t need this feature. Therefore I wont make any promises about implementing it.

But I'm open for a PR :octocat:

Sorry for the folks needing this 😕

Cheers, Michael