Customizing Laravel validation JSON message format - Laravel - laravel-8

I'm trying to figure out how to customize the Form requests to validate
By default Laravel gives a good enough JSON format for validation errors but what if we want to customize it?
{
"message": "The given data was invalid.",
"errors": {
"email": [
"Please enter email address."
],
"password": [
"Please enter password."
]
}
}
for a particular project, we decided to change the format to this.
{
"success": false,
"errors": [
{
"email": "Please enter an email address."
},
{
"password": "Please enter a password."
}
]
}
Any help would be great.
Regards.

Please try the following.
public function render($request, Throwable $e)
{
if ($e instanceof ValidationException) {
// Custom response
$response = [
'success' => false,
'error' => $e->errors()
];
return response()->json($response, 422);
}
return parent::render($request, $e);
}

Related

How to protect against email enumeration on sign-up

Google suggest to Enable email enumeration , but despite that being enabled, when a user (with intention to discover if the given email address exists on the app) tries to sign up ( register) with a email and if the email exists, the Google Identity-platform reveals that the emails does exists.
{
"error": {
"code": 400,
"message": "EMAIL_EXISTS",
"errors": [
{
"message": "EMAIL_EXISTS",
"domain": "global",
"reason": "invalid"
}
]
}
}
Below is the partial out of the fact that the Email protection is enabled
{
"name": "projects/601070666666/config",
"signIn": {
"email": {
"enabled": true,
"passwordRequired": true
},"emailPrivacyConfig": {
"enableImprovedEmailPrivacy": true
}
I followed all the steps

Why doesn't GraphQL.NET honour the errors.extensions schema?

I recently rewrote some GraphQL services from Java to .NET Core.
In Java, I was able to provide custom error messages to the clients using the errors.extensions in the response, ie:
{
"data": {
"someMutation": null
},
"errors": [{
"cause": null,
"message": "Unauthorized",
"httpStatusCode": 0,
"extensions": {
"uiMessage": "Oh no, your session expired. You'll need to login again to continue.",
"httpStatusDescription": "Unauthorized",
"httpStatusCode": 401
},
"errorType": "ValidationError",
"path": null,
"localizedMessage": "Unauthorized",
"suppressed": []
}
]
}
However, in .NET, I don't seem to be able to replicate this format.
ErrorInfo.Extensions is added to the root of the response, not to the the Errors object itself, eg:
{
"data": {
"someMutation": null
},
"errors": [{
"message": "Auth token not provided"
}
],
"extensions": {
"httpStatusCode": 401,
"httpStatusDescription": null,
"uiMessage": "Oh no, your session expired. You'll need to login again to continue.",
}
}
The GraphQL spec reads (ref https://spec.graphql.org/October2021/#sec-Errors, https://spec.graphql.org/October2021/#example-8b658):
GraphQL services may provide an additional entry to errors with key
extensions. This entry, if set, must have a map as its value. This
entry is reserved for implementors to add additional information to
errors however they see fit, and there are no additional restrictions
on its contents.
eg:
{
"errors": [
{
"message": "Name for character with ID 1002 could not be fetched.",
"locations": [{ "line": 6, "column": 7 }],
"path": ["hero", "heroFriends", 1, "name"],
"extensions": {
"code": "CAN_NOT_FETCH_BY_ID",
"timestamp": "Fri Feb 9 14:33:09 UTC 2018"
}
}
]
}
I created a new test project (.NET Core 3.1) using the latest versions of the libraries (GraphQL 7.1.1 et al) but am still unable to add custom properties to errors.extensions.
This is the test mutation which intentionally throws an exception:
Field<StringGraphType>("greet")
.Argument<NonNullGraphType<StringGraphType>>("name")
.Resolve(context => {
try {
throw new Exception("Invalid input");
return "Hello " + context.GetArgument<String>("name");
} catch(Exception ex) {
// This doesn't seem to get returned anywhere in the response
Dictionary<String, object> extraData = new Dictionary<string, object>();
extraData.Add("error1", "message1");
// Add the error to the response using the overloaded constructor
context.Errors.Add(new ExecutionError("Oh dear, that went wrong", extraData));
// This gets added to the root of the response
context.OutputExtensions.Add("error2", "message2");
return null;
}
});
the mutation to invoke it:
mutation {greet(name:"Chewbacca")}
and the response (I don't know where errors.extensions.details comes from):
{
"errors": [
{
"message": "Oh dear, that went wrong",
"extensions": {
"details": "GraphQL.ExecutionError: Oh dear, that went wrong"
}
}
],
"data": {
"greet": null
},
"extensions": {
"error2": "message2"
}
}
I would imagine that the GraphQL.NET library would expose an Extensions dictionary on the ExecutionError object so one could add custom values in the usual manner, eg:
ExecutionError executionError = new ExecutionError("Oh dear, that went horribly wrong");
executionError.Extensions.Add("customError", "Your custom error here")
context.Errors.Add(executionError);
Which would result in a response similar to this:
{
"data": {
"someMutation": null
},
"errors": [{
"message": "Oh dear, that went horribly wrong",
"extensions": {
"customError": "Your custom error here"
}
}
]
}
I am hopeful that some bright individual in the community can (slap me upside the head and) point me in the right direction.

SkillsFuture Credit Pay Not working properly

We are using the API /skillsFutureCredits/claims/encryptRequests with the following payload
{
"claimRequest": {
"course": {
"id": "TGS-2020002051",
"fee": "1.00",
"runId": "278849",
"startDate": "2022-04-28"
},
"individual": {
"nric": "T5001077A",
"email": "abc#abc.com",
"homeNumber": "87654321",
"mobileNumber": "12345678"
},
"additionalInformation": "any additional information"
}
}
We get the encrypted response back and run /skillsFutureCredits/claims/decryptRequests with the following payload
{ "claimRequestStatus": "eyJ2IjoiIiwiaXYiOiJ4eS9XTGdiM3l2cHNEK1VENzh3TVFBa1BSWGpHSzhzbmJ0QUI4YUlTZmtNPSIsImtleXMiOnsiZGQ6YTk6YzM6NGY6Yzk6YWQ6OTY6NjQ6ZDc6YWQ6NDY6M2Q6ZDE6YmI6OGM6MDQ6Y2E6OGY6YzA6MWUiOiJWWnN1d2xacGtZdEdKZEtnV3dMblJxMGNmN1ZwK3ZXbjcvWFhEOG5TdVBJMGpRRkFIRG0vaUM5ejRPTEt4ODhST21pQ1p3WEVXU2NHd0lod2htMnBvM0ExMEdYZy80eWdDVEJhNkI1NVQ1TmdvWmlGTS9LWlBVRHFoVzFrUXQ3alB3anlTZm81Z0M5a0JtSnJDbXlJZ05veXFQV2RPcytBQ0J2SHgrUGVqT1d3T2trYThJbm9LS2NqenhHV2hKbWpoWEl2ZFM3aDUwdE10TmJQMk5wbTdvZWROeUl1OWw0Ty9BV3FWQmtYVGY2ZFRvb2J5OFJsM2JJcHhFQmp6Qy9pYzZBN3N5OGFrZDQ4Znk4WWhyTngvdXpDZ0NENVl0bElHSmFpYmt5bm55ZWNBS1NEbFdqMnNlOGdsbmdFNUZCa0hCZjdmWDVuU2VydXdmRDl4Q1MrbnRSYU5Yc3NweHJ2bE9sMmpWN0l1dENId2JvNmRnS3laMVRDSXc0Q2tta2tuY1VrcWluZk5nNjBHaFNOTXI3aGlUWmg4RnNESkJ4TmEzMFRpY1IvNExtTGdncFNyKy9HdDRweW1WTitiUDRuQ0o4QSt1L0VuVEJOcnEzZ3RCczVkYmMzdjdhT3BQTXMyTHIvK2RtdENDTEVWNWpZUkVsZDM5ZkVVd1lXUVZZOWduVFpRUTQxbUs4N3RPc04vNTJWc095djNackUzWlBCUzk0YzMrQk9sQk9zRjdBVjFZSEVHalR6R0J0cTRTLy9XVGN2d2x0Q2JmS2s3RDFjanNMWHNyN1p5cmY4c2ZYYVZWR204ZC9hUGNpWm1HM0tJNHdZVzNMR1NHOXprb2dPc3hZcFlRNm5vMFowa0RXQ2ppTG5NQS8xdG8relhQdXJoS0FMeGdWbG44UT0ifSwiY2lwaGVyIjoiRnlvV0kxRS9FelNtQnZuRTY0SWVQcGs4b2pTNTBJd1habWt6aVRvdWhrbUllQ25SMzRKaUdCejlCZVF5Y1g5c3krOE4zRlVTNEhwWTB2WFNlL1FzMnVGUlgrOXl2TUNRRWh1K2M1eG5KeUNRb3BwWEF1aUM0VklpMDB1eHpzUC92UWhVcVIwQW5CR01tbml5TnNOTUtOL3pUUmV4ZE1GMVhOVHc4eHc1cElaSnFhRjdJMGNtZ1BaQ0xqdjJiUzFKRVRpQk9yUEtmUWc4OFhHNDJ2RlI5Z1JWcVp2dVpYaXNidTJDYkczSGZ4aUpySXZVc1N0ZFlxRVRic1dpL1JVdUo0QzdpMHgwaTBsbkJoK1lHRndHWVRXQWVCLy9iUDBjdE1WbDNoL2tlbGZ6ZHZvajJYOGJIRHJVTEtXTCt2R3lXd0xMUG05NzVVdjQ2OHEwRDFLMWs0K0tPM2lEbmtDd05IVlNFYmdDRy91ckQyTGRuWWlQN1V6VU44NXVXYzBDdjNERUtCUHJ2a1RRUExkTjhOVDN2SVcxTmNicGVlK2xKc3JTZmZ5cGdLbHpaempmRzYrU2JRMHZuMG45TEFqV2NFdFZXOGR3Nk40dWo2bG4vcG9KYUlHdmxOWVdHbjd0T3V1cG95RG1PeCtKUURRbVdkTFd1cjZDY2xkcVhidGdsWFZyQkpwZTFRVWp4dHc5OTF0TGVBPT0ifQ==" }
The response we got back is error
"error": "42+fmhx6gjvNyCQsf1ktG7nFNcfsjarCS1dVJ71ehiTxJcBz9utPN6K9Dv0jpISN7U4jy7Dv5jxcueQyQbC4qq/JWX7o7Pe0OeKUSYIMT/0xaPD19yOOyxuY0y+LWDhV9VP4oTFIGM/2hhoJRuLfGwVevQdQsRh3XLfcpPccO4Xer4D2KelIFACofkn0goY1"
which when decrypt, it is an empty data. In post man, it is showing 500 internal server error but not showing us what error it is.
Any help is greatly appreciated.

how to return a validation property on a hapi reply like the way Joi library does it

I have my own custom validation on a property and I'd like to return a 400 response that is similar to the the JOI.validation that is returned on the other fields. This means that in addition to the error and message I'd like to return a validation property as well - so that the client can know which field to highlight.
So, instead of this
{
"statusCode": 400,
"error": "Bad Request",
"message": "phone validation error: invalid phone number"
}
I'd like to reply with this
{
"statusCode": 400,
"error": "Bad Request",
"message": "phone validation error: invalid phone number"
"validation": {
"source": "payload",
"keys": [
"phone"
]
}
How do I add the validation the the hapi reply?
I've been doing this - which has not been working
e.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(Boom.badRequest(e));
I'm also assuming that I cannot have custom validators for Joi, otherwise I would have just extended Joi. But, is there a Joi validation error type or object I can use in the reply to get Joi like object structure in my response.
BTW, my phone validation is not a simple regex and has special cases so I cannot use the Joi built in regex validator.
If you inspect the object returned by boom.badRequest('some message'), you'll get:
{ data: null,
isBoom: true,
isServer: false,
output:
{ statusCode: 400,
payload:
{ statusCode: 400,
error: 'Bad Request',
message: 'some message' },
headers: {} },
reformat: [Function] }
So you actually need to do something like
var errObj = Boom.badRequest(e);
errObj.output.payload.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(errObj);
Try this:
var errObj = Boom.badRequest(e);
errObj.validation =
{
source: "payload",
keys: [
"phone"
]
}
reply(errObj);

Accessing the Openstack API in Bluemix

For the VM capability in Bluemix, is it possible to use the OpenStack API? If so, how do you access it?
I'm trying to use these URLs :
https://keystone2.open.ibmcloud.com/v2.0/tokens (POST) with this payload:
{"auth": {
"tenantName": "myTenant",
"passwordCredentials": {"username": "myUser", "password": "myPwd"}
} }
https://keystone2.open.ibmcloud.com/v3/auth/tokens (POST) with this payload :
{ "auth": { "identity": {
"methods": [ "password" ],
"password": { "user": { "id": "myID", "password": "myPWD" } }
} } }
In both cases, I get this answer:
error: {
message: "KS-58299FC La requête que vous avez faite nécessite une authentification."
code: 401
title: "Unauthorized"
}
What's my mistake?
Thanks in advance.
You need to login using the OpenStack credentials, not your Bluemix ID. To see those credentials, in the Bluemix dashboard, go to Mange Organization > Manage Infrastructure, and select Show Credentials. It will display data that looks something like this:
{
"auth_url": "https://keystone2.open.ibmcloud.com",
"tenant": "TENANT",
"credentials": {
"username": "USER",
"password": "PWD"
}
}
Then run the command with the body you had, but using these credentials:
{"auth": {
"tenantName": "TENANT",
"passwordCredentials": {"username": "USER", "password": "PWD"}
} }
This should be the POST body looks like if you want to get the auth token:
{
"auth": {
"tenantName": "demo",
"passwordCredentials": {
"username": "demo",
"password": "secretsecret"
}
}
}
and the URL should be: https://keystone2.open.ibmcloud.com/v2.0/tokens
Please refer: http://developer.openstack.org/api-ref-identity-v2.html
After got the token you can access all the resources provide by OpenStack.