houdini icon indicating copy to clipboard operation
houdini copied to clipboard

Support for multiple endpoints

Open fehnomenal opened this issue 1 year ago • 5 comments

Describe the feature

Due to reasons I need a custom build.js script that calls vite's build(), patches some files, moves the output to its target destination and creates a custom entry for the handle middleware.

It would be nice if I could integrate calling houdini generate into this file.

And in addition I'd love to have a script that pulls the schemas down (yes, there are mutliple...) with headers and all stuff. Basically I want to import { writeSchema } from 'houdini/build/cmd/utils/writeSchema';.

Currently all of this fails because of the exports field in the package.json.

Criticality

nice to have

fehnomenal avatar Aug 10 '22 06:08 fehnomenal

Hey @fehnomenal 👋 have you checked out #449 recently? There's a new summary that outlines all of the changes.

the vite plugin now integrates directly into your vite config file and will generate on build. It will also pull down your schema but i didn't realize you had multiple - how do you pull down your schema now? It sounds like we should extend apiUrl to be an array of strings and then the new plugin should do what you want, right?

AlecAivazis avatar Aug 10 '22 06:08 AlecAivazis

Yes, I have indeed and boy am I hyped to finally rework four apps to the new kit and houdini :partying_face:

OK, this will solve the generating problem (in the mean time I have svelte-kit sync && houdini generate && node build.js as the build script and pull and commit the schemas manually).

We use directus as a CMS which allows you to manage the structure and contents of a database easily. But our customers need a more domain specific interface and cannot work with the general (and at times cumbersome) interface directus provides. So thats the reason for the sveltekit app. To avoid naming conflicts, directus has two graphql endoints. The one at /graphql contains all the stuff from the database and the one at /graphql/system is responsible for authentication (and more which we do not use). I switch between them via metadata.isSystem which works really nice but unfortunately is unusable with inline queries.

Additionally, directus allows super fine grained permissions for each database table and adapts the graphql schema based on the collections (what they call the database tables) the user has access to. Because of that I currently set a static token in my local development deployment for an admin user and pull with rushx houdini generate -p -ph Authorization='Bearer 1nO6T7TZ3pvEO3JyG_CKSg3Wl2TDUrZx'. I have to do this two times and in between adjust the config which looks like this (so I only need to comment/uncomment):

/** @type {import('houdini').ConfigFile} */
const config = {
  sourceGlob: './src/**/*.{svelte,gql,graphql}',
  schemaPath: './schema*.graphql',
  // schemaPath: './schema.graphql',
  // apiUrl: 'http://localhost:8055/graphql',
  // schemaPath: './schema-system.graphql',
  // apiUrl: 'http://localhost:8055/graphql/system',
...

Of course generation fails because the queries and mutations in the code access both schemas but during generation houdini knows only the one it has just pulled.

I'm thinking if I want to pull the schemas on each CI build from the staging deployment. Which is probably OK as the schema only changes when the database structure changes and then the staging environment must be used for testing the changes and there is also a migration involved.

I probably could change the apiUrl based on an CI environment variable but there is still the problem of pulling multiple schemas.

AFAICT apiUrl is only used during generation with the pull option. What do you think of replacing apiUrl with an object mapping schema file names to api urls (like the rollup entry config)?

fehnomenal avatar Aug 10 '22 09:08 fehnomenal

While supporting multiple endpoints is probably a good thing to add, would it be an option to merge your endpoints before SvelteKit consumption?

If I understood, you are doing:

  graph TD;
subgraph SvelteKit
      SK[frontend]
end
      SK-->GA[ /graphql]
      SK-->GB[ /graphql/system]

Would it be possible to do something like:

  graph TD;
subgraph SvelteKit
      SK[frontend]-->M[GraphQL Mesh]
end
      M-->GA[ /graphql]
      M-->GB[ /graphql/system]

I'm curious 😁 Side note, I wanted to play with mermaid graph

jycouet avatar Aug 10 '22 21:08 jycouet

I just learned about Mesh and it sounds really cool.

From skimming the docs it should probably work but I'm a bit hesitant to introduce the additional complexity (out of respect for other developers and my own sanity :sweat_smile:):

  1. It works right now :joy:
  2. I think the mesh cannot live inside sveltekit but needs to be external. To build the frontend it needs the schema but it is only accessible after launching the frontend... Maybe I'm wrong here, but actually this would probably not that much of a problem as the Mesh could live in a separate Directus extension.
  3. But these extensions are strangely built and cannot easily access node_modules so it is best to completely bundle all dependencies. Is this even possible with the ymal config approach of Mesh?

fehnomenal avatar Aug 11 '22 07:08 fehnomenal

Ohh this has been fun to think about. Sorry I took a bit to reply, I wanted to really work through the implications of what you're describing. Really clever use of metadata 👍

So my first reaction was to suggest you go with a schema-stitching approach to combine your APIs into one which removes the need for that metadata trick. you can avoid the external service by using a library like @graphql-tools/stitch and resolving the stitched schema inside of an endpoint in SvelteKit. That might work if you dont mind having a different set of names in your application from what you see in your api documentation. It could also potentially enable some neat things for your UI to perform queries that cross this boundary.

That being said, I think this is probably the first real example I've seen for what houdini plugin might want to do. I've always told myself it seemed like a reasonable idea but i never really had something concrete. There are other things that are higher priority atm but i think there is a real possibility to provide a way to let you build a plugin that supports your situation without having to pull tricks like stitching them together.

Just to get some notes down here. This situation checks a bunch of boxes for things that I want plugins to be able to do:

  • define a custom directive that you could use to tag certain fields with which API
  • customize how you look up a particular type for a field
  • a way to take that directive and persist it in the artifact
  • and pass that persisted value as metadata to the request
  • custom store implementation (defined by import path)

AlecAivazis avatar Aug 11 '22 19:08 AlecAivazis

Even though I would still recommend moving this towards merging at the API level inside of SvelteKit, the new plugin system does have all of the hooks necessary to make this work:

  • special directive can be defined in schema hook of codegen plugin
  • can detect the directive on the query and persist it in the artifact with artifactData
  • the artifact is available to the client plugin pipeline
  • a fetch plugin can look at the artifact data and send the request to the right URL

Which is pretty cool and validating to see 🎉 Anyway, that means I feel comfortable closing this ticket as part of #871

AlecAivazis avatar Feb 02 '23 22:02 AlecAivazis

Would you be willing to provide an example of this working? I am also looking to implement multiple GraphQL APIs in the same SvelteKit app.

darrylyeo avatar Mar 04 '23 15:03 darrylyeo

Bump on this :)

darrylyeo avatar Apr 14 '23 07:04 darrylyeo

+1 for an example. struggling with the same problem when integrating directus currently.

i guess one would need to write a complete plugin for this. but it gets also very complicated as houdini would need to hit different endpoints. then how to define this? maybe a +page.gql and +page.system.gql for the other?

eikaramba avatar Nov 15 '23 15:11 eikaramba