GraphQL requesting fields that don't exist without error - graphql

I'm trying to handle backwards compatibility with my GraphQL API.
We have on-premise servers that get periodically updated based off of when they connect to the internet. We have a Mobile app that talks to the on-premise server.
Problem
We get into an issue where the Mobile app is up to date and the on-premise server isn't. When a change in the Schema occurs, it causes issues.
Example
Product version 1
type Product {
name: String
}
Product version 2
type Product {
name: String
account: String
}
New version of mobile app asks for:
product(id: "12345") {
name
account
}
Because account is not valid in version 1, I get the error:
"Cannot query field \"account\" on type \"Product\"."
Does anyone know how I can avoid this issue so I don't recieve this particular error. I'm totally fine with account coming back with Null or just some other plan of attack for updating Schema's. But having it completely blow up with no response is not good

Your question did not specify what you're actually using on the backend. But it should be possible to customize the validation rules a GraphQL service uses in any implementation based on the JavaScript reference implementation. Here's how you do it in GraphQL.js:
const { execute, parse, specifiedRules, validate } = require('graphql')
const validationRules = specifiedRules.filter(rule => rule.name !== 'FieldsOnCorrectType')
const document = parse(someQuery)
const errors = validate(schema, document, validationRules)
const data = await execute({ schema, document })
By omitting the FieldsOnCorrectType rule, you won't get any errors and unrecognized fields will simply be left off the response.
But you really shouldn't do that.
Modifying the validation rules will result in spec-breaking changes to your server, which can cause issues with client libraries and other tools you use.
This issue really boils down to your deployment process. You should not push new versions of the client that depend on a newer version of the server API until that version is deployed to the server. Period. That would hold true regardless of whether you're using GraphQL, REST, SOAP, etc.

Related

Parse iOS SDK not sending application Id

I'm testing out deploying my own parse server following the steps in the Parse Server Guide. I've got the server up and running and have been able to create and fetch objects via curl. I built a simple iOS app using the Parse SDK (1.14.2). I've initialized the SDK with the app id and server url as described in the Parse Server Guide. When I try to make requests, I get back unauthorized from the server. Digging further, I noticed that the SDK is not sending the application id header to the server. I modified the SDK to send the application id header and everything works. Am I missing a configuration step somewhere?
This is because you are not passing the ClientKey. In swift 3 you would pass it like this in the didFinishLaunchingWithOptions.
// Init Parse
let configuration = ParseClientConfiguration {
$0.applicationId = PARSE_APP_KEY
$0.clientKey = PARSE_CLIENT_KEY
$0.server = PARSE_SERVER_URL
$0.isLocalDatastoreEnabled = true
}
Parse.initialize(with: configuration)
If you are falling when trying to test CloudCode, then its because your parse-server is not passing the Javascript key. So just make sure you initialize the server to do so if this issue is related to Parse.Cloud function.

CRM: What is the difference between update Plugin and Update in XrmServiceToolkit

Is there any difference between updating an entity using a Plugin vs Updating an entity using XrmServiceToolkit?
var entityA= new XrmServiceToolkit.Soap.BusinessEntity("entA", id);
entityA.attributes["attrA"] = { value: attrValue1, type: "OptionSetValue" };
entityA.attributes["attrB"] = { value: attrValue2, type: "Money" };
XrmServiceToolkit.Soap.Update(entityA);
I know plugin can be used to connect to external databases but for a very basic update, is there any difference?
Thank you!
Operations in plugins are seemless integrated with the business logic of your CRM platform. Plugins are invoked in any scenario, regardless if they are triggered by a webpage (Javascript calls, e.g. using XrmServiceToolkit), workflow, external systems, integration tools or even other plugins.
An update done on your web page by Javascript only works on that form. If you only need it there, it's fine. If you need to cover other scenarios as well, you may have to look for another solution.

Google Drive SDK 1.8.1 RedirectURL

Is there any way to provide RedirectURL then using GoogleWebAuthorizationBroker?
Here is the sample code in C#:
Task<UserCredential> credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, GoogleDataStore.User, cancellationToken, dataStore);
Or we have to use different approach?
I have an "installed application" that runs on a user's desktop, not a website. By default, when I create an "installed application" project in the API console, the redirect URI seems to be set to local host by default.
What ends up happening is that after the authentication sequence the user gets redirected to localhost and receives a browser error. I would like to prevent this from happening by providing my own redirect URI: urn:ietf:wg:oauth:2.0:oob:auto
This seems to be possible using Python version of the Google Client API, but I find it difficult to find any reference to this with .NET.
Take a look in the implementation of PromptCodeReceiver, as you can see it contains the redirect uri.
You can implement your own ICodeReceiver with your prefer redirect uri, and call it from a WebBroker which should be similar to GoogleWebAuthorizationBroker.
I think it would be great to understand why can't you just use PrompotCodeReceiver or LocalServerCodeReceiver.
And be aware that we just released a new library last week, so you should update it to 1.9.0.
UPDATE (more details, Nov 25th 2014):
You can create your own ICodeReceiver. You will have to do the following:
* The code was never tested... sorry.
public class MyNewCodeReceiver : ICodeReceiver
{
public string RedirectUri
{
get { return YOU_REDIRECT_URI; }
}
public Task<AuthorizationCodeResponseUrl> ReceiveCodeAsync(
AuthorizationCodeRequestUrl url,
CancellationToken taskCancellationToken)
{
// YOUR CODE HERE FOR RECEIVING CODE FROM THE URL.
// TAKE A LOOK AT THE FOLLOWING:
// PromptCodeReceiver AND LocalServerCodeReceiver
// FOR EXAMPLES.
}
}
PromptCodeReceiver
and LocalServerCodeReceiver.
Then you will have to do the following
(instead of using the GoogleWebAuthorizationBroker.AuthorizeAsync method):
var initializer = new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets,
Scopes = scopes,
DataStore = new FileDataStore("Google.Apis.Auth");
};
await new AuthorizationCodeInstalledApp(
new GoogleAuthorizationCodeFlow(initializer),
new MyNewCodeReceiver())
.AuthorizeAsync(user, taskCancellationToken);
In addition:
I'll be happy to understand further why you need to set a different redirect uri, so we will be able to improve the library accordingly.
When I create an installed application the current PromptCodeReceiver and LocalServerCodeReceiver work for me, so I'm not sure what's the problem with your code.

Setting UUID manually

My server generates UUID for uploaded files, so i need to set UUID to the fileState after i received answer from upload server (to successfully use delete function). I added and implemented
setUuid: function(id, uuid)
In UploadHandler, FineUploaderBasic and UploadHandlerXhr to solve this issue but this involve editing fine-uploader sources, is there any other way around? I have feeling this can break something internally.
I would suggest not passing the UUID back to fine uploader. It would be simpler to associate your UUID with fine uploader's UUID server side. You could maintain a map of associations in the session if you don't want to persist them.
I encountered this issue and found some documentation that states you can set the UUID from the server side by returning it from the upload method.
click image where newUuid is being set
Here is my return method using C#
return new FineUploaderResult(true, new { newUuid = attachmentId });

How can a client query a db4o server?

I've set up a db4o server and client. My client calls are not working.
What's puzzling to me is that the db4o examples show how the client can close the server, but not how to get and save data. See: http://community.versant.com/Documentation/Reference/db4o-7.12/java/reference/Content/client-server/networked/simple_db4o_server.htm
If I start the db4o server, and run netstat, I can see that the port is open. And on the client, I can do things like this:
Debug.WriteLine(db.Ext().IsClosed().ToString());
And that returns False, which is good.
But when I try to get or save data, it doesn't work. When saving data, it appears to work, but I don't see the data in the DB. When trying to retrieve the object, I get this error:
Db4objects.Db4o.Ext.Db4oException: Exception of type 'Db4objects.Db4o.Ext.Db4oException' was thrown. ---> System.ArgumentException: Field '_delegateType' defined on type 'Db4objects.Db4o.Internal.Query.DelegateEnvelope' is not a field on the target object which is of type 'Db4objects.Db4o.Reflect.Generic.GenericObject'.
Here are the client calls to save, then get:
Server server = new Server() { Name = "AppServerFoo" };
IObjectContainer db = GetDatabase();
db.Store(server);
db.Close();
Here's the only line in the GetDatabase() method:
return Db4oClientServer.OpenClient(Db4oClientServer.NewClientConfiguration(), "DellXps", 8484, "user", "password");
And here's the call to get from the DB:
IObjectContainer db = GetDatabase();
Server testServer = db.Query<Server>(server => server.Name == "AppServerFoo").FirstOrDefault();
db.Close();
What am I missing?
Well a server without a reference the persisted classes is a 'risky' thing. A lot of functionally doesn't work and the error which occur are cryptic. I highly recommend to always reference the assembly with the persisted classes on the server.
Another tip: Use LINQ instead of native queries. It works better and has less problems.
A ha! I got it. It took some googling, but the problem was that the server didn't have a reference to the entities. As soon as my server project referenced my client project, it worked. So, it looks like I just need to move my entities to a common project that both the client and server can reference.
Thanks to this link:
http://www.gamlor.info/wordpress/2009/11/db4o-client-server-and-concurrency/
This link looks like a gateway to having the server work without referencing the entities:
http://community.versant.com/Documentation/Reference/db4o-7.12/net2/reference/html/reference/client-server/server_without_persistent_classes_deployed.html

Resources