Les 30: Inhoud distribueren van een upstream naar meerdere downstream sites
Stel dat een mediabedrijf een netwerk van WordPress-sites heeft voor verschillende regio's, waarbij elk nieuwsartikel alleen op een site wordt gepubliceerd als het geschikt is voor die regio.
In deze situatie is het zinvol om een architectuur te implementeren waarbij:
- Alle inhoud wordt gepubliceerd op (en bewerkt in) één upstream WordPress-site, die fungeert als de enige bron van waarheid voor inhoud
- Geschikte inhoud wordt gedistribueerd naar (maar niet bewerkt in) elk van de regionale downstream WordPress-sites
Deze tutorialles laat zien hoe je deze architectuur implementeert, waarbij de upstream WordPress-site de relevante Gato GraphQL-extensies actief moet hebben, terwijl de downstream sites alleen de gratis Gato GraphQL-plugin nodig hebben.
GraphQL query om inhoud te synchroniseren van upstream naar downstream sites
(Alleen voor downstream sites) Om deze GraphQL query te laten werken, moet de Schemaconfiguratie die op het endpoint is toegepast Geneste Mutaties hebben ingeschakeld
De onderstaande GraphQL query wordt uitgevoerd op de upstream WordPress-site, om de inhoud van de bijgewerkte post te synchroniseren met de relevante downstream sites, waarbij de post-slug als gemeenschappelijke identificator tussen sites wordt gebruikt.
(De query kan worden aangepast om ook de andere eigenschappen te synchroniseren — tags, categorieën, auteur en uitgelichte afbeelding — zoals uitgelegd in de vorige tutorialles.)
De query bevat transactionele logica, zodat wanneer de update mislukt op een downstream site, of dat nu komt doordat het HTTP-verzoek mislukte (bijvoorbeeld als de server niet beschikbaar is) of doordat de GraphQL query fouten opleverde (bijvoorbeeld als er geen post is met de opgegeven slug), de mutatie dan wordt teruggedraaid op alle downstream sites.
Om de staat terug te draaien, moet de variabele $previousPostContent worden opgegeven. We kunnen deze waarde doorgeven door in te haken op de WordPress-actie post_updated, waarna de GraphQL query wordt uitgevoerd (zoals uitgelegd in een vorige tutorialles).
De query doet het volgende:
- Het ontvangt de slug van de bijgewerkte post en de nieuwe en vorige inhoud ervan
- Het haalt de meta-eigenschap
"downstream_domains"op uit de post, die een array bevat met de domeinen van de downstream sites waarnaar de post gedistribueerd moet worden - Als de meta-eigenschap niet bestaat (d.w.z. de waarde
nullheeft), haalt het de optie"downstream_domains"op uit de tabelwp_options, die de lijst met alle downstream domeinen bevat - Het logt de gebruiker in op elk van de downstream sites (met hetzelfde
$usernameen$userPassword, voor de eenvoud) en voert de mutatie uit om de post-inhoud bij te werken - Als een downstream site een fout oplevert, wordt de mutatie teruggedraaid op alle downstream sites
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
initVariablesWithFalse: _echo(value: false)
@export(as: "requestProducedErrors")
@export(as: "anyErrorProduced")
@export(as: "hasDownstreamDomains")
@remove
}
query GetCustomDownstreamDomains($postSlug: String!)
@depends(on: "InitializeDynamicVariables")
{
post(by: { slug: $postSlug }, status: any)
@fail(
message: "There is no post in the upstream site with the provided slug"
data: {
slug: $postSlug
}
)
{
customDownstreamDomains: metaValues(key: "downstream_domains")
@export(as: "downstreamDomains")
hasDefinedCustomDownstreamDomains: _notNull(value: $__customDownstreamDomains)
@export(as: "hasDefinedCustomDownstreamDomains")
@remove
hasCustomDownstreamDomains: _notEmpty(value: $__customDownstreamDomains)
@export(as: "hasDownstreamDomains")
}
isMissingPostInUpstream: _isNull(value: $__post)
@export(as: "isMissingPostInUpstream")
}
query GetAllDownstreamDomains
@depends(on: "GetCustomDownstreamDomains")
@skip(if: $isMissingPostInUpstream)
@skip(if: $hasDefinedCustomDownstreamDomains)
{
allDownstreamDomains: optionValues(name: "downstream_domains")
@export(as: "downstreamDomains")
hasAllDownstreamDomains: _notEmpty(value: $__allDownstreamDomains)
@export(as: "hasDownstreamDomains")
}
############################################################
# (By default) Append "/graphql" to the domain, to point
# to that site's GraphQL single endpoint
############################################################
query ExportDownstreamGraphQLEndpointsAndQuery(
$endpointPath: String! = "/graphql"
)
@depends(on: "GetAllDownstreamDomains")
@skip(if: $isMissingPostInUpstream)
@include(if: $hasDownstreamDomains)
{
downstreamGraphQLEndpoints: _echo(value: $downstreamDomains)
@underEachArrayItem(
passValueOnwardsAs: "domain"
)
@strAppend(string: $endpointPath)
@export(as: "downstreamGraphQLEndpoints")
query: _echo(value: """
mutation LoginUserAndUpdatePost(
$username: String!
$userPassword: String!
$postSlug: String!
$postContent: String!
) {
loginUser(by: {
credentials: {
usernameOrEmail: $username,
password: $userPassword
}
}) {
userID
}
post(by: {slug: $postSlug})
@fail(
message: "There is no post in the downstream site with the provided slug"
data: {
slug: $postSlug
}
)
{
update(input: {
contentAs: { html: $postContent },
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
slug
rawContent
}
}
}
}
"""
)
@export(as: "query")
@remove
}
query ExportSendGraphQLHTTPRequestInputs(
$username: String!
$userPassword: String!
$postSlug: String!
$newPostContent: String!
)
@depends(on: "ExportDownstreamGraphQLEndpointsAndQuery")
@skip(if: $isMissingPostInUpstream)
@include(if: $hasDownstreamDomains)
{
sendGraphQLHTTPRequestInputs: _echo(value: $downstreamGraphQLEndpoints)
@underEachArrayItem(
passValueOnwardsAs: "endpoint"
)
@applyField(
name: "_echo",
arguments: {
value: {
endpoint: $endpoint,
query: $query,
variables: [
{
name: "username",
value: $username
},
{
name: "userPassword",
value: $userPassword
},
{
name: "postSlug",
value: $postSlug
},
{
name: "postContent",
value: $newPostContent
}
]
}
},
setResultInResponse: true
)
@export(as: "sendGraphQLHTTPRequestInputs")
@remove
}
query SendGraphQLHTTPRequests
@depends(on: "ExportSendGraphQLHTTPRequestInputs")
@skip(if: $isMissingPostInUpstream)
@include(if: $hasDownstreamDomains)
{
downstreamGraphQLResponses: _sendGraphQLHTTPRequests(
inputs: $sendGraphQLHTTPRequestInputs
)
@export(as: "downstreamGraphQLResponses")
requestProducedErrors: _isNull(value: $__downstreamGraphQLResponses)
@export(as: "requestProducedErrors")
@export(as: "anyErrorProduced")
@remove
}
query ExportGraphQLResponsesHaveErrors
@depends(on: "SendGraphQLHTTPRequests")
@skip(if: $isMissingPostInUpstream)
@skip(if: $requestProducedErrors)
@include(if: $hasDownstreamDomains)
{
graphQLResponsesHaveErrors: _echo(value: $downstreamGraphQLResponses)
# Check if any GraphQL response has the "errors" entry
@underEachArrayItem(
passValueOnwardsAs: "response"
affectDirectivesUnderPos: [1, 2]
)
@applyField(
name: "_propertyIsSetInJSONObject"
arguments: {
object: $response
by: {
key: "errors"
}
}
setResultInResponse: true
)
@export(as: "graphQLResponsesHaveErrors")
@remove
}
query ValidateGraphQLResponsesHaveErrors
@depends(on: "ExportGraphQLResponsesHaveErrors")
@skip(if: $isMissingPostInUpstream)
@skip(if: $requestProducedErrors)
@include(if: $hasDownstreamDomains)
{
anyGraphQLResponseHasErrors: _or(values: $graphQLResponsesHaveErrors)
@export(as: "anyErrorProduced")
@remove
}
query ExportRevertGraphQLHTTPRequestInputs(
$username: String!
$userPassword: String!
$postSlug: String!
$previousPostContent: String!
)
@depends(on: "ValidateGraphQLResponsesHaveErrors")
@include(if: $hasDownstreamDomains)
@include(if: $anyErrorProduced)
{
revertGraphQLHTTPRequestInputs: _echo(value: $downstreamGraphQLEndpoints)
@underEachArrayItem(
passValueOnwardsAs: "endpoint"
)
@applyField(
name: "_echo",
arguments: {
value: {
endpoint: $endpoint,
query: $query,
variables: [
{
name: "username",
value: $username
},
{
name: "userPassword",
value: $userPassword
},
{
name: "postSlug",
value: $postSlug
},
{
name: "postContent",
value: $previousPostContent
}
]
}
},
setResultInResponse: true
)
@export(as: "revertGraphQLHTTPRequestInputs")
@remove
}
query RevertGraphQLHTTPRequests
@depends(on: "ExportRevertGraphQLHTTPRequestInputs")
@skip(if: $isMissingPostInUpstream)
@include(if: $hasDownstreamDomains)
@include(if: $anyErrorProduced)
{
revertGraphQLResponses: _sendGraphQLHTTPRequests(
inputs: $sendGraphQLHTTPRequestInputs
)
}
query ExecuteAll
@depends(on: "RevertGraphQLHTTPRequests")
{
id @remove
}In de bovenstaande GraphQL query wordt een post niet gedistribueerd naar een downstream site wanneer de meta-eigenschap "downstream_domains" ervan is gedefinieerd met een lege array als waarde.
Dit is mogelijk vanwege het verschil tussen de functievelden _notNull en _notEmpty (geleverd door de extensie PHP Functions via Schema):
- Als de meta-eigenschap
"downstream_domains"niet is gedefinieerd, is de waardenull, en evalueren zowel_notNullals_notEmptynaarfalse - Als de meta-eigenschap
"downstream_domains"is gedefinieerd als een lege array, is de waarde[], en evalueert alleen_notEmptynaarfalse