-
-
Notifications
You must be signed in to change notification settings - Fork 328
Description
I'm working on a ShopifySharp.Experimental package that I plan to publish to Nuget in the next few days. I want to use this package as a testing ground for new ideas that won't necessarily make it into ShopifySharp on the first iteration. I won't promise stability in this package between releases, I expect there will be breaking changes quite often, so don't use it in a production app.
The first experiment I'm doing is to fix the major issue this package has with updating/creating objects (#379) (#373) (#367) (#284). You have to be able to send null to the Shopify API, but it's far too easy to send null for a property that you didn't intend. In practice, I've added a hard rule for my apps that first I need to pull in the entire Shopify object, set the one single property I want to change on it, and then send that entire object back to Shopify -- just to make sure I don't accidentally erase a field.
In my experiment, I'm setting up an F# module which will explicitly build each property of an object so you know exactly what will be sent when creating and updating. Null will never be sent if you don't explicitly add the property and set it to null. Other properties will not be sent at all if you don't add them.
Here's what the intended usage looks like once I've got this finished:
open ShopifySharp.Experimental
let webhook =
newWebhook
|> address "https://example.com"
|> topic "app/uninstalled"
// Serialized to JSON, this looks like:
// { "address": "https://example.com", "topic": "app/uninstalled" }Note that the format, metafield_namespaces, created_at, updated_at fields are not null like they would be if you serialized the regular ShopifySharp.Webhook class -- they just aren't in the JSON at all.
If you want to set a property to null, you'll use makePropertyNull:
let webhook =
newWebhook
|> address "https://example.com"
|> topic "app/uninstalled"
|> makePropertyNull WebhookProperty.Format
// Serialized to JSON, this looks like:
// { "address": "https://example.com", "topic": "app/uninstalled", "format": null }If you need to remove a property from the object for whatever reason, you'll use removeProperty:
let webhook =
newWebhook
|> address "https://example.com"
|> topic "app/uninstalled"
|> format "json"
|> removeProperty WebhookProperty.Format
// Serialized to JSON, this looks like:
// { "address": "https://example.com", "topic": "app/uninstalled" }In the background, the webhook builder is just using an F# Map<WebhookProperty, obj option> which is roughly equivalent to a C# IReadOnlyDictionary. So if you really want to dig in to add custom properties or raw values that don't match the types on the helper functions, you'd be able to do that:
let webhook =
newWebhook
|> address "https://example.com"
|> Map.add (WebhookProperty.CustomProperty "some_property") (Some (box 5))
// Serialized to JSON, this looks like:
// { "address": "https://example.com", "some_property": 5 }This makes liberal use of F# types, which can sometimes be difficult to use from C#. If this experiment makes it into the main package, I'd wrap all of the F# stuff in a fluent-style class for C#. I haven't specced that out yet, but in my head it'd look something like this:
var webhookBuilder = WebhookBuilder.NewWebhook()
.WithAddress("https://example.com")
.WithTopic("app/uninstalled")
.WithFormat("json")
.WithNullProperty(WebhookProperty.Topic)
.WithCustomProperty("some_property", 5);One thing I haven't figured out is how I'll merge the F# code into the C# package. I'd personally like to create a ShopifySharp.Functional package, which is where I imagine this F# webhook builder would be published. But I don't know that I want to have ShopifySharp itself add a dependency for the F# package, or bring in the FSharp.Core dependency.