I see several similar issues as to what I am running into reported on here like:
Basically, I am trying to mock up a production API that I have no control over, so I need to be able to follow the exact paths they expose. I keep running into issues and some I have been able to work past by setting up a customer server.js file, I still am hitting some roadblocks preventing this from working.
Currently, issue 1 is that query strings can not be put into the custom routes or the custom route fails, i.e. "/export?week=:week": "/export/:week" fails.
Issue 2 is I don't see documented anywhere how to set the id field when using this as a module. Before the module, I could set this via the CLI or settings file, however this no longer works. Since I have an id field named something other than id, this means I have to customize the output to remove the array around the single object returned, which I have successfully done.
Issue 3 is that query strings are lost upon custom routing. So, I did all these steps to work around the top 2 issues including massaging my db.json file, setting up a server.js, and implementing the code for custom routes and custom response, and yet now it still doesn't work because when the custom routing occurs, the entirety of the query string is lost.
I am hoping someone has some thoughts because json-server seemed like a great, easy to use fit and I can see how if you have no requirements for routes it is, however in my case I have spent a lot of time and have hit roadblocks at each turn.
Ultimately, I need to accept a URL like "/:user/export?week=:week&otherparms" and using the following object structure:
{ export: [ { week: 49, otherdata } ] }
... return the following:
{ week: 49, otherdata }
Thanks in advance.
Is there anything wrong with "/export/week/:week": "/export/:week" ?
The other params should filter accordingly
Yes, there are two things wrong. One, as I mentioned I cannot control what the API is so unfortunately I have to use /:user/export?week=:week. Second, as I and others have mentioned in other issues, currently the query string is completely lost upon redirect. I am absolutely open to ideas to get this to work, however the one major restriction I have (just to reiterate) is I cannot change the endpoint URLs, so I need to make this fit those, not the other way around. Thanks.
What's the schema for users? is it this:
User hasOne export
'week' is an attribute on the export table?
I am also having this issue. I feel like I must be doing something wrong. I have a list of profiles that are defined in a Profile array in the db.json. They each have an id and a bunch of other properties. I am trying to make a custom route to emulate our apis without having to change our application calls.
In my routes.json I cannot seem to get this route working "/:resource/GetProfile/0?id=:id":"/:resource/:id".
The 0 in the route is static and is used to make the calls route to different applications on the server. the only thing that changes is the id field. When I make the call I get back an empty object instead of the object that correlates to the id like I would expect. Am I doing something wrong here or can we not use query parameters with this application?
a route is everything up until the ?. Everything after the ? is a query and will go into req.query as key:value pairs. You may create custom routes.
/:resource/GetProfile/0?id=:id
/:resource/GetProfile/0?name=:name
These are both the same route with different queries parameters. Therefore, you cannot have different custom routes for each of those.
When you add that custom route, nothing after the ? can be used to map to /:resource/:id as it's not part of the route, it's part of the query parameters.
@rhedges for now, you can use "/:resource/GetProfile/0":"/:resource?" as a custom route.
When you do something like /users/GetProfile/0/id=1 it will return a collection of users where their id is equal to 1. There is currently no way to return a single object as opposed to a collection, but I will look into it.
I am also going to make a PR shortly that will allow you to do "/:resource/GetProfile/0":"/:resource" instead (you shouldn't have to add the question mark)
@BrennerSpear No the schema is basically what I listed above:
{ export: [ { week: 49, otherdata } ] }
More complex than this, but this is the structure. When I set up my redirect as "/:user/export/": "/export/", and I navigate to /someuser/export, it does work correctly. However, if I try to navigate to /someuser/export?week=1, I get every single week, which to me looks like its losing the query string. Especially because navigating to /export?week=1 does filter the results correctly. That is my issue, and maybe its caused by having :user in the beginning of the url?
On a side note, I do need it to return an object, not an array of objects as well. Someone on here posted this workaround:
router.render = (request, response) => {
const { data } = response.locals;
if (Array.isArray(data) && data.length === 1) return response.jsonp(data[0]);
response.jsonp(data);
};
...which does work, but requires I set up the server manually. If we could resolve this query string issue and return an object instead of an array of one object, I would be golden. Does that help?
Yes, thank you.
I just submitted a PR to fix the first problem. It now merges client-specficied queries (i.e. ?week=1) and queries specificed in the rules on the server side. Within a rule, I am referring to the key as the client side and the value as the server side.
I will write up some more documentation around this but basically, with regards to custom route rules:
? because a route is everything before the ? and these are custom defined routesSo, for your use case specifically, with the current code base, you need this:
"/:user/export/": "/export?"
After my PR gets merged or if you want to deal with changing the code yourself, what you had before will work:
"/:user/export/": "/export"
As for the second probem, that's a little trickier. That work around looks like it sends all single object arrays as an object. What if your client code is expecting a collection, and it happens to only have 1 row of data? Or is this render function specific to only the route(s) you specify?
Great, thank you for your assistance.
Yes, I can understand why handling single objects can be tricky. I suppose the "right" way to do it would be a parm you pass indicating to return the object or array (defaulting to array), but that wouldn't work for me. Personally, I would be fine with some attribute on my custom route indicating this, or some property I could set for all routes as I never need the array version, just the single object.
Or, would a custom route work to merge the parms? So I could do something like ":user/export/": "/export?return=object" and then it would add the additional parms passed to ?return=object so I would end up with a query string like ?return=object&week=2. Cause then that might be the best case possible since it should work for everyone.
Yes, I'm thinking we'd stick flag on the server side of the custom route and it would basically automatically do what that router.render block that you posted a few comments ago does
Cool, that'd be terrific
Hi,
JSON Server has been updated with a third-party module to handle URL rewriting. It should offer more options now: https://github.com/typicode/json-server#add-custom-routes
Thank you again for the help and feedback! :)
Closing the issue.
Most helpful comment
@BrennerSpear No the schema is basically what I listed above:
{ export: [ { week: 49, otherdata } ] }More complex than this, but this is the structure. When I set up my redirect as
"/:user/export/": "/export/", and I navigate to /someuser/export, it does work correctly. However, if I try to navigate to /someuser/export?week=1, I get every single week, which to me looks like its losing the query string. Especially because navigating to /export?week=1 does filter the results correctly. That is my issue, and maybe its caused by having :user in the beginning of the url?On a side note, I do need it to return an object, not an array of objects as well. Someone on here posted this workaround:
...which does work, but requires I set up the server manually. If we could resolve this query string issue and return an object instead of an array of one object, I would be golden. Does that help?