I have a working client writen in typescript and a legacy web server written in c# . I am attempting to convert the c# code into nodes.js / express.
The client fetch function:
export async function myFetch(url : String, data : Object | null) {
const bodyData = JSON.stringify(data);
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: bodyData
}
const fullUrl = serviceBase() url;
let res;
try {
if (data==null)
res = await fetch(fullUrl);
else
res = await fetch(fullUrl, options);
if (!res.ok) {
throw new Error(`HTTP error: ${res.status}`);
}
return await res.json();
}
catch (error : any) {
AlertError('Web error',error)
}
}
and this is the interface (in C#) for one of the server endpoints:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/GetRidesForDate", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[ServiceKnownType(typeof(List<Ride>))]
IEnumerable<Ride> GetRidesForDate(int date);
Using this, GetRidesForDate
returns correct results.
In the node/express attempt I have:
const app = express ();
const port = process.env.PORT || 3000;
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.listen(port, () => {
console.log("Server Listening on PORT:", port);
});
app.get("/GetRidesForDate/:date", (request: any, response: { json: (arg0: any[]) => void; }) =>
{
console.log('getRidesForDate ' request.params.date);
getRidesForDate(request,response);
})
but if I call the client fetch with
rides.value = await myFetch("GetRidesForDate",18800);
the server code never arrives at console.log
, instead I get an error:
SyntaxError: Unexpected token '1', "#" is not valid JSON
at JSON.parse (<anonymous>)
The 1
here is the first digit of the fetch data. The client gives a 400 error (bad request).
If I use a browser and go to http://localhost:3000/GetRidesForDate/18800
the node/express server responds correctly.
What should the parameters of app.get()
be to make this work with my fetch
command?
CodePudding user response:
The problem is that the fetch body JSON.stringify(18800)
is not a valid JSON, and that parse error is coming from the server JSON body parser, hence the 400 Bad request
error (not familiar with c#, so no idea why there is no error there..).
So, you need to actually use a valid JSON:
instead of this:
const bodyData = JSON.stringify(data);//18800: not valid JSON
use this:
const bodyData = JSON.stringify({data}); //{"data":18800}: valid JSON
and then access it on the server via req.body.data
.
Furthermore, it's unclear how you handle this request, because in your client fetch code, you seem to have two request: one GET, and one POST (which gives the error), but neither of them should work, because on the server you have only GET route which expects :date
parameter, which you seem to send only via body in the POST request..
So, why not just always send it via body, and then if it's undefined, set it to something default, and do you processing.
And if you really want that route to work with both POST and GET, then you can use app.use("/GetRidesForDate"....
, but there seems to be no purpose for that, and also, you'd need to add :date
parameter in url, and not use body
at all, which is why it's probably more convenient to always use req.body
.
Note: you can also remove extra app.use(bodyParser.json());
, because you already use app.use(express.json());
Try this:
client:
export async function myFetch(url : String, data : Object | null) {
const bodyData = JSON.stringify({data});
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: bodyData
}
const fullUrl = serviceBase() url;
let res;
try {
res = await fetch(fullUrl, options);
if (!res.ok) {
throw new Error(`HTTP error: ${res.status}`);
}
return await res.json();
}
catch (error : any) {
AlertError('Web error',error)
}
}
server:
// to make both GET and POST work, you could use `app.use("/GetRidesForDate"....`, but there seems to be no purpose for that..
app.post("/GetRidesForDate", (request: any, response: { json: (arg0: any[]) => void; }) =>
{
console.log('getRidesForDate ', request.body.data);
// if no req.body.data, add some defaults..
getRidesForDate(request,response);
})