New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When creating an inquiry-offer-order, associate the offer and order in the mutation #2974
Conversation
No idea why the schema has been ruined by my pr and not the first time weirdness has happened when it dumped in the commit hook. I'll dig in and fix. |
Mutation: { | ||
// monkey-patch the existing exchange mutation | ||
// to add operations dependent on impulse | ||
commerceCreateInquiryOfferOrderWithArtwork: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question @starsirius: here we are basically re-using the exchange name. Is this name good or you have other suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this follows the pattern so I'm 👍 !
} = args | ||
|
||
try { | ||
await conversationLoader(impulseConversationId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. We are talking to both Exchange and Impulse, and before we create an Exchange order with a given Impulse conversation id, we want to verify if it's legit (e.g. conversation exists, user is authorized to access it, etc.).
I'm thinking verifying this kind of external id can be optional and we can leave it to the actual service (i.e. Impulse in this case) to verify eventually. For example, if an invalid Impulse conversation id is provided, the create conversation order loader below should fail. We can still be extra cautious here and monitor the performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@starsirius we just wanted to make sure we verify the validity of the conversation ID and authenticate the user before creating the exchange order (deligateToSchema
function below) since we cannot roll back the exchange mutation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our case here would be to validate that the 'conversation id' is something more than just an arbitrary string. Either exchange could do it (call impulse) or metaphysics could do it, which gives us the additional user access check before any data is changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'm fine being extra cautious here! 👍 I was mainly thinking it's hard to control external records (e.g. impulse conversations can be deleted in the future) so a broken link may not be that bad as long as the external service does proper check like authorization. And in our case, we cannot roll back the exchange order just created but it would eventually expire and buyers have to start a new one (after we do this).
You may need to pull latest. I'm noticing you're editing the |
…ulse Co-authored-by: sepans <sepans@sepans.com>
6b9e7aa
to
feaf75b
Compare
Mutation: { | ||
// monkey-patch the existing exchange mutation | ||
// to add operations dependent on impulse | ||
commerceCreateInquiryOfferOrderWithArtwork: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wondering if this needs to be stitched in at all? this looks like a new mutation, which requires data from two services. Should it perhaps be a regular mutation in Metaphysics? it can use fetch
or something to hit the Exchange GraphQL endpoint (although there's a more graphql-tools
-y way of hitting a GraphQL endpoint in an ad-hoc way).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We used fetch
to meet a similar challenge in causality's stitching file (maybe lot.ts
actually) but the issue there is passing the queried fields on to fetch
assuming we want to return the same exchange type. In causality we solved this by doing querying every field but it might be worth looking into.
@@ -349,6 +350,93 @@ export const exchangeStitchingEnvironment = ({ | |||
}, | |||
}, | |||
}, | |||
Mutation: { | |||
// monkey-patch the existing exchange mutation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of monkey-patching, this mutation can be excluded from being included with the Exchange schema (via this transform, and then this mutation can be defined more conventionally inside MP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We started out with that approach, then decided it might be more clear to follow the exchange convention. So something like Mutation.createInquiryOffer
but defined in this stitching file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not following the stitching use-case exactly. Per https://github.com/artsy/metaphysics/pull/2974/files#r570581737 basically, I would probably stick with a regular Metaphysics mutation at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready for final review!
I changed the naming to createInquiryOffer and got WrapQuery working to add an Order.internalID to the underlying delegateToSchema call. I did not move the mutation into the local schema (cc @mzikherman) because the tradeoffs for this were harsh when doing it for causality - because the local schema doesn’t have access to not-yet-merged schemas i am pretty sure wouldn’t be able to refer to the CommerceCreateOrderOverMutationResponse or other types so would have to come up with a completely new one. In the case of the Lot
type we did keep it there in part because there was also a SaleArtwork
on the lot type (see lot.ts
). Happy to discuss this further if it helps or folks have other ideas.
I also noticed that we don’t have access to the (presumably newer) graphql-tools FilterInterfaceFields (eg Mutation.commerceCreateInquiryOrderOfferEtc
) so i don’t think I can rename/remove the underlying query. If that is an issue we can discuss an alternative.
extend type Mutation { | ||
createInquiryOffer( | ||
input: CommerceCreateInquiryOfferOrderWithArtworkInput! | ||
): CommerceCreateInquiryOfferOrderWithArtworkPayload |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note here that we are still referencing the underlying exchange mutation types, but with a new name for the Mutation rather than monkey-patching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, so that's why you were doing this in the stitching file (vs. a regular old MP mutation).
info, | ||
transforms: [ | ||
// add orderOrError.order.internalID to the Order selectionSet | ||
new WrapQuery( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now works 🧑🤝🧑
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v nice!
@@ -50,5 +50,10 @@ export default (accessToken, userID, opts) => { | |||
}, | |||
{ method: "POST" } | |||
), | |||
conversationCreateConversationOrderLoader: impulseLoader( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i feel like createConversationOrderLoader
makes more sense, but I see all these impulse ones have the prefix conversation-
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
happy to break this convention if you say it's ok!
} = args | ||
|
||
try { | ||
await conversationLoader(impulseConversationId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I missing something, or is there a return value of this missing? Or is it just doing an exist-y check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just an exist-y check - though we could make more explicit what is going on.
Looks great! |
@@ -349,6 +356,87 @@ export const exchangeStitchingEnvironment = ({ | |||
}, | |||
}, | |||
}, | |||
Mutation: { | |||
createInquiryOffer: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since "offer" can mean 2 different things in Exchange: a "mode" of an order model and a separate model associated with an order. Let's maybe change this to createInquiryOfferOrder
to be consistent.
...restOfResolveArgs, | ||
}) | ||
}) | ||
|
||
describe("commerceCreateInquiryOfferOrderWithArtwork", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name would need to change accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have 1 naming comment otherwise looks good to me! It's also amazing that WrapQuery
was figured out! 💯
#squashongreen |
completes PURCHASE-2381
This pr creates a
createInquiryOfferOrder
mutation to make additional calls to both the exchangecreateInquiryOffer...
with impulse before and after the exchange call, failing if any request along the way fails. We ultimately return the exchange type; this could mean returning adata...orderOrError.error
from exchange or no data but anerrors
key in the graphql response.It relies onWe got this working withorder.internalID
being selected in the query - we currently have some commented-out code where we tried and failed to use aWrapQuery
transform to achieve this automatically but it didn't work so far. So for now just make sure you request theorder.internalID
.WrapQuery
🎉Consumers will have to handle a rejected request, a success with
errors
, and a success withdata.commerceCreateInquiryOfferOrderWithArtwork.orderOrError.error
.Co-authored-by: sepans sepans@sepans.com and also part of a mob session with @artsy/purchase-devs.