Hi everyone,
I’ve been using @snek-at/function (the predecessor project to getcronit/pylon) for quite some time. Over the past three years, snek-function, snek-functions, and snek-query - all previously maintained by @schettn - became core parts of my backend infrastructure. Unfortunately, none of these packages will be actively maintained in the future, so I've been looking for a reliable alternative. That’s why I’m excited about moving to pylon and leveraging GQty, but I’ve hit a few bumps along the way.
1. Dealing with Parameters vs. Arguments
-
Situation
pylon’s GraphQL setup uses parameters, whereas GQty uses arguments. With snek-query, I can do this:
async (...params: QueryTypes["getIsUnique"]["params"]): Promise<QueryTypes["getIsUnique"]["return"]> => {
const context = getContext()
const header = context.req.header("Authorization")
const args = convertParamsToArgs.Query.getIsUnique(params);
const [isUnique, errors] = await sq.query(q => q.getIsUnique(args), {
headers: {
Authorization: header
}
})
if (errors) {
throw new GraphQLError(errors[0].message, {
extensions: errors[0].extensions,
});
}
return isUnique
}
Here, convertParamsToArgs and QueryTypes help transform function parameters into the arguments snek-query expects, and QueryParamNames (ordered array of arg keys) keeps everything in the right order. With a bit of reduce() magic the parameters are converted to arguments. Due to TypeScript reasons there is a pregenerated function for each Query and Mutation:
// schema.generated.ts
export const convertParamsToArgs = {
Mutation: {
userCreate(params: MutationTypes["userCreate"]["params"]): Parameters<Mutation["userCreate"]>[0] {
return convertParamsToArgsFn<Parameters<Mutation["userCreate"]>[0]>(MutationParamNames["userCreate"], params);
}
},
Query: {
getIsUnique(params: QueryTypes["getIsUnique"]["params"]): Parameters<Query["getIsUnique"]>[0] {
return convertParamsToArgsFn<Parameters<Query["getIsUnique"]>[0]>(QueryParamNames["getIsUnique"], params);
},
getAllUser(params: QueryTypes["getAllUser"]["params"]): Parameters<Query["getAllUser"]>[0] {
return convertParamsToArgsFn<Parameters<Query["getAllUser"]>[0]>(QueryParamNames["getAllUser"], params);
}
}
};
-
Problem
In GQty, variables are alphabetically sorted via lexicographicSortSchema(assertSchema(schema)), which creates type conflicts in TypeScript when optional parameters end up behind required ones. This makes it increasingly difficult to implement an equivalent to QueryParamNames and convertParamsToArgs.
2. fetch({ mode: 'cors' }) and Cloudflare Workers
- Issue
On Cloudflare Workers, fetch({ mode: 'cors' }) doesn’t exist and isn't needed. Therefore having a custom pylonClientCode that generates different client code within generator.ts would be cool.
3. Adding pylon as a Supported Framework
- Suggestion
It would be awesome if GQty officially recognized pylon the same way it does react and solid-js. That way, anyone building with pylon could have a straightforward entrypoint and a consistent experience.
4. Error Handling with resolve
- Unclear Docs
GQty’s docs don’t give me a clear example of how to handle GraphQL errors when calling resolve on the server. If there's a recommended pattern or some best practices, I'd love to see them ❤
My Workaround
I tweaked the GQty generator enough to get a proof-of-concept working with pylon. You can check out a live demo on a Cloudflare Worker
Working Example deployed on Cloudflare Worker:
import { app, getContext } from '@getcronit/pylon'
import { GraphQLError } from 'graphql';
// Gqty
import { resolve } from './clients/iam/index';
import { QueryTypes, MutationTypes, convertParamsToArgs } from './clients/iam/schema.generated';
// Recursively fetch entire object for logging
const getAll = (obj) => {
for (const key in obj) {
if (typeof obj[key] === 'object') {
getAll(obj[key])
} else {
console.log(obj[key])
}
}
}
export const graphql = {
Query: {
getIsUnique: async (...params: QueryTypes["getIsUnique"]["params"]): Promise<QueryTypes["getIsUnique"]["return"]> => {
const context = getContext()
const authorizationHeader = context.req.header("Authorization")
const args = convertParamsToArgs.Query.getIsUnique(params);
const isUnique = await resolve(
({ query }) => {
const objectGql = query.getIsUnique(args)
// Just a temproary workaround to get the whole object
// should be replaced with just the thing that are requested
// from pylons graphql api.
getAll(objectGql)
return objectGql
},
{
extensions: { authToken: authorizationHeader },
cachePolicy: 'no-store'
}
)
return isUnique
}
},
Mutation: {
userCreate: async (...params: MutationTypes["userCreate"]["params"]) => {
const context = getContext()
const authorizationHeader = context.req.header("Authorization")
const args = convertParamsToArgs.Mutation.userCreate(params);
const data = await resolve(
({ mutation }) => {
const response = mutation.userCreate(args)
// Just a temproary workaround to get the whole object
// should be replaced with just the thing that are requested
// from pylons graphql api.
getAll(response)
return response
},
{
extensions: { authToken: authorizationHeader },
cachePolicy: 'no-store'
}
)
return data
}
}
}
export default app
While this demonstrates that GQty can work in a pylon environment, it’s definitely not as polished as I’d like.
I will open a pull request with my changes so others can try this out. Since snek-function, snek-functions, and snek-query will no longer be actively maintained in the future, it would be really helpful for anyone who wants to migrate from those old setups into a modern solution with pylon and GQty.
Our friends have been doing server side integrations for gqty, give them a try!
- getcronit/pylon
- stepci/garph
While we are focusing on client-side DX, we are also open to ideas on server implementations.
With absolutely no commitment, it may happen in gqty if you have great ideas on server API and no one else bothers doing it.
Originally posted by @vicary in #2025 (comment)
@vicary and @schettn – if you have ideas on how to officially support pylon in gqty, especially regarding parameter ordering, dynamic data fetching and error handling please let me know.
Hi everyone,
I’ve been using
@snek-at/function(the predecessor project togetcronit/pylon) for quite some time. Over the past three years, snek-function, snek-functions, and snek-query - all previously maintained by @schettn - became core parts of my backend infrastructure. Unfortunately, none of these packages will be actively maintained in the future, so I've been looking for a reliable alternative. That’s why I’m excited about moving topylonand leveraging GQty, but I’ve hit a few bumps along the way.1. Dealing with Parameters vs. Arguments
Situation
pylon’s GraphQL setup uses parameters, whereas GQty uses arguments. With snek-query, I can do this:Here,
convertParamsToArgsandQueryTypeshelp transform function parameters into the argumentssnek-queryexpects, andQueryParamNames(ordered array of argkeys) keeps everything in the right order. With a bit ofreduce()magic the parameters are converted to arguments. Due to TypeScript reasons there is a pregenerated function for each Query and Mutation:Problem
In GQty, variables are alphabetically sorted via
lexicographicSortSchema(assertSchema(schema)), which creates type conflicts in TypeScript when optional parameters end up behind required ones. This makes it increasingly difficult to implement an equivalent toQueryParamNamesandconvertParamsToArgs.2.
fetch({ mode: 'cors' })and Cloudflare WorkersOn Cloudflare Workers,
fetch({ mode: 'cors' })doesn’t exist and isn't needed. Therefore having a custompylonClientCodethat generates different client code within generator.ts would be cool.3. Adding
pylonas a Supported FrameworkIt would be awesome if GQty officially recognized
pylonthe same way it doesreactandsolid-js. That way, anyone building withpyloncould have a straightforward entrypoint and a consistent experience.4. Error Handling with
resolveGQty’s docs don’t give me a clear example of how to handle GraphQL errors when calling
resolveon the server. If there's a recommended pattern or some best practices, I'd love to see them ❤My Workaround
I tweaked the GQty generator enough to get a proof-of-concept working with
pylon. You can check out a live demo on a Cloudflare WorkerWorking Example deployed on Cloudflare Worker:
While this demonstrates that GQty can work in a
pylonenvironment, it’s definitely not as polished as I’d like.I will open a pull request with my changes so others can try this out. Since snek-function, snek-functions, and snek-query will no longer be actively maintained in the future, it would be really helpful for anyone who wants to migrate from those old setups into a modern solution with
pylonand GQty.@vicary and @schettn – if you have ideas on how to officially support
pyloningqty, especially regarding parameter ordering, dynamic data fetching and error handling please let me know.