How to do error handling for GraphQL server using FSharp.Data.GraphQL in F#? - f#

I am using FSharp.Data.GraphQL for implementing GraphQL server. The documentation is not very clear about error handling. In the following mutation resolver, I wish to return errors if user provides invalid values for email and password:
let login =
Define.AsyncField(
name = "login",
typedef = Nullable Output.Token,
description = "Login using email and password",
args = [
Define.Input("email", String)
Define.Input("password", String)
],
resolve =
fun ctx _ ->
// ... some more code related to db and validation
let customErr: exn = Error.InvalidUserPassword
// This statement has not effect
ctx.AddError customErr
// Should I use raise to explicitly throw exception
// raise customErr
Async.result None
)
Looking into the source code, I found out AddError method on ResolveFieldContext. But it seems to produce no effect on the final result of the mutation. The output is always without any error:
{
"documentId": 1234,
"data": {
"login": null
},
// The errors array is not available
"errors": []
}
Should I raise the exception to add the error handling? And, if that is the case, how can I go about adding multiple error codes as part of single query or mutation since I can raise only one exception?

Related

Can't place GraphQL custom type as a Postman variable

Has anyone had luck with placing a GraphQL custom type argument as a Postman or Graphql variable? I'm kinda spinning in circles right now, I hope a fresh pair of eyes could point me in the right direction.
What I'm trying to do is to send a mutation request using Postman. The problem I'm having is that the method I'm calling is taking a custom type as an argument. Placing the content of that variable as GraphQL variable or Postman variable is giving me a headache. I can't embedd pictures yet, so here are the links (they are safe).
Schema
This custom type is a JSON-like structure, consisting of two enums and a set of primitive types (strings, ints...). I can screenshot the entire thing but basically that's it: two enums followed by strings, ints...
Custom type definition
What I've tried so far:
Simply hardcoding the request in Postman works but I wish to send multiple requests with varying data
Placing it in a GraphQL variable results in error message
{
"errors": [
{
"message": "Bad request - invalid request body.",
"locations": []
}
],
"data": null
}
Placing the custom type content as a Postman environment variable works, but I'm getting a syntax error (although the request passes...).
Request body is below. Hardcoding it and using a Postman variable produces the same request body, apart from the syntax error.
query: "mutation {
createApplication(request: {
applicationKind: NEW_ISSUANCE,
documentKind: REGULAR_PASSPORT,
personalData: {
timestamp: null,
firstname: "NAME",
lastname: "LASTNAME",
middlename: "MIDDLENAME",
dateOfBirth: "2011-09-28",
citizenshipCountryCode: "USA",
gender: MALE,
personalNumber: "3344",
placeOfBirth: "CHICAGO",
municipalityOfBirth: "SOUTH",
countryCodeOfBirth: "USA"},
addressData:{
street: "WEST",
municipality: "EAST",
place: "CHICAGO",
country: {
code: "USA",
name: null
},
entrance: "б",
flat: "13",
number: "35"}
})
{
__typename
... on AsyncTaskStatus {
taskID
state
payload {
... on ApplicationUpdated {
applicationID
applicationNumber
__typename
}
__typename
}
__typename
}
... on Error {
...errorData
__typename
}
}
}
fragment errorData on Error {
__typename
code
message
}"
Postman variable with a squiggly line
I'm spinning in circles right now. Has anyone had any luck with Postman requests of this kind?
I can post more info, screenshots...just let me know. I'll be watching this topic closely and provide feedback.
Thank you for your time.
please add a the variable in variable section as :
{
"request": {{request}}
}
and then refer this in your query as
$request

Problem when displaying errors in friendly way in Zapier

I'm trying to display errors in a friendly way, but I'm always getting the errors stack trace with console logs that I want to get rid of.
The idea is to create a Lead in our platform using any source, for example, Google Sheets.
When an invalid email is provided in the lead and posted to our API, I'm getting the expected message I want to display followed by the stack trace.
My custom error message is
INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail.
But this is what I'm getting:
INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail. What happened: Starting POST request to https://cosmo-charon-production.herokuapp.com/v1/lead/vehicle Received 500 code from https://cosmo-charon-production.herokuapp.com/v1/lead/vehicle?api-key=gIBp04HVdTgsHShJj6bXKwjbcxXTogsh after 62ms Received content "{"code":"SCHEMA_VALIDATION_FAILED","message":"Request validation failed: Parameter (lead) failed sch" INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail. Console logs:
Image showing error displayed in Zapier
I've added a middleware for ErrorHandling into afterResponse, just as one of the examples provided in Zapier docs.
The function analyzeAndParse() receives an error object from the API and returns a string with the error message translated in a friendly way
const checkForErrors = (response, z) => {
// If we get a bad status code, throw an error, using the ErrorTranslator
if (response.status >= 300) {
throw new Error(analyzeAndParse(response.json))
}
// If no errors just return original response
return response
}
This is the code that creates a Lead in our platform, making a request to our API.
function createLead (z, bundle) {
const industry = bundle.inputData.industry
// add product to request based on the inputFields
leadType[industry].addProductFields(bundle.inputData)
const requestOptions = {
url: `${baseUrl}lead/${_.kebabCase(industry)}`,
method: 'POST',
body: JSON.stringify(checkSourceForCreate(bundle.inputData)),
headers: {
'content-type': 'application/json'
}
}
return z.request(requestOptions).then((response) => {
if (response.status >= 300) {
throw new Error(analyzeAndParse(response.content))
}
const content = JSON.parse(response.content)
if (content && content.leads) {
// get only the last lead from the list of leads
content.lead = content.leads[0]
delete content.leads
}
return content
})
}
Any ideas?
Thanks!

OData success message even though no new entry?

I have an SAPUI5 application which is deployed to ABAP server and accessible with Fiori Launchpad. I use this app to create a new interaction (OData Service CUAN_IMPORT_SRV) in Hybris Marketing. My problem is that even though the OData call created no new entry (because such entry already exists), I get the success message. When I add invalid data to the upload data, I get the error message.
This is my code:
var oModel = new sap.ui.model.odata.v2.ODataModel("https://hostname:port/sap/opu/odata/sap/CUAN_IMPORT_SRV/", true);
var oData = { some json... }
oModel.create("/ImportHeaders", oData, {
success: function() {
sap.m.MessageBox.success("Interaction successfully created!", {
title: "Success"
});
},
error: function() {
sap.m.MessageBox.error("Interaction could not be created.", {
title: "Error"
});
}
});
When I run /n/iwfnd/traces it is marked as "successful execution" (even though no new entry was created).
How can it be that the success message appears even though no new entry was created? How can I avoid that?
First thing is to add your business error in the ABAP backend:
DATA:
lt_bapi_return type table of bapiret2,
lo_message_container type ref to /iwbep/if_v4_message_container.
#Error handling
if lt_bapi_return is not initial.
#check if an error message is in lt_bapi_return
loop at lt_bapi_return into ls_bapi_return.
if ls_bapi_return-type = 'E'.
lo_message_container = io_response->get_message_container( ).
loop at lt_bapi_return into ls_bapi_return.
lo_message_container->add_t100(
exporting
iv_msg_type = ls_bapi_return-type
iv_msg_id = ls_bapi_return-id
iv_msg_number = ls_bapi_return-number
iv_msg_v1 = ls_bapi_return-message_v1
iv_msg_v2 = ls_bapi_return-message_v2
iv_msg_v3 = ls_bapi_return-message_v3
iv_msg_v4 = ls_bapi_return-message_v4 ).
endloop.
"raise exception
raise exception type zcx_e2e001_odata_v4_so
exporting
message_container = lo_message_container.
endif.
endloop.
endif.
And at UI:
error: function(response) {
//response will have message details
//each message can have business text, technical info, error code.
sap.m.MessageBox.error("Interaction could not be created.", {
title: "Error"
});
}
You can add this part of code to every redefined method..
better is create a util method and reuse.

Get error on GML options

I'm trying to create wfs-t service I have used the ol.format.WFS#writeTransaction method and serialize the WFS-t XML but my jslint always preview error at the GML format options. Is it possible that I am initializing the ol.format.WFS object incorrectly?
Or maybe I am passing the wrong options to the writeTransaction method? Or maybe it's a bug in OpenLayers4? this detail of my wfs-t service using angular http service:
private _transactWFS(feature: any, operation: any): any {
let payload;
try {
const formatWFS = new ol.format.WFS({});
const formatGML = new ol.format.GML({
featureNS: operation.featureNS,
featureType: operation.featureType,
srsName: operation.srsName
});
const xs = new XMLSerializer();
let node: any = null;
switch (operation.mode) {
case 'insert':
node = formatWFS.writeTransaction([feature], null, null, formatGML);
break;
case 'update':
node = formatWFS.writeTransaction(null, [feature], null, formatGML);
break;
case 'delete':
node = formatWFS.writeTransaction(null, null, [feature], formatGML);
break;
}
payload = xs.serializeToString(node);
} catch (error) {}
return payload;
}
lint message:
[ts]
Argument of type 'GML' is not assignable to parameter of type 'WFSWriteTransactionOptions'.
Property 'featureNS' is missing in type 'GML'.
From the OpenLayers WFS-T example:
// Word to the Wise from an anonymous OpenLayers hacker:
//
// The typename in the options list when adding/loading a wfs
// layer not should contain the namespace before, (as in the
// first typename parameter to the wfs consctructor).
//
// Specifically, in the first parameter you write typename:
// 'topp:myLayerName', and in the following option list
// typeName: 'myLayerName'.
//
// If you have topp included in the second one you will get
// namespace 14 errors when trying to insert features.
//
wfs = new OpenLayers.Layer.WFS(
"Cities",
"http://sigma.openplans.org/geoserver/wfs",
{typename: 'topp:tasmania_cities'},
{
typename: "tasmania_cities",
featureNS: "http://www.openplans.org/topp",
extractAttributes: false,
commitReport: function(str) {
OpenLayers.Console.log(str);
}
}
);
Seems to indicate you are building your WFS object wrong.
I'm give up using WFS Format for build WFS Transaction request so my problem was solved by myself, I found this lib geojson-to-wfs-t-2. This library is very legit for solving my problem.

axios async await function not returning validation errors

export const register = (user, callback, errorback) => async dispatch => {
try{
let response = await axios.post(`${PINGUIN_ROOT_URL}/users/create`, user)
if (response.data.auth_token){
auth_token = response.data.auth_token
dispatch({ type: REGISTER_SUCCESS, payload: auth_token})
callback()
} else {
let error = response
throw error
}
}catch(error){
dispatch({type: REGISTER_FAIL})
errorback()
}
Hi, I am building a login register based off of what we have learned. It works but for some reason the error validations wont come back. I built a rails api and I see the validation errors when I use postman but when I try to get the errors back using redux the register function above gets to the "let response = .." line and immediately goes to the catch(error) line. I dont know how to pass back the actual validation errors that I see when I use post man because the error that is being caught is the following:
Error: Request failed with status code 422
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:538)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:381)
at XMLHttpRequest.js:485
at RCTDeviceEventEmitter.emit (EventEmitter.js:181)
at MessageQueue.__callFunction (MessageQueue.js:250)
at MessageQueue.js:101
Now again, the code is working when it actually logs in the user however it fails to actually give me the validation errors that I need. I see the validation errors comming back as json in postman but i do not get to see them in practice. Help please?
You can get the response object from your error object as error.response
try{
let response = await axios.post(`${PINGUIN_ROOT_URL}/users/create`, user)
...
} catch(error){
console.error(error.response)
}

Resources