I am using Mule 4.4 community edition
I have a GET endpoint with 4 query params:
empId ( mandatory )
collegeId ( mandatory )
subject ( either subject or score is required )
score ( either subject or score is required )
what is the best way to be doing these validations ?
Here is what I have tried but am not satisfied with the outcome ...
Validating 'empId' and 'collegeId' through Open API spec ( required attribute )
parameters:
- name: empId
in: query
description: The web user account
required: true
schema:
type: string
- name: collegeId
in: query
description: The web organisation
required: true
However if I simply pass an empty string against these , no validation is triggered ....
Tried using pattern such as :
pattern: "^[A-Za-z0-9]+$"
while this does prevent empty / null strings the error message is not satisfactory :
Invalid value ' ' for uri parameter empId.
string [ ] does not match pattern ^[A-Za-z0-9]+$
Question: Can I override the error message in Open API spec to make it something easier on the eyes ?
Now on to 'subject' and 'score' , atleast one of these should be non null or empty
Did not find anything except this link here
How do we enforce atleast one of the two has a non null / empty value ( via Open api spec 3.0.1 )
So I thought I will hand craft validation , using validators but they seem quite clunky
ex - for a simple check like 'not null or empty' have to use two validators .....
<flow name="get:employee-search" >
<validation:any doc:name="Any" >
<validation:is-not-null doc:name="Is subject not null" value="#[attributes.queryParams['subject']]" message="${validation.subject}" />
<validation:is-not-null doc:name="Is score not null" value="#[attributes.queryParams['score']]" message="${validation.score}" />
<validation:is-not-blank-string doc:name="Is subject not blank string" value="#[attributes.queryParams['subject']]" message="${validation.subject}"/>
<validation:is-not-blank-string doc:name="Is score not blank string" value="#[attributes.queryParams['score']]" message="${validation.score}"/>
</validation:any>
also if both fields are not sent then the error message for both validators shows up
Question:
should I write a groovy script to perform these simple validations
Just wanted to know if that is the best approach or something better ?
I do not think you can customize the error message solely via Open API Specs, However when you generate the flows in your application, it will create error handlers too for APIKIT validations. You can write a transform message within the bad request error handler to modify the response by checking the error message.
Now for the Validation part, you do not need to check for validation:is-not-null if you are checking validation:is-not-blank-string as the later will also check if the string is Null. Also you will have to merge the remaining two validators as well, otherwise, it will fail if the subject is empty even though the score is passed. For handling this you can use either validation:is-false or validation:all Scope.
With validation:all you will wrap the two validation:is-not-blank-string in a single scope, and it will fail only if both of the validation fails.
With the validation:is-false you can write custom weave expression in the module, that returns true if both the fields are blank. This will fail this validation (since it is not false) and you can customize the error message. Something like this
<validation:is-false doc:name="Is false"
doc:id="c62a27a4-d030-4f72-9610-eacbb74dd593"
expression="#[isBlank(attributes.queryParams.score) and isBlank(attributes.queryParams.subject)]"
message="Both Score and Subject can not be empty" />
Related
I would like to send the filter as a syntax tree, and not a query string, to Azure search. Ist that possible?
All I can find is to send the filter as a string.
I have a filter syntax like ( State eq 1 ) or ( Domain eq 'Love' ) but I'd like to send it parameterised to Azure search instead of as a string.
(It's a security thing - I'd prefer not to have to escape/wash the indata but instead let Microsoft/Azure/Lucene take care of the details as they know more about the inner workings than I do.)
Basically: I'd like to
filter =
Or (
Equal( "State", stateValue ),
Equal( "FieldName", domainValue )
)
Instead of me doing it like
filter = $"( 'State' eq {MyStringEscapeFunction(stateValue)} ) " +
"or ( 'Love' eq {MyStringEscapeFunction(domainValue)} )"
Filters in Azure Cognitive Search must be specified via the $filter parameter using OData-syntax.
https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter
Your example filter is a valid OData filter. Provided that you have an index where State is a number and Domain is text.
$filter=(State eq 1) or (Domain eq 'Love')
If I understand your question correctly, you have an application where the values 1 and 'Love' are inputs from end users. The Azure Search API will validate that the filter values are valid according to the datatype. Other than that, you are responsible for validating input to your application.
For example, assume that your input parameters are s and d for State and Domain, respectively. You risk someone trying to manipulate your filter to return results you did not intend:
yourpage.aspx?s=1&d=Love%27%20or%20Domain%20eq%20%27Hate
This could potentially cause your $filter query to become:
$filter=(State eq 1) or (Domain eq 'Love' or Domain eq 'Hate')
You are responsible for implementing validation. You must build a layer that validates end-user inputs before using it in a $filter query. Here you can validate that end users' state and domain input are limited to valid values before creating an OData filter. See examples here:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-7.0
Im trying to make a get method in Anypoint studio. I have already defined raml file with get method that looks something like this:
/kupci:
get:
queryParameters:
active:
required: false
enum:
- "true"
- "false"
I want to make a get flow that returns data from mysql database with 2 options:
if i have defined queryParam return everything from the database based of that condition
if not defined, just return everything from database
You just need a simple if else condition wherever you are creating your select query, and add a where clause if active is non empty.
SELECT field1, field2, ... FROM table
++ if(!isEmpty(attributes.queryParams.active)) 'WHERE active = $(attributes.queryParams.active)'
else ''
Note: You might need to change the above query if the datatype of the column active is Boolean. For example:
WHERE active IS $(attributes.queryParams.active)
You need to wrap this around the #[] script tag when writing in db:select as mentioned in the mule database connector docs
New to SQL, I am writing as an exercise an API middleware that checks if the information contained in some headers match a database entry ("token-based authentication"). Database access is based on GORM.
To this, I have defined my ORM as follows:
type User struct {
ID uint
UserName string
Token string
}
In my middleware I retrieve the content of relevant headers and end up with the variables userHeader and tokenHeader. They are supposed to be matched to the database in order to do the authentication.
The user table has one single entry:
select * from users
// 1,admin,admintoken
The authentication code is
var auth User
res := db.Where(&User{UserName: userHeader, Token: tokenHeader}).Find(&auth)
if res.RowsAffected == 1 {
// authentication succeeded
}
When testing this, I end up with the following two incorrect results (other combinations are correct):
with only one header set to a correct value (and the other one not present) the authentication is successful (adding the other header with an incorrect value is OK (=auth fails))
no headers set → authentication goes though
I expected my query to mean (in the context of the incorrect results above)
select * from users where users.user_name = 'admin' and users.token = ''
select * from users where users.user_name = '' and users.token = ''
and this query is correct on the console, i.e. produces zero results (ran against the database).
The ORM one, however, seems to discard non-existing headers and assume they are fine (this is at least my understanding)
I also tried to chain the Where clauses via
db.Where(&User{UserName: userHeader}).Where(&User{Token: tokenHeader}).Find(&auth)
but the result is the same.
What should be the correct query?
The gorm.io documentation says the following on the use of structs in Where conditionals:
When querying with struct, GORM will only query with non-zero fields,
that means if your field’s value is 0, '', false or other zero
values, it won’t be used to build query conditions ...
The suggested solution to this is:
To include zero values in the query conditions, you can use a map,
which will include all key-values as query conditions ...
So, when the token header or both headers are empty, but you still want to include them in the WHERE clause of the generated query, you need to use a map instead of the struct as the argument to the Where method.
db.Where(map[string]interface{}{"user_name": userHeader, "token": tokenHeader}).Find(&auth)
You can use Debug() to check for the generated SQL (it gets printed into stderr); use it if you are unsure what SQL your code generates
I have a custom field being added on user story (HierarchicalRequirement) level.
The WSAPI documentation shows the following details for the field:
c_CustomFieldName
Required false
Type string
Max Length 32,768
Sortable true
Explicit Fetch false
Query Expression Operators contains, !contains, =, !=
When trying to create a report using Custom List to identify user stories where this field is empty, I add (c_CustomFieldName = "") to the query.
And yet, the result shows rows where this field is not empty.
How can that be?
I tried querying on null, but it didn't work.
thx in advance
What you're doing should work- are you getting errors, or just incorrect data? It almost seems like it's ignoring your query altogether.
I tried to repro both with the custom list app and against wsapi directly and the following all worked as expected:
(c_CustomText = "") //empty
(c_CustomText = null) //empty
(c_CustomText != "") //non-empty
(c_CustomText != null) //non-empty
It's possible you're running into some weird data-specific edge case in your data. It may be worth following up with support.
I am using twilio to provide audio conference functionality in my rails app. When I call my conference number, twilio passes on a couple of values - including 'From' which contains the caller's phone number in international format.
I have a profile for every user in my system and in my controller I am querying the profile to provide a personalised welcome message. Every profile contains between 0 and 3 numbers (primary, secondary and cellphone) and I need to check the caller's ID against those three fields in all profiles.
When I use the console on my dev machine, the following code finds the correct profile:
Profile.find_by('+44000000000')
When I upload to heroku, I use following code instead:
name = Profile.find_by(params['From']) || 'there'
Which causes an error in my app:
2014-04-03T19:20:22.801284+00:00 app[web.1]: PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type bigint
2014-04-03T19:20:22.801284+00:00 app[web.1]: LINE 1: SELECT "profiles".* FROM "profiles" WHERE (+4400000000) ...
Any suggestion how that could be solved?
Thanks!
Additional information:
I think my problem is that I don't know how to query either the whole profile or three columns at once. Right now the code:
name = Profile.find_by(params['From'])
is not correct (params['From'] contains a phone number) because I am not telling rails to query the columns primary phone number, secondary phone number and cellphone. Neither am I querying the whole profile which would also be an option.
So the question basically is:
How can I change this code:
Profile.find_by(params['From'])
so that it queries either all fields in all profiles or just the three columns with phone numbers which each profile contains?
Is there something like Profile.where(:primary_number).or.where(:secondary_number)or.where(:cellphone) => params['From']
?
I am not familiar with twilio and not sure if this helps but find and find_by_attribute_name accepts array of values as options:
name = Profile.find_by([params['From'], 'there'] )
suppose params['From'] was here , This should generate:
SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`attribute` IN ('here', 'there')
Or:
If you are trying to build dynamic matcher at run time , which is called Meta-programming , you can try this code:
name = eval("Profile.find_by_#{params['From']) || 'there'}(#rest of query params here) ")
Update
First of all, i think you are not using find_by correctly!! the correct syntax is:
Model.find_by(attribute_name: value)
#e.g
Profile.find_by(phone_number: '0123456')
Which will call where and retrive one record, but passing a value will generate a condition that always passes, for example:
Model.find_by('wrong_condition')
#will generate SQL like:
SELECT `models`.* FROM `models` WHERE ('wrong_condition') LIMIT 1
#which will return the first record in the model since there is no valid condition here
Why don't you try:
Profile.where('primary_number = ? OR secondary_number = ? OR cellphone = ?', params['From'], params['From'], params['From'])
You can write your query like:
Profile.where("primary_number = ? or secondary_number = ? or cellphone = ?", params['From'])
Just double check the syntax, but that should do it.