Fork me on GitHub
#graphql
<
2019-01-22
>
mpenet14:01:40

Just curious: any good approach to use graphql + CDN

mpenet14:01:34

with rest it's quite easy to set rules via cache-control headers and have a good level of granularity

mpenet14:01:44

can't find good examples of this with graphql

3Jane14:01:54

The whole problem with graphql queries being flexible is that you can’t easily cache it like with normal REST endpoints.

mpenet14:01:27

Well you can if you have full control. But unless you have a CDN vendor that is/would be graphql aware that seems tricky to achieve with the same level of efficiency

3Jane14:01:32

One thing you can do is what Facebook do, which is precompile queries to hashes, and only accept the hashes in prod.

orestis14:01:49

I think graphql has a very good fit for private data, or data that really changes according to the viewer. For things that are public/cacheable, you have to jump through hoops.

mpenet14:01:22

precompiling doesn't fix the problem

mpenet14:01:39

various parts of the query results could/should have various level of caching

hlship17:01:26

If you combine server-stored queries (coming in Lacinia) with query variables, you end up with a good cache key: the name of the query and the name and values of the query variables. Personally, I prefer to cache the raw data and just let the GraphQL execute.

hlship17:01:59

Because GraphQL execution isn't pure, so there could be lots of state (time based values, auth rules driving visibility, or simply data changing in the backend) that make the cache data stale in non-obvious ways. If your data is fast, Lacinia is pretty fast too ... I run benchmarks and the execution overhead is typically under 5ms. You spend all your time waiting for data from backend or data store.

mpenet18:01:29

I am not worried about this. But if you want to be able to delegate caching/availability/locality to a cdn (which is super convenient and easy to achieve with rest) you dont have the same level of granularity now. You cannot have the same query (with or without params) return a response with A and B with different caching rules.

mpenet18:01:08

You can add a proxy that will query a cdn behind the scene but that's backward. You create a potential bottleneck you have to manage yourself, which kind of defeats the purpose of using a cdn

mpenet18:01:15

To get the same level of granularity a CDN would have to support/understand graphql and some custom extension to express cache settings from the query (like cache-control with rest) but per field

mpenet18:01:49

I really wish that existed on keycdn/fastly/cloudfront etc

3Jane14:01:02

graphql is good for schema change management without having to version, and for avoiding overfetches

3Jane14:01:29

oh, I think I see what you mean

mpenet14:01:37

Sure, I am sold into this already. But I am trying to see if we can replace a public facing api with it also

mpenet14:01:51

which is currently rest+cdn

orestis14:01:55

If you’re talking about HTTP-level caching, I think you’ll find graphql really lacking, but you can in theory send some queries over GET, so that they can be cached my middle proxies.

3Jane14:01:10

if you want to vary caching of various parts of the query, you’ll have to do this server-side

mpenet14:01:35

yeah but even with middle proxies you don't get the "locality" from a CDN or the guaranteed availability

mpenet14:01:57

yeah, got it, but that doesn't fit my use-case

3Jane14:01:20

you could also have a composite graphql server

mpenet14:01:05

Apollo has extension to hint caching at field level

orestis14:01:50

But still it’s happening server-side, right? That is, the client will get everything from your server, every time. It’s just that the server might save some work fetching those fields from somewhere else.

mpenet14:01:58

yeah it's basically done via a proxy

mpenet14:01:20

which is not so good

orestis14:01:24

So that’s still not a CDN — just an implementation detail.

mpenet14:01:30

reading about it now

3Jane14:01:35

schema stitching

mpenet14:01:16

I mean there has to be a cdn vendor who supports this, via that graphql schema ext. or something else

orestis14:01:50

Ah right. I don’t think you’ll have much luck there, too many moving parts for a vendor to support easily.

mpenet14:01:17

there are a few it seems but no big names

mpenet14:01:32

yeah, I guess we ll stick with rest for now on this front

orestis14:01:36

GraphQL schema extensions are very implementation-oriented, there’s only a couple official ones.

orestis14:01:17

You can still send a graphql query over a GET parameter (a big opaque string), if you control the client and the query is static you will save some bytes, and you can use all the major CDN poviders.

mpenet14:01:05

the http method is not really an issue. I'd happily use precompilation

mpenet14:01:47

it's more about the fact that cache settings will be set per (whole) response vs per fragments (field, object(s))

orestis14:01:26

Yes, that’s a hard nut to crack with CDN providers.

mattly21:01:00

is it possible according to the GraphQL spec to have the same field-name/field-type definition in multiple interfaces that an object provides?

mattly21:01:06

I see this in the spec:

mattly21:01:09

> The field must have a unique name within that Interface type; no two fields may share the same name.

mattly21:01:30

but take that to mean an interface must not have duplicate names

mattly21:01:38

let's say I have an interface Person which represents common fields for a union of people object types, and specifies phoneNumber, and an interface hasPhoneInfo which is more something used for any object that provides phone fields and also specifies phoneNumber, my take is that I should be able to do that

mattly21:01:34

however when I try that with Lacinia, I get ExceptionInfo Object field is not compatible with extended interface type.

mattly21:01:18

{:object :PractitionerPerson, :interface-name :Person, :field-name :phoneNumber}

mattly21:01:04

I'm using an old version of lacinia, maybe I should really upgrade before continuing here

mattly21:01:04

aha, figured it out

mattly21:01:17

one interface defined the field as nullable, the other not-nullable