<@U01MV4U2EV9>, had an idea that I tried this morn...
# sst
d
@thdxr, had an idea that I tried this morning: Not using any framework (besides graphql.js, “graphql” in npm) or running a server at all for a graphql lambda. Was surprisingly easy, and even Apollo specific things like
apollo-server-errors
work out of the box (because
apollo
uses graphql.js). ESM now works, and my package size dropped by ~1.8MB, which made cold starts about half as long. Happy to share more if it is interesting.
t
that's almost what we're doing in the new graphql stack
we're using helix instead of apollo, probably not as bare bones as just graphql.js but we got esm working + the bundle is a lot smaller
d
I am assuming express is involved (helix typically works this way), so the added bulk might actually be kinda significant. express v4.17.3 ❘ Bundlephobia
In case bundlephobia just went down, its about 450/225KB.
For our API which has ~100 resolvers, this would amount to around a 20% increase
graphql.js is 165/39KB
t
Express isn't involved! Helix isn't a GraphQL server itself it's just utility functions, we wrote the connect to AWS lambda events
d
alright, that sounds close enough, certainly. You can rest assured telling people it is a solid replacement, we have a fairly complicated use case and leaned heavily on Apollo, and it was still really, really easy. I think the only thing that would hang people is caching or middleware.
I might also phrase it as using
graphql.js
, rather than Helix as the primary framework (whenever you make the docs). When you told me this, I looked up Helix, compared to Apollo, and wanted maturity. If I had looked up
graphql.js
, and noticed
apollo
used it, I would have been MUCH more inclined to do this earlier. I also saw Express on the Helix example when I looked it up and that was also a bad taste.
t
that's a good point we should keep that in mind
Helix is used by a few full fledged gql servers (graphql-yoga for example) and in general I want to bet on the people behind it
They also make all the GraphQL codegen stuff, graphql-scalars which is also great
They have an upcoming typed frontend tool coming out soon
d
I am using
graphql-compose
for these types of purposes, but my experience has been mixed. It definitely works. I don’t have experience with Helix to compare.
in any case, based on everything you have said combined with my experiences, I think you are definitely on or near the right track with regards to GraphQL + lambda.
I’m about to convert two more even larger APIs, ill post if anything goes awry, but I don’t expect it to.
t
yeah that'll be helpful, I'm happy with where the base is but I'm not sure what happens when you have a bunch of resolvers + real code in the mix
d
No issues at all, aside from one interface change from
graphql
15 to 16 (resolveType for unions)
t
do you have some sample code converting a lambda event into something that invokes a GraphQLSchema in graphqljs?
d
@thdxr
Copy code
const handler: APIGatewayProxyHandlerV2WithJWTAuthorizer = async (
    event,
    context
) => {
    const graphqlContext: LambdaContextFunctionParams<
        DataLoaders,
        undefined
    > = {
        event,
        context,
        express: undefined,
        loaders: dataLoaders,
    };

    if (!event.body) {
        throw new Error("No body");
    }

    const parsedBody = JSON.parse(event.body);

    graphQlLogger.log("Request started! Query:\n" + parsedBody.query, {
        label: "handler",
    });

    const response = await graphql({
        schema,
        source: parsedBody.query,
        contextValue: graphqlContext,
        variableValues: parsedBody.variables,
    });

    return {
        statusCode: 200,
        body: JSON.stringify(response),
        headers: {
            "Content-Type": "application/json",
        },
    };
};
You may see a few useless things, these are to match Apollo because: • We use libraries that work with Apollo. • Just in case this somehow fails and we need to revert (unlikely, but no downside other than these useless things).
schema
and
dataLoaders
are instantiated outside the handler (so that it only fires on cold start).
t
nice thanks will look at this soon
d
Realized that the dataLoaders should be INSIDE the handler, just an FYI.