After adding an operation (mutation or query) to exchange the corresponding operation has to be added to Metaphysics. Because most of the clients don't use exchange directly since exchange doesn't know anything about galleries, users or artworks and it only keeps the ID of those entities. MP pulls that data from gravity and adds that to the order object coming from exchange.
This is a temporary solution for now. Graphql has a mechanism called sticking that can infer all these from the schema and defined types. At this point stitching is not fully implemented so it needs to be done manually. If you know that stitching is enabled for exchange stop reading and delete this document immediately.
Follow this PR as a reference: artsy/metaphysics#1375
-
Copy updated exchange schema which includes the new mutation here: src/data/exchange.graphql (from exchange/_schema.graphql)
-
Add test in
src/schema/__tests__/ecommerce
similar to seller_accept_offer_mutation.test.tsSome annotations:
This mocks exchange to return
exchangeOrderJSON
(a sample order) when the mutation is called.const resolvers = { Mutation: { sellerAcceptOffer: () => ({ orderOrError: { order: exchangeOrderJSON }, }), }, } rootValue = mockxchange(resolvers)
This calls the mutation and verifies if the mutation return value matches
sampleOrder
return runQuery(mutation, rootValue).then(data => { expect(data!.ecommerceSellerAcceptOffer.orderOrError.order).toEqual( sampleOrder() ) }) })
Note: There is a limitation with this pattern of testing: it completely mocks the call to exchange so if there is a problem with the last 3 lines of the mutation code where it actually calls the exchange mutation, the test passes but the actual mutation doesn't work.
-
Add the mutation file in
src/schema/ecommerce/
similar to seller_accept_offer_mutation.tsDefine the input types of the mutation. If the mutation/query you are adding has input types similar to an already existing one, reuse that otherwise define new ones.
inputFields: OfferMutationInputType.getFields()
Output of the mutation. Most likely you don't need to change this:
outputFields: { orderOrError: { type: OrderOrFailureUnionType, }, },
offerId
needs to match the input field you have defined aboveaccessToken
andexchangeSchema
are passed to the function to be used to authenticate the call and actually pass it to exchange.mutateAndGetPayload: ( { offerId }, context, { rootValue: { accessToken, exchangeSchema } }
This is the actual mutation that is passed to exchange:
const mutation = gql` mutation sellerAcceptOffer($offerId: ID!) { ecommerceSellerAcceptOffer(input: { offerId: $offerId, }) { orderOrError { __typename ... on EcommerceOrderWithMutationSuccess { order { ${SellerOrderFields} } } ... on EcommerceOrderWithMutationFailure { error { type code data } } } } } `
sellerAcceptOffer($offerId: ID!)
is just what the mutation is called here and is arbitrary (true? does the name matter?)ecommerceSellerAcceptOffer
matches the name of the exchange mutation withecommerce
prefix. (defined in step 5)All the fields exchange need to return are defined here. The most common fields are defined here to be reused. You most likely need the
SellerOrderFields
orBuyerOrderFields
depending on what client (force vs volt) calls this mutationorder { ${SellerOrderFields} }
This is where the exchange mutation is actually being called and the result is returned back to the client.
ecommerceSellerAcceptOffer
should match the prefixed mutation name above.return graphql(exchangeSchema, mutation, null, context, { offerId, }).then(extractEcommerceResponse("ecommerceSellerAcceptOffer"))
-
Add/Update types in src/schema/ecommerce/types/ if needed:
-
Add your mutation to src/schema/schema.ts