#Erik Sipsma3294 So it s working out
1 messages · Page 1 of 1 (latest)
Yeah that's a good question, I haven't tried any of them with extend yet. I hope they do work with it, otherwise we will have to resort to mangling again or to customizing them further (which we are gonna do anyways but was hoping to do that more incrementally over time)
for the next phase we'll need sub-resolvers
and for extend to work
(e.g. extend Query { alpine: Alpine! })
Yes for sure, I'm thinking about some of the architecture and terminology stuff right now, but can see what happens w/ the various generators when you give them extend early next week if you haven't gotten there yet.
BTW, made issues for all the most pressing issues that have come up in discussion so far (subresolver support here: https://github.com/dagger/cloak/issues/32)
But feel free to add ones too as needed
(I also gotta do another pass to add more labels+priority, just got the creation of all of them out of the way now)
Oh, btw, arguably that's the difference between SDL and introspection
with introspection you don't get the extend etc, only the end result
panic: conflict on type "Core": field "image" re-defined <-- went with simple "fail on conflict" merging strategy for "stitching", for now
Pretty happy with the API so far ...
pretty close to have converted Core over this
That's interesting, so with SDL we see extend and know that we should merge schemas, but with introspection json the equivalent would be merging giant json blobs? I guess?
Awesome, I would be interested to see what it looks like so far if you want to push to a branch
I'm just curious what the extend looks like
And can then see how it'd fit (or not fit) with the code generation for user actions
Yeah, with SDL basically it's all the SDLs concatenated ("loss-less"). Introspection it's "reverse engineered" from a running schema, so the extends have been taken into account already
introspection uses a some queries like __type to list the types -- there's no way to actually see the "extend" from there, it's listing objects and their fields
(as they're loaded in the executable schema)
SDLs ... well in the CURRENT implementation they're concatenated, I don't think there's anything preventing from merging the extend ahead of time and building up a new SDL
I think that's why apollo is using _service { sdl } instead of using the introspection query -- it'd lose the extend field, probably other things
Right I guess what I was wondering is if we only had a bunch of instrospection JSONs and merged them (like if they have the same keys, merge all the values underneath), would that create the same result as if you had taken a bunch of SDLs that use extend, parse the schema and then introspect it?
Not sure if that makes sense, if not, no worries, it's mostly for my own curiosity
I think we'd lose sanity checking
e.g. we'd have to "assume" we want to extend a type
(they'll just show up as duplicates through introspection)
whereas with the SDLs, we know the difference between type Filesystem and extend type Filesystem
Ah okay, yeah that makes sense
Yeah I don't think we should switch to introspection format, I was just curious
Yep
well I was the one pitching introspection yesterday
this changed my mind
I think we should use "introspection", but return the SDLs rather than introspection query
(and even that, that's a maybe)
right right, yeah that's most practical for now anyways and seems like it might be the better approach
what is the other option? we need to get schemas to stitch in somehow right?
Ah I see
instead of execop'ing an "introspection"
(and the SDK could respond to the introspection request, so it's not like the user needs to do anything)
the advantage I guess is freedom of schema. You could split it up in a bunch of files, it doesn't need a magical path, etc
downside is it's not hermetic. Right now we know that for a given "stable FS" (like, from a git commit or whatever), we generate the stubs and they're not going to change so long as it's the same FS
with introspection we don't know what's happening
anyway, it's low priority, either way, IMO
Actually this gets back to what we were talking about before a little bit. Maybe import should not just take a Filesystem, but instead take both a Filesystem and a separate arg for the SDL.
We could still implement the current approach where the schema is read from the Filesystem (the client can just read it using the other core apis), but we'll also have the flexibility to do more in the future
var _ router.ExecutableSchema = &FilesystemSchema{}
type FilesystemSchema struct {
}
func (s *FilesystemSchema) Schema() string {
return `
scalar FSID
type Filesystem {
id: FSID!
}
extend type Core {
filesystem(id: FSID!): Filesystem!
}
`
}
func (r *FilesystemSchema) Resolvers() router.Resolvers {
return router.Resolvers{
"FSID": fsIDResolver,
"Core": router.ObjectResolver{
"filesystem": r.Filesystem,
},
}
}
func (r *FilesystemSchema) Filesystem(p graphql.ResolveParams) (interface{}, error) {
return &model.Filesystem{
ID: p.Args["id"].(model.FSID),
}, nil
}
schema, err := router.Stitch([]router.ExecutableSchema{
&router.RootSchema{},
&core.CoreSchema{},
&core.FilesystemSchema{},
})
it's almost as pleasant as gqlgen
(sorry, that's a different topic, got excited for a minute)
Yeah it looks great! Infinitely better than the current blob of code
We don't have to switch right now to the different model of import where SDL and the implementation Filesystem are separate args, but that does feel right somehow, and if it simplifies the updates you're making then maybe we should do it
No i have pushed everything, not changing that locally
perfect
hey, I'm just going to assume that arguments are there with the correct type, since graphql is already doing type checking
removes a ton of boilerplate
any concerns?
you mean skip the !ok branches? Yeah I mostly have those because copilot writes them for me. But it is entirely possible for them to be unexpected types
graphql doesn't do all the checking
before:
"image": &tools.FieldResolve{
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
rawRef, ok := p.Args["ref"]
if !ok {
return nil, fmt.Errorf("missing ref")
}
ref, ok := rawRef.(string)
if !ok {
return nil, fmt.Errorf("ref is not a string")
}
llbdef, err := llb.Image(ref).Marshal(p.Context, llb.Platform(getPlatform(p)))
if err != nil {
return nil, err
}
gw, err := getGatewayClient(p)
if err != nil {
return nil, err
}
_, err = gw.Solve(context.Background(), bkgw.SolveRequest{
Evaluate: true,
Definition: llbdef.ToPB(),
})
if err != nil {
return nil, err
}
return newFilesystem(llbdef), nil
},
}
now:
func (r *coreSchema) Image(p graphql.ResolveParams) (interface{}, error) {
ref := p.Args["ref"].(string)
st := llb.Image(ref)
return r.Solve(p.Context, st)
}
yep, those ones
i realized that if it happens we should panic, something went terribly wrong
Yeah I think the problem is that you don't see the entire panic, including stack trace because the panic gets caught by graphql-go, so you only see an error saying the cast was wrong but not the line number
I could be misremembering but I think that's what happened
and why I started letting copilot fill all that in
either way, not a big deal
yeah, but for it to happen, it means the schema got "bypassed" somehow
can only happen with a graphql-go bug
except for non-mandatory fields, for those we do need the check
No it can happen for custom types. I.e. the action resolver returns what it unmarshals into the interface{} object here: https://github.com/dagger/cloak/blob/e60aede62917e4e2711cca499d019c857f0b14ed/api/graphql.go#L190-L193
None of those types will be cast to, i.e. *Filesystem, even though in other methods they may actually already be converted to that type before being passed to the resolver. That's why I temporarily added these if statements: https://github.com/dagger/cloak/blob/e60aede62917e4e2711cca499d019c857f0b14ed/api/chaining.go#L218-L232