I need to match the following route on a Hapi server:
http://localhost:8080/messages/{deviceId}/?deviceType=phone
|___________________||________||_________||_______________|
1 2 3 4
Detail:
1 is my server url
2 is the path
3 is a parameter called deviceId, that is going to be different according to the requests.
4 is a query parameter that is attached by the emitter of the request. I do not control this attached query parameter, however I know it's always going to match ?deviceType=phone.
I tried to do as following, but the Hapi server doesn't even start..
server.route({
method: 'POST',
path: config.serverPath + '/messages/{deviceId}/?deviceType=phone',
handler: (request, reply) => {
}
});
Then I tried this:
server.route({
method: 'POST',
path: config.serverPath + '/messages/{deviceId*2}',
handler: (request, reply) => {
const parameters = request.params.deviceId.split('/');
const deviceId = parameters[0];
const attachedQueryParameter = parameters[1]; // should match '?deviceType=phone'
}
});
{deviceId*2} means that the route will match only if 2 parameters are provided.
I can then easily extract the parameters.
This route nearly works, expected when the parameters start with a '?' (error 404)...
... which is exactly the case I want to match (component n° 4 of the request starts with '?').
Can anyone help me with this tricky problem? Thanks
Tried again and still have a 404 error... My path is set to:
path: config.serverPath + '/messages/{deviceId}'
It works if I do a POST with this URL:
http://localhost:8080/messages/7d8a09d37d1e7b?deviceType=phone
But if I do a POST with this one:
http://localhost:8080/messages/7d8a09d37d1e7b/?deviceType=phone
It doesn't work... 404 error, saying 'Not found'.
I'm using hapi v15.0.1.
I found a temp. solution with this path:
path: config.serverPath + '/messages/{deviceId*}'
It works for both requests above, but with the second one the request.params.deviceId contains a '/' character at the very end...
You can set the path to
path: config.serverPath + '/messages/{deviceId}'
and use request.query to get the query parameters.
You can do it this way. No need to write cofig.serverPath. Also, you will have to use Joi for validation of query params.
path: '/messages/{deviceId}',
handler: storyController.getAllPaginatedStories,
config: {
validate: {
query: {
deviceType: Joi.string().required().valid(['phone']),
}
}
}
Related
I'm trying to make an API call from my Vue3 app. The prepared API has an endpoint like http://localhost:8888/api/dtconfigsearch, where one needs to pass a json payload like { "Modelname": "MyFancyModel"} to get the full dataset with the given modelname. Pure get functions without a payload / a body do work from my Vue3 project to the golang backend, but I'm having problems with passing a payload to the backend.
Test with curl -> ok
$ curl -XGET localhost:8888/api/dtconfigsearch -d '{"Modelname" : "MyFancyModel" }'
{"ID":4,"Modelname":"MyFancyModel","ModelId":"96ee6e80-8d4a-b59a-3524-ced3187ce7144000","OutputTopic":"json/fancyoutput"}
$
This is the expected output.
Test with javascript ok
Source file index.js:
const axios = require('axios');
function makeGetRequest() {
axios.get(
'http://localhost:8888/api/dtconfigsearch',
{
data: { Modelname : "MyFancyModel" },
headers: {
'Content-type' : 'application/json'
}
}
)
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log(err)
})
}
makeGetRequest()
Output
$ node index.js
{
ID: 4,
Modelname: 'MyFancyModel',
ModelId: '96ee6e80-8d4a-b59a-3524-ced3187ce7144000',
OutputTopic: 'json/fancyoutput'
}
$
Here, I also get the desired output.
Test within Vue fails :-(
Source in the Vue one file component:
onSelection(event) {
let searchPattern = { Modelname : event.target.value }
console.log(event.target.value)
console.log("searchPattern = " + searchPattern)
axios.get("http://localhost:8888/api/dtconfigsearch",
{
data : { Modelname : "Windshield"},
headers: {
'Content-type' : 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
.then(response => {
console.log(response.data)
})
.catch(err => {
console.log(err)
alert("Model with name " + event.target.value + " not found in database")
})
},
Output in browser:
In the image you can see in the terminal log on the right side that the backend is not receiving the body of the API call. However, in the browser information of the call there is content in the config.data part of the object tree, which is the payload / the body. The only thing that bothers me that it is not a json object, but stringified json, although it was entered as json object. According to the documentation, the parameter name (data) in the call should be correct to hold the body content of the api call.
I've tried different header information, looked if it could be a CORS issue, what it isn't to my opinion, exchanged key data with body, used axios instead of axios.get and adapted parameter, all without success. The version of the axios library is 0.27, identical for Vue and vanilla javascript. After checking successfully in javascript, I was sure that it would work the same way in Vue, but it didn't.
Now I'm lost and have no further ideas how to make it work. Maybe someone of you had similar issues and could give me a hint? I'd be very grateful for some tipps!!
In Cypress I am using cy.route() for sending the below request, but cypress is not identifying the below request send. In the route url there is a openHash value which will be different for every POST request. Is there any way to ignore the openHash value or accept what ever value displays there.
So far I have tried by giving the url in following ways in route.
url: '**/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=**',
url: '**/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=**&ajaxCall=true**',
I believe while using cy.route() the POST url need to match exactly. Could someone please advise
Cypress version: 5.4.0
Student.feature
Feature: Update student details
Background: User logged in to application
Given I should load all of the routes required for tests
Scenario: Update student details
When I am logged in as the student user
And I click on "Student" subtab
And I should see details displayed
Step definition:
import { Then, When, And } from "cypress-cucumber-preprocessor/steps";
before(() => {
Then('I should load all of the routes required for tests', () => {
cy.server();
cy.route({
method: 'POST',
url: '**student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=5fc8329a76e73&ajaxCall=true**',
delay: 2000
}).as('getStudentTabDetails');
})
})
Then('I am logged in as the student user', () => {
cy.get('[name=loginUsername]').type("Student1");
cy.get('[name=loginPassword]').type("somePassword1", { sensitive: true });
cy.contains('Login').click();
})
Then('I click on {string} subtab', (student) => {
cy.get('#main a').contains(student).click({force:true});
});
Then('I should see details displayed', () => {
cy.wait('#getStudentTabDetails', { timeout: 5000 });
});
Error:
CypressError
Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: getStudentTabDetails. No request ever occurred.
Cypress.minimatch is a tool that can be used for checking the route matchers.
By default Cypress uses minimatch to test glob patterns against request URLs.
If you’re struggling with writing the correct pattern you can iterate much faster by testing directly in your Developer Tools console.
The two routes you show in the question actually pass the minimatch test.
const url = 'http://example/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=5fc8329a76e73&ajaxCall=true';
const pattern1 = '**/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=**';
console.log( Cypress.minimatch(url, pattern1) ); // true
const pattern2 = '**/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=**&ajaxCall=true**';
console.log( Cypress.minimatch(url, pattern2) ); // true
Here is a Cypress fiddle that shows how to use the new intercept method to handle query parameters.
/// <reference types="#cypress/fiddle" />
const test = {
html: `
<p class="text-lg"></p>
<script>
setTimeout(() => {
const url = 'http://example/student/details.php?viewDetails=project&stdCount=1§ionID=1&openHash=5fc8329a76e73&ajaxCall=true';
window.fetch(url, { method: 'POST'});
}, 1000);
</script>
`,
test: `
cy.intercept({
method: 'POST',
url: '/student/details.php',
query: {
viewDetails: 'project', // whatever query parts you care about
stdCount: '1',
sectionID: '1'
}
}, {}) // Added an empty stub here, as my url does not actually exist
.as('getStudentTabDetails');
cy.wait('#getStudentTabDetails')
`
}
it('', () => {
cy.runExample(test)
});
The POST is made with native fetch(), which would not be captured in the old cy.route() method without using a polyfill.
This type of path is not working:
{ path: 'account/finalize?user=:user&token=:token', component: MyComponent }
I get route not found error when I access http://localhost:4200/account/finalize?user=devanshu&token=122323
But this is working:
{ path: 'account/finalize/:school/:token', component: MyComponent }
So, I can access http://localhost:4200/account/finalize/devanshu/122323
What is the problem here? Why is there an error in the first case?
you can use
path: 'account/finalize'
and send user and token as query Params when navigating
this.router.navigate(['/account/finalize'], { queryParams: { user: 'user', token: 'your token' } });
I think you do not need to pass these parameters:
user=:user&token=:token
You can get these parameters in the req.body
And if there is any particular component then you have to place the condition within the function.
I have a route /changepassword and I need to add to it 2 params: iduser and resetcode. To look like this: /changepassword?iduser=123&resetcode=foo
I read other things related to this (1, 2) but I couldn't figure this out. I don't have any experience in ember and I was ask to do some modifications where I work. We are using ember 1.5.1
I tried this but it's throwing me this: Uncaught Error: Assertion Failed: Error: Assertion Failed: The URL '/changepassword?test1=aaasd' did not match any routes in your application
[EDIT]
Thanks to #GJK, I know that what I need is query params, no path params.
Now, my code looks like this:
Routes:
module.exports = App.Router.map ->
...
...
#resource('change_password', path: '/changepassword')
Controller:
module.exports = App.ChangePasswordController = Ember.Controller.extend
needs: ['config', 'viewport', 'application']
queryParams: ['test']
test: null
...
...
But, when I access http://localhost:3333/#/changepassword?test=foo is transitioning to: http://localhost:3333/#/changepassword
[OLD]
This are my routes:
module.exports = App.Router.map ->
#resource 'index', path: '/', ->
#resource('account_sign_up', path: '/signup')
#resource('unsubscribe', path: '/unsubscribe')
#resource('change_password', path: '/changepassword/:test1/:test2')
Any help? Thanks!
There are two possible ways to do this:
1) Use the params variable with multiple parameters:
#resource('change_password', path: '/changepassword/:iduser/:resetcode')
model : function (params) {
console.log(params.iduser);
console.log(params.resetcode);
}
2) Use the http://guides.emberjs.com/v1.10.0/routing/query-params/ (which I'm not sure is available for 1.5)..so I didn't include an example..
router.get('/:id', function(req, res, next){console.log(req.params.id)
request(
config.API_URL + "/v1/gallery/get?id=" + req.params.id,
function (err, response, body){
console.log('###BODY###',JSON.stringify(body));
console.log('###BODY###',JSON.stringify(body.data));
res.render('gallery', { user: req.session.user, gallery: body.data, title: 'Gallery', purchased: req.session.user.outlet ? (req.session.user.outlet.purchased || []) : [], config: config });
}
);
});
I'm trying to pass the request body's data field as the gallery for this template, but upon passing body.data, in the template it says my gallery argument is undefined. As you can see above, I then console logged the body and then its field. console.log(body) yields the following output:
###BODY### "{\"err\":null,\"data\": {\"_id\":\"5d955d7431d34f862a0dbd60\",\"owner
\":null,\"caption\":\"A suspected shooting at the Washington DC Navy Yard has sh
ut down parts of the city. This is the same location where a gunman killed 12 pe
ople in 2013. After an investigation search, authorities gave the \\\"all clear.
\\\"\",\"tags\":[\"dc\",\"navyyard\",\"shooting\",\"washington\"]...
I shortened the output, but as you can see, the data field is clearly there next to data.err. However, when I run console.log('###BODY###',JSON.stringify(body.data)), I am returned ###BODY### undefined. Can anyone explain this behavior please?
Replace this:
request(
config.API_URL + "/v1/gallery/get?id=" + req.params.id,
<callback>
);
With:
request({
url: config.API_URL + "/v1/gallery/get?id=" + req.params.id,
json: true
}, <callback>);
That will instruct request to automatically parse the response body as json (assuming you're using this request module, of course).