Swagger API "required" - how much is this required? - node.js

I've created a Swagger (on nodejs/express) test API with this specification (only relevant part):
...
parameters:
- name: name
in: query
required: true
type: string
...
But I can call the url with empty paramter, for example
http://localhost/test?name=
And it works without any problem, throws no exception or any other sign. Why?

If I make a similar call from the terminal via curl or via postman, it works as well. I parsed the query from the request object and found that in this case, the query parameter is interpreted as an empty string.
Making the call via SwaggerUI is different though, as the UI will actually not make the call UNLESS the query field has a value.
Try doing console.log(req.query); in your handler. You will probably see {name: ''}. Which is legitimate, just that the value of name is an empty string.
Look at JSON4 here: Representing null in JSON. So name IS defined, but it's empty.
You will probably need to do a check for empty string values.
I hope this helps!

Related

Specify the type of parameter for DELETE request in Nodejs

I would like to do a DELETE request with unspecified number of parameters a=someValue. There is 2 main ways of supplying parameters to my understanding
Query parameters. ?a=someValue . This approach turn everything into
string and since I allow any number of parameters, I cannot know
which one is String, Boolean or Integer
Parameters in Body.This approach goes against the spec of DELETE operation to not have a body. Some server even strip away the body-content. But as I
send an json object, user can specify which type of value each of
their parameters has.
What would be your approach for this?
I'd use query parameters over body as the DELETE method has an optional body. Some clients may choose to ignore the body totally.

How to display actual value of a property which is using property expansion

I require some help on being able to get around displaying an endpoint from a SOAP Request.
Below I have a piece of code which retrieves an endpoint from a SOAP Request named 'TestAvailability' and outputs it to a file (the code is within a groovy script step).
def endpoint = testRunner.testCase.getTestStepByName('TestStep').get
Now here is the catch, in the file it outputs the endpoint as so:
ENDPOINT: ${#Project#BASE_URL}this_is_the_endpoint
The reason it displays ${#Project#BASE_URL} is because this is a variable set at project level so that the user can select their relevant environment from a drop down menu and that value will be displayed for the variable: ${#Project#BASE_URL}
But I don't want the project variable to be displayed but instead its value like so if ${#Project#BASE_URL} is set to 'testenv'
ENDPOINT: testenv_this_is_the_endpoint
My question is how do I change the code in order to display the endpoint correctly when outputted to a file?
You have a trivial issue. Since it is using property expansion in the endpoint, it request to expand it.
All you need is to change below statement
From:
testResult.append "\n\nENDPOINT: " +endpoint
To:
testResult.append "\n\nENDPOINT: ${context.expand(endpoint)}"

How to make optional params name in express route?

Here is below my code of route:-
app.get('/server/lead/get/:id?', leadCtrl.get);
app.get('/server/lead/filter/:filterQuery', leadCtrl.get);
As you see above i am using different route to access same controller method leadCtrl.get.
Now, i want something like route app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get params either req.params.id or req.params.filter but only one at a time.
What you asked in the question is not possible in the form that you describe it.
Now, i want something like route
app.get('/server/lead/get/:id?:filter?', leadCtrl.get);. So, i can get
params either req.params.id or req.params.filter but only one at a
time.
Your router would have no way to differentiate those two parameters. If it got a request to /server/lead/get/X then what is X? A filter or an ID?
Your options
You have few solutions here:
You can either keep using two routes like you did before.
You can use a common parameter for both cases as Robert explained in the comments.
Or you can use what seems to me the perfect solution for your use case - named query parameters - just use a route /server/lead/get and use query parameters to pass id and the filter.
Example URLs:
/server/lead/get?id=xxx
/server/lead/get?filterQuery=xxx
You will only have to make sure in your handler that only one of those two are set at a time with something like:
if (req.query.id && req.query.filterQuery) {
// respond with error
}
You can even mix the two if you have app.get('/server/lead/get/:id?') route you can have the id in the route and filterQuery as a query parameter. Now the URLs would be:
/server/lead/get/xxx (for id)
/server/lead/get?filterQuery=xxx (for filter)
For more info see: http://expressjs.com/en/api.html#req.query
Better way
If you follow some REST conventions then you can use:
app.get('/server/lead/:id') for one object with id (not optional)
app.get('/server/lead') for a list of objects (with optional filterQuery passed as a query parameter)
That way you would always know that when you access:
/server/lead/xxx - then it's one object with ID = xxx
/server/lead - then it's a list of any objects
/server/lead?filterQuery=xxx - then it's a list of objects that match the query
If you follow the REST conventions for things like this instead of inventing your own, it would be much easier for you to design the routes and handlers, and it would be much easier for other people to use your system.
You may also want to use plural /server/leads instead of /server/lead which is common with REST. That way it will be more obvious that leads is a list and leads/id is one of its elements.
For more info see:
https://en.wikipedia.org/wiki/Representational_state_transfer
http://www.restapitutorial.com/lessons/whatisrest.html
https://spring.io/understanding/REST
You have to realize that the following two routes match exactly the same:
app.get('/server/lead/get/:id?', leadCtrl.get);
app.get('/server/lead/get/:filter?', leadCtrl.get);
Express doesn't care about how you name the placeholders, so any requests for /server/lead/get/SOMEVALUE will always match the first (the one with :id).
You can add a distinction yourself, by only allowing a parameter to match a particular regular expression. From your code, it looks like :id should match MongoDB ObjectId's, so you can create a specific match for those:
app.get('/server/lead/get/:id([a-fA-F0-9]{24})?', leadCtrl.get);
If SOMEVALUE matches an ObjectId, it will call leadCtrl.get and populate req.params.id. If you also add another router for "the rest", you can also cover the req.params.filter case:
app.get('/server/lead/get/:filter?', leadCtrl.get);
As an aside: you're saying that you're passing JSON to the "filter" routes, in the URL. I would strongly suggest using a POST route for that, and post the JSON as request body content.

Using 'querystring.parse' built-in module's method in Node.JS to read/parse parameters

Scenario:
Consider the following code:
var querystring = require('querystring');
var ParamsWithValue = querystring.parse(req._url.query);
Then I am able to read any query string's value.
E.g: If requested string is http://www.website.com/Service.aspx?UID=Trans001&FacebookID=ae67ea324
I can get the values of query string with codes ParamsWithValue.UID & ParamsWithValue.FacebookID respectively.
Issue: I am able to get the values of any number of parameters passed in the same way described above. But for second time onwards I am getting the following error in response on browser.
Error:
{"code":"InternalError","message":"Cannot read property 'query' of undefined"}
Question: What is wrong in the approach to read the query string from the URL.
Note: I don't want to use any frameworks to parse it. I am trying to depend on built-in modules only.
Update: It responds correctly when the value of any of the parameter is changed. But if the same values requested again from even different browser it throws same error.
I think you need req.url rather than req._url.
req.url is a string, if you want a URI instance use require('url').parse(req.url)
So, you should finally have:
var ParamsWithValue = querystring.parse(require('url').parse(req.url).query);
Edit: I corrected a typo in point 1, the last req.url -> req._url

NodeJS url.parse( url ).query

In the nodejs documentation:
query: Either the 'params' portion of the query string, or a querystring-parsed object.
Example: 'query=string' or {'query':'string'}
Link: NodeJS URL
This part is confusing.
When will 'query=string' happens?
When will this
{'query':'string'} also happens?
I have seen that when I do url.parse() it automatically converts the parameters into an object. My code will be buggy if I only support one format.
How will I know if url.parse() converts the parameters in this format: 'query=string'?
url.parse(urlStr, [parseQueryString], [slashesDenoteHost])
If you pass true as the second argument it will also parse the query string using the querystring module and you will get an object {'query':'string'}, otherwise the query string will not be parsed (default behavior) and you will get query=string.

Resources