Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to 'get' data using POST with json-server? #453

Closed
vsharma2266 opened this issue Jan 11, 2017 · 21 comments
Closed

Is it possible to 'get' data using POST with json-server? #453

vsharma2266 opened this issue Jan 11, 2017 · 21 comments

Comments

@vsharma2266
Copy link

Hi,

I am trying to get response using POST. My POST body has some key-value pairs which determine what needs to be responded.
Is it possible to get data back from POST method ?

Thanks

@sanserna
Copy link

sanserna commented Mar 2, 2017

It would be helpful if they answered this issue... i'am facing the same problem

@typicode
Copy link
Owner

typicode commented Mar 2, 2017

Hi @vsharma2266 @sanserna,

Out of the box it's not possible, sorry. With REST, making a POST usually mean that you request a change and if you want to query GET is the right verb.

That said, using the project as a module, you can fake it:

// server.js
var jsonServer = require('json-server')
var server = jsonServer.create()
var router = jsonServer.router('db.json')
var middlewares = jsonServer.defaults()

server.use(middlewares)

server.use(jsonServer.bodyParser)
server.use(function (req, res, next) {
  if (req.method === 'POST') {
    // Converts POST to GET and move payload to query params
    // This way it will make JSON Server that it's GET request
    req.method = 'GET'
    req.query = req.body
  }
  // Continue to JSON Server router
  next()
})

// If you need to scope this behaviour to a particular route, use this
server.post('/comments', function (req, res, next) {
  req.method = 'GET'
  req.query = req.body
  next()
})

server.use(router)
server.listen(3000, function () {
  console.log('JSON Server is running')
})

I would suggest checking https://expressjs.com/ docs and https://github.com/typicode/json-server#module

And if you need to customize more, you can also access router's lowdb instance using router.db.

Hope this helps :)

@hopkinson
Copy link

hopkinson commented Apr 20, 2017

@typicode i tried pasted above code ,but i found that i failed to get data
in routes.json,
'/api/product/stocks_index/list': '/referenceList/:id'
I want '/api/product/stocks_index/list' this api‘s request value is {id:1},and want to turn '/referenceList/:id' into '/referenceList/1' but ,/api/product/stocks_index/list can not change such as/api/product/stocks_index/list?id=1` ..
Or,what can i solve this problem?

@vsharma2266
Copy link
Author

Closing as this question is answered.

@appsparkler
Copy link

appsparkler commented Nov 9, 2017

This is what worked for me:

Instead of writing the server.js file from scratch and executing it; I created a middleware file. The contents of the middleware file are from @typicode's response above:

// middleware-1.js
module.exports = function (req, res, next) {
  if (req.method === 'POST') {
    // Converts POST to GET and move payload to query params
    // This way it will make JSON Server that it's GET request
    req.method = 'GET'
    req.query = req.body
  }
  // Continue to JSON Server router
  next()
}

Next, this is in my json-server.json file:

{
    //...
    "middlewares": ["middleware-1.js"],
    //..
}

The db.json file is as usual with all the data, and finally, executed the code:

json-server db.json

Good Luck.

@mircolac
Copy link

mircolac commented Dec 1, 2017

@appsparkler thanks a lot for your answer, it helped me fixing a problem in the project i'm working at the moment.

Moreover, while writing the middleware and testing your solution, I discovered a weird behaviour when the query result cointained a field with the same name of a field contained in the POST original body.

I'll explain it better, using an example from the code I wrote

HTTP request

(variable's names are voluntarily changed)

this.http.post<OutputFormat>(EndpointUrl('URL'),
      {
        'foo': foo,
        'bar': bar,
        'baz': 'baz',
        'qux': 'qux'
    })
      .subscribe(
      res => {
        console.log("res is  ",res);
       ...

MIDDLEWARE

module.exports = (req, res, next) => {
...
                req.method ='GET';
                req.query = req.body
                next();
...
}

RESULT:
Everything works fine UNLESS the json at the endpoint contains a field that has the same label of the fields in the req.body ( 'foo', 'bar', 'baz' or 'qux' ).

example:

"endpointYouAskedFor": [
    {
      "foo": {...},
      "someOtherThing": {...}
}

In this case, the result will be an empty res object.
If there was no 'foo' field in the endpoint, everything would have been fine.

I hope this will be useful and spare some hours to someone :)

@appsparkler
Copy link

appsparkler commented Dec 2, 2017

hi @mircolac

i'm not sure if this would work but another thing that we can include in the middleware is to make the req.body into an empty object before :

// ...
    req.query = req.body;
    delete req.body; //or null (if that works)
// ...

this might avoid the req.body reaching the json-server logic without missing out on the query...

@mircolac
Copy link

mircolac commented Dec 4, 2017

Hey @appsparkler
That was certainly worth a try, but unfortunately didn't fix the problem!

Thanks anyway :)

@leohxj
Copy link

leohxj commented Feb 1, 2018

@typicode
I use POST method to make some change, but want to get some response (not the insert resource).

Is there another way which not to make the method to 'get' ?

Thanks.

@leotm
Copy link

leotm commented Feb 2, 2018

@leohxj Is there an issue with setting your method to get, like so?

server.post('/some/url', (req, res) => {
  req.method = 'GET'
  res.jsonp({ some: "response" })
})

As you can still POST to your server, .then use the response.

@m-e-conroy
Copy link

I needed to reroute the URL but resetting req.url wasn't working so I did the following.

const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const request = require('request');
const middlewares = jsonServer.defaults();

server.use(middlewares);
server.use(jsonServer.bodyParser);

server.post('/login',(req,res,next) => {
  // We don't care if we don't check the password we just want to receive a user back for testing
  let url = 'http://localhost:3000/user?login.username=' + req.body.username;
  request({url: url, json: true},(err, response, body) => {
    res.send(body);
  });
}); // post(/login)

server.use(router);

server.listen(3000, ()=>{
  console.log('http://localhost:3000 Running...');
});

@MickL
Copy link

MickL commented Feb 13, 2019

It seems like the only way is write a middleware that changes requests from POST to GET:

server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.method = 'GET';
  }
  next();
});

You can still have and react to POST requests if you do this BEFORE the middleware:

server.post('/addUser', (req, next) => {
  res.jsonp(myResponse);
});

server.use((req, res, next) => {
  if (req.method === 'POST') {
    req.method = 'GET';
  }
  next();
});

@SetTrend
Copy link

SetTrend commented Mar 29, 2019

I've been facing the same issue. My team demands sending their query data in the body, so they're using a POST instead of a GET for querying data.

After searching the web I created a json-server.js file that sends a GET when it's supposed to send a POST (I currently don't filter which addresses to convert).

So, for anyone who's searching for a compound json-server.js file, here's mine:

// json-server.js
const jsonServer = require('json-server');
const bodyParser = require("body-parser");
const server = jsonServer.create();
const router = jsonServer.router('./db.json');
const middlewares = jsonServer.defaults();

server.use(bodyParser.json());
server.use(bodyParser.urlencoded({
	extended: true
}));

server.use(function (req, res, next) {
	if (req.method === 'POST') {

		// Converts POST to GET and move payload to query params
		req.method = 'GET';
		req.query = {}

		for (let p in req.body) req.query[p] = req.body[p];
	}
	// Continue to JSON Server router
	next();
});

server.use(middlewares)
server.use(router)

const port = 3000;
server.listen(port, () => console.log(`JSON Server is running on port ${port} ...`))

@beanmac
Copy link

beanmac commented Apr 5, 2019

Thanks for the details @SetTrend.

@gazdagergo
Copy link

gazdagergo commented May 10, 2019

I set up a middleware like this and works fine for me:

middleware1.js

module.exports = function (req, res, next) {
  if (req.method === 'POST' && req.originalUrl === '/user/login') {
    return res.jsonp({ token: "foo" })
  }
  next()
}

And run

> json-server  --middlewares middleware1.js  ...

@isahilpahuja
Copy link

@appsparkler thanks a lot for your answer, it helped me fixing a problem in the project i'm working at the moment.

Moreover, while writing the middleware and testing your solution, I discovered a weird behaviour when the query result cointained a field with the same name of a field contained in the POST original body.

I'll explain it better, using an example from the code I wrote

HTTP request

(variable's names are voluntarily changed)

this.http.post<OutputFormat>(EndpointUrl('URL'),
      {
        'foo': foo,
        'bar': bar,
        'baz': 'baz',
        'qux': 'qux'
    })
      .subscribe(
      res => {
        console.log("res is  ",res);
       ...

MIDDLEWARE

module.exports = (req, res, next) => {
...
                req.method ='GET';
                req.query = req.body
                next();
...
}

RESULT:
Everything works fine UNLESS the json at the endpoint contains a field that has the same label of the fields in the req.body ( 'foo', 'bar', 'baz' or 'qux' ).

example:

"endpointYouAskedFor": [
    {
      "foo": {...},
      "someOtherThing": {...}
}

In this case, the result will be an empty res object.
If there was no 'foo' field in the endpoint, everything would have been fine.

I hope this will be useful and spare some hours to someone :)

Thanks for this!!

@webia1
Copy link

webia1 commented Jun 13, 2020

maybe, it is much easier and you don't have to change methods:

const server = jsonServer.create();
const router = jsonServer.router(db);
const middlewares = jsonServer.defaults();
const port = 3000;

// @ts-ignore
router.render = (req, res) => {
  if (req.originalUrl === '/whatever' && req.originalMethod === 'POST') {
    res.jsonp({
      result: {
        agent: 'James Bond',
        code: '007',
      },
    });
  } else {
    res.jsonp({
      result: res.locals.data,
    });
  }
};

server.use(middlewares);
server.use(router);

server.listen(port, () => {
  console.log(`JSON Server is running on port ${port}`);
});

@alexcroox
Copy link

alexcroox commented Apr 27, 2022

Note req.query = req.body will result in a 500 error due to there being a json-server specific _delay property on req.query.

This prevents that:

req.query = { ...req.query, ...req.body }

@Jackie098
Copy link

@appsparkler in this case, if i add "middlewares": ["middleware-1.js"], inside a json-server.json, he will understand that is a new route.

Is there no other way to do this work within only "json files" without needing a server.js file?

@appsparkler
Copy link

Hi @Jackie098, this was a long time ago (5-6 yrs). I've not been using json-server for few years now
and am no longer sure about its implementation, logic, etc. I'm currently focused on Android
with Compose in Kotlin so I hope you understand.

Thanks & Regards

@Jackie098
Copy link

@appsparkler i understand! Thanks for answered me 😁❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests