How can I route a path which has '?' character in it in nestjs? - node.js

For example in browser we send /controller/test?value=2 but I want to route this at an endpoint? I have another endpoint /controller/test which captures even the requests made to this route

That's a query string.
You can use #Query decorator in the function parameter
#Get('/path')
async find(#Query() query) {
console.log(query);
}
More info

In this situation, it seems like your route /controller/test accepts a query parameter value. Regardless of whether or not you query that route with the query parameter value, all requests will hit your route controller at controller/test.
In other words, your server treats
GET /controller/test as a request to /controller/test as a request with value: undefined
and
GET /controller/test?value=2 as a request to /controller/test as a request with value: 2
Therefore, your controller should look something like (assuming you're using typescript)
interface ControllerQuery {
value?: number
}
#Get('/controller/path')
async controller( #Query query: ControllerQuery ) {
if (query.value) {
console.log(query.value);
} else {
console.log('No value provided, now what?');
}
}

Like said above, query params are not filtered by route. But you could do something like this, which would be more restful as well. That or having a search endpoint.
#Get('/path')
async without() {
console.log('without param');
}
#Get('/path/:value')
async find(#Param('value') value: string,) {
console.log(value);
}
#Get('/path/search')
async search(#Query() query) {
console.log(query);
}

Related

How to access query parameters with dots in ExpressJS

Imagine I have the following incoming request with query parameters
https://api.myawesomeapi.com/v1/facebook/group_app_install_hook?hub.mode=subscribe&hub.challenge=1409653872&hub.verify_token=myToken
then I have my express function as below to handle the incoming request above
static async appInstallOnGroupHookHandler(req, res) {
let hubChallenge = req.query["hub.challenge"]; //This is always undefined
console.log(`Hub Challenge ${hubChallenge}`);
let verificationToken = req.query["hub.verify_token"];
console.log(`Hub Verification Token=${verificationToken}`);
return res.status(200).send(hubChallenge ?? 'success');
}
When I tried accessing the hub.challenge query parameter using
let hubChallenge = req.query["hub.challenge"];
hubChallenge keeps coming back as undefined.
Is there a better way to access query parameters that has the dot character in them?
Thanks

Can't make #Get('id') to work in NestJS tutorial

So I am following this tutorial, and following it, word by word:
https://medium.com/#kaushiksamanta23/nest-js-tutorial-series-part-1-introduction-setup-c87ba810ea9e
So I have this in my service file:
getCourse(courseId): Promise<any> {
let id = Number(courseId);
return new Promise(resolve => {
const course = this.courses.find(course => course.id === id);
if (!course) {
throw new HttpException('Course does not exist', 404)
}
resolve(course);
});
}
and this in my controller, exactly like in the tutorial ,except the log:
#Get(':courseId')
async getCourse(#Param('courseId') courseId) {
console.log(courseId)
const course = await this.coursesService.getCourse(courseId);
return course;
}
In the POSTMAN, when calling http://localhost:3000/courses/courseId=3, I am getting "message": "Course does not exist"
The log clearly shows the problem:
{ courseId: 'courseId=3' }
So when I try http://localhost:3000/courses/3 instead it works, but it's not the right way.
I am lost here, my code is identical to the one in tutorial, and I thought the whole purpose of #Param('courseId') is to recognize the string 'courseId' as key and get whatever value after the '=' in the url. If so, why am I receiving 'courseId=3'? Surely I am not supposed to parse the string manually.
You're confusing URL Parameters with Query Parameters. In a URL, you can have parameters that are parsed differently depending on the route handler. In this case, your URL says that you have a base of courses and then a url parameter by the name courseId. When you make the request, the URL looks likehttp://localhost/courses/3 (the 3 is the courseId) and then you would get the id like req.param['courseId]. If you are wanting to use a URL more like http://localhost/courses/?courseId=3 then you need to use #Query() instead to get the query parameter (this would map to req.query instead of req.param)

Append parameters to URL

How can we append the parameters to path URL using axios.get() in react client?
axios.get('/api/order/user/', {
params: {
user_id: 2
}
})
the route defined in the express server is this.
router.route('/user/:user_id').get(//);
This is what return from the above axios.get() code.
GET /api/order/user/?user_id=2
What I want to achieve is something like this.
GET /api/order/user/2
How can this be achieved?
What you want to achieve is path parameter
const url = '/api/order/user/' + user_id;
axios.get(url);
The params property in axios is Query parameter
GET /api/order/user/?user_id=2

How can I put an Express REST layer on top of an Apollo GraphQL server?

I'm looking into putting a REST layer (using Express) on top of a GraphQL server (Apollo Server v2) to support some legacy apps. To share as much logic as possible, the REST endpoint should ideally wrap a GraphQL query that I'm sending to the GraphQL server, and be able to do small modifications to the response before sending the response to the client.
I'm having trouble figuring out the best way to query the apollo server from the Express routing middleware. So far I've explored two different solutions:
Modify the request from the REST endpoint such that req.body is a valid graphql query, change the req.url to /graphql, and call next(). The problem with this is that I cannot modify the result before it's being sent to the client, which I need to do.
Calling the /graphql endpoint with axios from the routing middleware, and modify the response before sending to the client. This works, but feels to me a bit hacky.
Do you have other suggestions, or maybe even an example?
I believe the solution 2 is okay to implement.
I've made a similar implementation, but in my case, a GraphQL service fetches data from another(multiple) GraphQL service(s).
And somewhere down the line I did something like this:
export type serviceConnectionType = {
endpoint: string
queryType: {
query: Object // gql Object Query
variables: {
input: Object // query arguments (can be null)
}
}
}
export async function connectService(params: serviceConnectionType) {
const response = await fetch(params.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params.queryType),
})
if (response.status === 404) {
console.warn('404 not found')
}
return response.json()
}

Express.js routing with optional param?

I have two situations to get data from DB
To show normal data
http://exampleapp.com/task/{{taskId}}
To edit data via posting
http://exampleapp.com/task/{{taskId}}/?state={{app.state}}
Both url have the same http://exampleapp.com/task/{{taskId}} just a little bit different with last phrase ?state={{app.state}}
I use Express routing as followed:
app.get('/task/:taskId/(?state=:status(pending|cancel|confirmed|deleted))?', routes.task.show);
But I dont know why it does not work ?
For example error: Cannot GET /task/51d2c53f329b8e0000000001 when going to h**p://exampleapp.com/task/51d2c53f329b8e0000000001
Query strings cannot be defined in routes. You access query string parameters from req.query.
app.get('/task/:taskId', function(req, res) {
if (req.query.state == 'pending') { ... }
});
However, if you're modifying a task, this is not the appropriate way to do it. GET requests SHOULD be idempotent: the request SHOULD NOT modify state. That's what POST requests are for.
app.get('/task/:taskId', function(req, res) {
// show task info based on `req.params.taskId`
});
app.post('/task/:taskId', function(req, res) {
// set task `req.params.taskId` to state `req.body.state`
});
You could either have a <form> that posts to the task, or make an ajax request:
$.post('/task/1', { state: 'pending' }, function() { ... });
According to the Express API, you cannot mix RegExp routes with string routes.
You should do something like this (I'm assuming taskId is an integer):
app.get(/^\/task/([0-9]+)/(?state=:status(pending|cancel|confirmed|deleted))?, routes.task.show);
However, I don't see why you cannot only check if req.query.state is defined in your route. It's probably less error prone and easier:
app.get("/task/:taskId", function( req, res, next ) {
if (req.query.state) {
// Do things
}
next();
});
Your problem is that query strings are not considered in routing. You will either have to redesign your urls (ie, include the state into the url itself, instead of the query string) or check the query string in your route handler function.

Resources