Python 3.x Python石墨烯与阿波罗联盟的集成问题

Python 3.x Python石墨烯与阿波罗联盟的集成问题,python-3.x,graphql,microservices,apollo,apollo-server,Python 3.x,Graphql,Microservices,Apollo,Apollo Server,使用python跨多个微服务实现GraphQL,有些使用Ariadne,有些使用graphene(和graphene Django)。由于微服务体系结构,阿波罗联合会将合并来自不同微服务的模式 对于Ariadne,它非常简单(首先是模式),下面是一个小示例: 从ariadne导入QueryType、gql、make_executable_schema、MutationType、ObjectType 从ariadne.asgi导入图形ql query=QueryType() 突变=突变类型() s

使用python跨多个微服务实现GraphQL,有些使用Ariadne,有些使用graphene(和graphene Django)。由于微服务体系结构,阿波罗联合会将合并来自不同微服务的模式

对于Ariadne,它非常简单(首先是模式),下面是一个小示例:

从ariadne导入QueryType、gql、make_executable_schema、MutationType、ObjectType
从ariadne.asgi导入图形ql
query=QueryType()
突变=突变类型()
sdl=”“”
类型服务{
sdl:字符串
}
类型查询{
_服务:_服务!
你好:字符串
}
"""
@query.field(“hello”)
异步定义解析\u你好(\u,信息):
回复“你好”
@查询字段(“\u服务”)
def解析服务(信息):
返回{
“sdl”:sdl
}
schema=make_executable_schema(gql(sdl),查询)
app=GraphQL(模式,调试=True)
现在,这是阿波罗联盟没有问题的:

const { ApolloServer } = require("apollo-server");
const { ApolloGateway } = require("@apollo/gateway");


const gateway = new ApolloGateway({
    serviceList: [
      // { name: 'msone', url: 'http://192.168.2.222:9091' },
      { name: 'mstwo', url: 'http://192.168.2.222:9092/graphql/' },
    ]
  });

  (async () => {
    const { schema, executor } = await gateway.load();
    const server = new ApolloServer({ schema, executor });
    // server.listen();
    server.listen(
      3000, "0.0.0.0"
      ).then(({ url }) => {
      console.log(`The solution is actually a slight hack the schema that is automatically generated via 
graphene
. I thought I had tried this already and it still worked, but I just did it again now but it broke.

So if in Ariadne, I add

schema {
    query: Query
}
const{ApolloServer}=require(“阿波罗服务器”);
const{apollo gateway}=require(“@apollo/gateway”);
const gateway=新网关({
服务列表:[
//{name:'msone',url:'http://192.168.2.222:9091' },
{name:'mstwo',url:'http://192.168.2.222:9092/graphql/' },
]
});
(异步()=>{
const{schema,executor}=wait gateway.load();
const server=new服务器({schema,executor});
//server.listen();
服务器,听(
3000, "0.0.0.0"
)。然后({url})=>{

log(`这个解决方案实际上是对通过graphene
自动生成的模式进行了一点小小的修改。我以为我已经尝试过了,它仍然有效,但我现在又做了一次,但是它坏了

所以如果在阿里阿德涅,我补充说

def resolve_service(self, info, **kwargs):
    from config.settings.shared import get_loaded_sdl
    res = get_loaded_sdl()
    res = res.replace("schema {\n  query: Query\n}\n\n", "")
    return _Service(sdl=res)
Apollo Federation在
sdl
中还提出了
类型查询必须定义一个或多个字段。
。没有它,它可以正常工作。因此,我也转到了graphene,并在
解析服务中执行了以下操作:

schema {
    query: Query
}
现在石墨烯也可以工作了,所以我想问题是我忽略了,阿波罗联盟似乎无法处理以下的模式语法:

GraphQLSchemaValidationError: Field "_Service.sdl" can only be defined once.
更新1 我在阿波罗的网站上没有注意到一句话:

此SDL不包括上述联合规范的新增内容。给定如下输入:

在联合中将服务组合在一起时,这一点很明显,因为这将引发错误:

schema = ""
class ServiceField(graphene.ObjectType):
    sdl = String()

    def resolve_sdl(parent, _):
        string_schema = str(schema)
        string_schema = string_schema.replace("\n", " ")
        string_schema = string_schema.replace("type Query", "extend type Query")
        string_schema = string_schema.replace("schema {   query: Query   mutation: MutationQuery }", "")
        return string_schema


class Service:
    _service = graphene.Field(ServiceField, name="_service", resolver=lambda x, _: {})

class Query(
    # ...
    Service,
    graphene.ObjectType,
):
    pass

schema = graphene.Schema(query=Query, types=CUSTOM_ATTRIBUTES_TYPES)
因此,尽管在带有define
\u Service.sdl
的微服务的完整模式中,我们希望完整模式的字符串中没有该信息,该字符串作为
\u Service.sdl
的返回字符串返回

更新2 阿波罗联盟现在工作正常,确保
sdl
字段返回的字符串不包含联盟规范

在graphene中,我认为每个实现可能有所不同,但通常您希望替换以下内容:

res=get\u loaded\u sdl()
res=res.replace(“模式{\n查询:查询\n}\n\n”,“”)
res=res.replace(“类型_服务{\n sdl:String\n}”,”)
res=res.replace(“\n\u服务:\u服务!”,”)

在Ariadne中,只需要定义两个sdl,一个包含联合规范(用于服务返回的模式),另一个不包含联合规范(由
sdl
字段返回的)

你在另一个答案上走的很好,但是看起来你需要从印刷版上去掉一些东西

这是我在工作中使用的方法

我在这里总结我的代码:

import graphene
from graphene_federation import build_schema


class Query(graphene.ObjectType):
    ...
    pass

schema = build_schema(Query)  # add _service{sdl} field in Query

这个pip库可以提供帮助

只需使用
build_schema
,它将为您添加_服务{sdl}:

interface x implements y, z {
   ...
}


如果有人想知道,这是因为graphene v2在接口中使用逗号而不是符号

import re

from myproject import Query, Mutation
from graphene_federation import service, build_schema


# monkey patch old get_sdl
old_get_sdl = service.get_sdl

def get_sdl(schema, custom_entities):
    string_schema = old_get_sdl(schema, custom_entities)
    string_schema = string_schema.replace('\n', ' ')

    pattern_types_interfaces = r'type [A-Za-z]* implements ([A-Za-z]+\s*,?\s*)+'
    pattern = re.compile(pattern_types_interfaces)

    string_schema = pattern.sub(lambda matchObj: matchObj.group().replace(',', ' &'), string_schema)
    return string_schema

service.get_sdl = get_sdl
schema = build_schema(Query, mutation=Mutation)
这种语法已经不起作用了,一种解决方法是使用monkey patch获取_sdl


联邦服务需要实现。在Apollo中,这是通过使用
buildFederatedSchema
函数来实现的。我不确定graphene。据我所知,在成功实现Ariadne之后,联邦服务需要在模式中有一个
\u service
字段,即ype
\u Service
,它有一个字段
sdl
,whcih以字符串形式返回整个架构。这很奇怪,因为这只是重复,基本上在架构中有一个字段,返回所述架构。您是正确的,graphene本机不支持这一点,但几乎每个后端都不支持utilize graphql,像Ariadne一样,我们只是定义了他们的文档所说的需要。替换(“类型查询”,“扩展类型查询”)
是否存在缺陷?在这个替换之后,当您扩展现在不存在的东西(
查询
)时,模式如何有效?当我开始工作的时候,我也会尝试一下。所以我刚刚尝试了你的解决方案,但仍然失败,因为联邦认为
sdl
属于
ServiceField
类型,应该是
\u Service
。我在
更新1
中的回答中还声明,从
sdl
返回的sdl不包含联邦元素,我现在将添加
update2
,以更清楚地记录这一点。您应该能够定义SerficeField的名称,对我来说没有问题。您实际上不需要替换扩展查询,它对我和我都有效。您需要的唯一联邦元素是端点及其类型,您不需要定义查询如果你看一下我在这篇评论中链接的完整实现,你会发现这一切都是可行的:)这很好,但对我来说仍然不起作用,我会接受我自己的答案,因为它确实解决了问题。