Open mvestil opened 8 years ago
We could also create a ids.json
file and specify the each id of the resources like this
{
"posts": "post_id",
"comments": "comment_id"
}
I think this would allows us to create more generic ids, not just ones that follow some pattern.
how to use ids.json @mertkahyaoglu
json-server db.json --id ids.json
could work, like --routes routes.json
if we want all of the resource ids to be same, we could just create a json file like this;
{
"id": "custom_id"
}
@JulienBrks
I tried but not work. And I can't find doc about this way to use --id
. May you give a demo or a detail doc link.
@mertkahyaoglu
@JulienBrks Oh, it was just a suggestion. json-server
does not have this feature, but it would be great to have. Sorry about the confusion.
👍 for an ids.json
:+1: for an ids.json
:+1: for an ids.json
:+1: for an ids.json
:+1: for an ids.json
(👍 for ids.json,) Is it being worked? or even not considered? 😢
did u improved it? it could be awesome
2017-01-12 5:14 GMT-02:00 Heesu Jung notifications@github.com:
(👍 for ids.json,) Is it being worked? or even not considered? 😢
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/typicode/json-server/issues/279#issuecomment-272093320, or mute the thread https://github.com/notifications/unsubscribe-auth/AGN88SK_CScf60t-2fHq7ZYeXauSoNvwks5rRdLkgaJpZM4IZ3ub .
for an ids.json, it's so great and helpful for us 👍
This would be really helpful.
+1
+1
+1
+1
+1
+1
Thank you for all the feedback 👍
JSON Server now supports a --foreignKeySuffix
option, which lets you define how the foreign key should end (making it easier to fake Rails APIs for example).
{
"posts": [ { "id": 1 } ]
"comments": [ { "id": 1, "post_id": 1 } ]
}
json-server db.json --fks _id
GET /posts/1/comments
@typicode I don't think that's what people in this thread are referring to. They want to be able to rename primary keys to something other than "id". The --id
flag doesn't work for me either.
{
"posts": [
{ "postId": 1, "title": "Hello world" },
{ "postId": 2, "title": "Hello other world" },
{ "postId": 3, "title": "Goodbye world" }
]
}
In this case, /posts/1
returns {}
. I've also tried post_id
with --id "_id"
.
That works for me. Exact command that I use json-server mocked_db.json --id _id --port 3004
?
Having the same need in the program too. It is solved by these:
const server = jsonServer.create();
const router = jsonServer.router('dummy.json');
router.db._.id = "yourCustomIdField";
server.use(router);
It would be nice to have this feature. In particular it would be nice to be able to set different ID param names for different entities.
For example:
{
"posts": [
{ "postId": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "commentId": 1, "body": "some comment", "postId": 1 }
]
}
in this case I would like to assign postId
as id key for the "posts" entities, and commentId
as id key for "comments" entities
Has there been any traction on this? I'm very in favor of a solution to have an ids.json file that would map each resource to it's own custom ID.
I overwrote the render
function of router to return the custom id as I want without much effort. It is still storing the data with 'id', but returning with custom id.
import _ from 'lodash';
const idMappings = {
posts: "postId",
comments: "commentId",
};
router.render = (req, res) => {
const entity = req.path.split('/')[1];
let data;
if(_.isArray(res.locals.data)) {
data = _.map(res.locals.data, (item) => {
item[idMappings[entity]] = `${item.id}`;
delete item.id;
return item;
});
} else {
data = res.locals.data;
data[idMappings[entity]] = `${data.id}`;
delete data.id;
}
res.jsonp({
data,
});
};
I needed a quick way to keep my ids in sync, below is inspired by and similar to above but as middleware:
'use strict'
// idMappings.js
// read --ids as JSON, e.g. json-server db.json --ids '{ "posts": "postsId", "comments": "commentsId" }'
let index = process.argv.indexOf('--ids');
let idMappings = process.argv[index + 1];
idMappings = JSON.parse(idMappings);
module.exports = (req, res, next) => {
if (req.method === 'POST' || req.method === 'PUT') {
const entity = req.path.split('/')[1];
req.body.id = req.body[idMappings[entity]];
}
next()
}
Run
json-server --watch db.json --ids '{"posts":"postsId", "comments": "commentsId"}' --middlewares idMapping.js
My implementation, merging tomeustace and other ideas above. Put this in server.js or other file and run as node server.js. db.json will still contain "iternal id" column but each request and response will be remapped.
This was a quick and dirty fix, I think that this req path parsing could be improved to support more complex resource urls.
const jsonServer = require('json-server');
const server = jsonServer.create();
const path = require('path');
const router = jsonServer.router(path.join(__dirname, 'db.json'));
const middlewares = jsonServer.defaults();
// define primary key columns for each resource
const primaryKeys = {
"countries": "code",
"towns": "id",
"access-policies": "accessPolicyId",
"device-services": "id"
};
const port = 3200;
server.use(middlewares);
server.use(router);
server.listen(port, () => {
console.log('Test server is running on port: ' + port)
});
router.render = (req, res) => {
const resource = req.path.split('/')[1];
let filteredResponse = res.locals.data;
// remapping internal id columns to dedicated resource columns
if (req.method === 'POST' || req.method === 'PUT') {
req.body.id = req.body[primaryKeys[resource]];
} else if (req.method === 'GET') {
filteredResponse = filterResponse(resource, res.locals.data);
}
// optional response wrapping to data attribute
res.jsonp({
data: filteredResponse
});
};
function filterResponse(resource, response) {
// don't filter if primaryKey is same as internal
if (primaryKeys[resource] === 'id') {
return response;
}
if (response instanceof Array) {
for (let i=0;i<response.length;i++) {
delete response[i].id;
}
} else {
delete response.id;
}
return response;
}
@typicode how can we use foreignKeySuffix when running json-server as module? Also can we add json-server.json config when running as module? I've added {"foreignKeySuffix":"_id"} in json-server.json but it's still not working..
@Gabriel-Cheung Could you please tell me where should I put the source code that you mentioned?
@549393092 My reply was just the idea. For further implementations, you could refer to the two answers below, which already made it as middleware. Also, I think what you were asking about was this?
@capJavert When adopt your code, there is one issue. if using GET /posts then it works fine. if using GET /posts/1 then it fails. The status code is 404. Then I console.log(res.locals.data) before call method filterResponse(), it returns { }. Did you encounter this problem before?
@549393092 I am using that code on regular basis for CRUD service mockups and it works in both ways. Did you correctly define mappings for primary keys in primaryKeys variable. Also if you are filling data in your db.json by hand you should put auto increment id attribute no matter if that endpoint has it or not (it is required by internal mapping).
@capJavert It works now. I forget to add id attribute in db.json as I thought it is not necessary. Thanks a lot for your help.
@capJavert Still one thing to ask you. When input http://localhost:3000/posts/1 in the IE, it returns as below { "data": { postId: 1, ... } } but what I want is as below which is normal { postId: 1, ... } Do you know how to do it, thanks!
@549393092 You can adjust response wrapping in this part of my code:
...
res.jsonp({
data: filteredResponse
});
...
@capJavert Yes, it works. Thank you very much!
For anyone coming here looking for a workaround (like me), something I found useful was to organize my mock data like this:
GET locahost:3000/cats Response:
[
{ id: 1, catId: 1, name: 'felix' },
{ id: 2, catId: 2, name: 'garfield' },
]
GET locahost:3000/cats/2 Response:
{ id: 2, catId: 2, name: 'garfield' }
GET locahost:3000/dogs Response:
[
{ id: 1, dogId: 2, name: 'fido' },
]
GET locahost:3000/dogs/1 Response:
{ id: 1, dogId: 2, data: 'fido' }
My API consumer uses the desired id (catId or dogId) and ignores id.
In case you want to persist using the alternate IDs, I wrote a server.js that takes an ID mapping file and saves it using the other IDs. I used different paths, get// and put/, since I wasn't sure if json-server would let me override the defaults.
IdMap.json: { "post": "postId" }
server.js: `const jsonServer = require('json-server'); const server = jsonServer.create(); const router = jsonServer.router('./db.json'); const middlewares = jsonServer.defaults(); const port = process.env.PORT || 3000; var db = require('./db.json'); var idMap = require('./IdMap.json');
server.use(jsonServer.bodyParser); server.use(middlewares);
server.put('/put/:object/', (req, res) => { if (req.method === 'PUT') { let newObj = req.body; let name = req.params.object; let id = newObj[idMap[name]]; let find = {}; find[idMap[name]] = id; if (id && newObj) { if (router.db.get(name).find(find)) { res.status(200).jsonp( router.db.get(name).find(find).assign(newObj).value()); router.db.write(); } else { res.status(400).jsonp({ error: "Bad id" }); } } else { res.status(400).jsonp({ error: "No valid id" }); } } });
server.get('/get/:object/:id', (req, res) => { if (req.method === 'GET') { let id = Number(req.params.id) ? Number(req.params.id) : req.params.id; let name = req.params.object let find = {}; find[idMap[name]] = id; if (id) { let result = router.db.get(name).find(find) if (result.value()) { res.status(200).jsonp(result.value()); } else { res.status(400).jsonp({ error: "Bad id" }); } } else { res.status(400).jsonp({ error: "No valid id" }); } } });
server.use(router); server.listen(port);`
A work around for add another id can be a middleware like:
module.exports = (req, res, next) => {
const tableName = req.url.substring(1);
res.req.body[tableName + "Id"] = res.req.body.id;
next();
};
it's weird but this works for me. I put the option for --id
first before the --watch
.
json-server --id _id --watch db.json
=> works
json-server --watch db.json --id _id
=> doesnt work
I last posted on this issue in Fall 2017.
I have a test.json
file that looks like:
{
"posts": [
{ "post_id": 1, "title": "Hello world" },
{ "post_id": 2, "title": "Hello other world" },
{ "post_id": 3, "title": "Goodbye world" }
]
}
I run json-server test.json --id _id
and go to localhost:3000/posts/1
and receive {}
back. I also tried reorganizing the arguments.
The workaround I've used since 2017 is to go to localhost:3000/posts?post_id=1
, but that's still not ideal.
I'm on version 0.14.2
.
@Nezteb I think --id
config option is meant for overwriting default id (key) and not as suffix to existing keys.
I wish we can have customized ids per entity/resource as suggested by @mertkahyaoglu.
The feature that user suggested doesn't exist:
Oh, it was just a suggestion. json-server does not have this feature, but it would be great to have. Sorry about the confusion.
I agree that it's a good idea. --foreignKeySuffix
is an excellent addition, but having a --primaryKeySuffix
as well would be nice. Although if the primary and foreign suffixes are the same, that'd cause issues.
@santosidauruk I tried your way and it worked. Thanks.
I am using 0.14.2 version
json-server --id
Any solution for using custom id for a resource and that too for multiple resources with a single json-server?
In case you want to persist using the alternate IDs, I wrote a server.js that takes an ID mapping file and saves it using the other IDs. I used different paths, get// and put/, since I wasn't sure if json-server would let me override the defaults.
IdMap.json: { "post": "postId" }
server.js: `const jsonServer = require('json-server'); const server = jsonServer.create(); const router = jsonServer.router('./db.json'); const middlewares = jsonServer.defaults(); const port = process.env.PORT || 3000; var db = require('./db.json'); var idMap = require('./IdMap.json');
server.use(jsonServer.bodyParser); server.use(middlewares);
server.put('/put/:object/', (req, res) => { if (req.method === 'PUT') { let newObj = req.body; let name = req.params.object; let id = newObj[idMap[name]]; let find = {}; find[idMap[name]] = id; if (id && newObj) { if (router.db.get(name).find(find)) { res.status(200).jsonp( router.db.get(name).find(find).assign(newObj).value()); router.db.write(); } else { res.status(400).jsonp({ error: "Bad id" }); } } else { res.status(400).jsonp({ error: "No valid id" }); } } });
server.get('/get/:object/:id', (req, res) => { if (req.method === 'GET') { let id = Number(req.params.id) ? Number(req.params.id) : req.params.id; let name = req.params.object let find = {}; find[idMap[name]] = id; if (id) { let result = router.db.get(name).find(find) if (result.value()) { res.status(200).jsonp(result.value()); } else { res.status(400).jsonp({ error: "Bad id" }); } } else { res.status(400).jsonp({ error: "No valid id" }); } } });
server.use(router); server.listen(port);`
This informative answer is what I want.
// deal with custom resource id for each resource
const idMappings = {
customers: 'customerid',
updates: 'updateId',
};
server.get(`/:resource/:id`, (req, res) => {
const { resource, id: resourceId } = req.params;
const query =
resource in idMappings
? {
[idMappings[resource]]: resourceId,
}
: {
id: resourceId,
};
const result = router.db
.get(resource)
.find(query)
.value();
return res.status(200).jsonp(result);
});
I have the same problem, but I don't think this is what JSON-Server should do .You can use other frameworks like aok.js
json-server is great , i use it only when do api mocking
I've came up with using custom routes in cases where I need custom id: json-server --watch db.json --routes routes.json
routes.json:
{ "/customIDroute/:cusomID" : "/customIDroute?cusomID=:cusomID" }
Currently, an option to set a custom id is provided using commandline option
--id id
Is it possible to make id set to a format something like this :
--id resource_id
where resource is the name of the resource...So when you run
json-server db.json --id resource_id
, the below json db is valid