 Hi everyone, hopefully you can all hear me sounds good awesome as a partner said my name's Alex and I'm team leader here Bloomberg for the cross commodities team. We're responsible for discoverability of commodities and run both the front-end Python stack as well as a rabbit MQ Python pipeline in the background as well And I've recently come across GraphQL and I want to talk about my journey of learning about GraphQL and trying to inspire more of you to go out find out about it because I think it's a really cool Technology and this presentation is really given from the point of view of an enthusiastic beginner I've written a couple of example script Servers try to get to know it. I'm currently writing a proof of concept internally as well Before trying to persuade the rest of my team to use it So hopefully today I can inspire you to go and learn a little bit more about it The slides are all online. The example code is online as well And I'll tweet about it later Alex Chamberlain as well So as I said, I'm really looking to inspire you to write some GraphQL servers in Python and signpost you towards some fantastic open source Libraries that are available now for you to use So GraphQL is a an API technology that's come out of Facebook. I'm not going to read the definition to you There it's available on graphql.org But essentially GraphQL comes in two parts a schema definition language that defines the Contracts between your client and your server. I am going to talk about that quite a lot because I think it's quite important and a query language for actually Defining what you want as a client from the server So you can kind of think of the query language as your SQL data manipulation type stuff and your schema language in a similar way to your data definition language in SQL. They're kind of comparable So this is an example query You'll notice that You can name queries in the case in this case. It's named country there You have operations on which that you want to call. So we're calling the country API You have arguments that are always keyword arguments that are always specified by name And in this case, we're passing in the string us That's a two character iso code there And then what makes graphql different from most of the query languages out there is you then tell it Tell the server hey as a client for my use case I need these fields returned So in this case, I need iso code name and a list of cities that are belong to this country And I'm going to keep reusing this example throughout the presentation. So I'll refer to City API that it's just a sort of basic idea You can kind of imagine that it exposes accesses for city objects for country objects and the links between them Because it just it's it's a good use case for graphql This is another example Just to point out a couple of the other features that you can have In this case, you can see that arguments can support many different types In the first case, we used a string argument. In this case, we're using an integer You can have aliases for any field So in this case, the first query is alias to london the second query to new york And that's supported throughout the query So if I wanted to rename name as label or something to that effect Prefixing it with that alias would work and each key has to be unique Which sometimes makes aliasing necessary The arguments can also be complex types. They're called input types if you want to go look them up But I won't really be talking about them too much today So the graphql basics, as I said, graphql really starts with schema definition language This is where you define what types your schema use And graphql is really built around its type system Type system is quite powerful And I'll show you an example of the schema in a bit The schema defines your contract between your client and your server And I think this is a really important thing and it's very important for schema-driven or schema-first design Where you sit down and you define your schema That's not to say that you never change it again. Schemas obviously evolve as the use cases evolve But it's really a useful methodology to get yourself into about thinking about okay So I've got my server. What's my interface to my server? And I think that's a really massive benefit We've been using schema-first design here at Bloomberg for quite a while And I must say it really does speed up development You have your basic root types. These are the basic operations that a graphql server can support Read-only operations such as the queries read write operations in the mutation And there is some now getting some basic support around subscriptions as well So that's where basically it's a kind of pub-sub mechanism Typically but not absolutely necessary for graphql The query and mutations would be served over HTTP The vast majority of examples out there are going to be HTTP based and the subscription would be over web sockets But the actual graphql spec doesn't really talk about transport The transport is really a convention that's built up over time So if you have a different request response protocol that you use at your corporation Graphql still works if you have a different pub-sub or you want to publish your pub-sub over rabbit or over kafka That still works too One other really important thing that I'm going to talk about is resolvers So whilst the spec again doesn't actually specify how you go about implementing your server Your server could just be serving up static files for all the spec cares about and in mock servers That probably is what you're actually going to do But most Implementations out there use a resolver pattern where A function or a resolver is called for each field and I think it's quite important to understand those resolvers So this is a little bit python specific, but the javascript examples and most other examples have very similar patterns as well A graphql resolver is is just a function It typically takes two Positional arguments the source that's the object that this field is being resolved for so at the top that's probably going to be none Okay, you're just saying I want to call this city api at the root level But as you go down your tree as you go into the fields on the city type or on the country type That's going to become a sort of real object that you might want to reference The resolve info which has loads of information Most of which you'll never use in a typical use case But it provides a space where you can share information across your resolvers So that's your context if you like and in the example code we share a database connection via the context mechanism And the field name which is really useful as I'll show you in a second for the default resolver The arguments from the client get passed in as keyword arguments. These are already being validated. They're already of the correct type Um, so you can trust you can trust that that comes from the libraries for free um And and it'll be according to the schema as well And then your response to your client comes in in the form of the result So at a high level that might be a value semantic object an object you're returning to the client or it could um Could be a scalar type either one of the native ones supported like string flow in that type of thing Or a scalar type that you've defined So one of the schemas i've worked on recently we defined a a uu id or gu id uh scalar object because a lot of our ids took that form And then resolvers kind of recurse into themselves So the first resolver you get called might return a city object The whole object that represents the the city row in the database whereas um When you're populating the name field on that city object the source becomes that city object it recurses into that And then um, you've returned a scalar value from that presumably a string for the name And of course At the lowest level most of the resolvers actually look exactly the same, you know, you've gone to your database You've constructed your city object you've constructed your your country object And you just want to return the the value that's on that attribute. And so the default resolver provides that for you But the reason i've copied it here is it provides a nice illustration of some of the things you can do Uh with the resolve info so the resolve info you can access the field name So if you want the same resolver across multiple field names and they might maybe have a slightly different Implementation that information is available for you. It also shows that the default resolver in the python stack uses A attribute notation or dot notation. There's no good returning a dictionary The default resolver is not going to work for you. You need to use first-class objects or override the default Resolver that took me a couple of minutes to figure out the first time So let's move on to the pros and cons. So this isn't necessarily python specific at this point But of course when you're trying to sell a new idea to a bunch of engineers, what do they first do and they go You know that might work for 95 of our use cases, but it doesn't work for the other five percent So we can't use it. So they're going to list all the cons off for you first So these are a few of the cons I could think of and of course we're at a python conference And the first thing I notice about the graphql ecosystem. It's largely javascript You google graphql most of your example is going to be javascript Most of the tutorials are in javascript. Most of the clients are in javascript. Now, that's great if you're a web developer But if you're trying to apply it to other technologies that may feel a little bit alienating to start with But I'd like to start by reassuring you that the ecosystems in the other languages are Are equally thriving as well. It just started in in the javascript space And the other pet peeve of mine. I told you I'd mentioned the schema quite a lot is Many examples conflate the schema with the business logic So they might define the schema in code rather than using the schema definition language And that's makes it really hard if you're the other side of the coin So if you're the server developer fine, I don't have to define my schema twice I just do it in code and when I add a new attribute it just magically appears in the schema But imagine that you're the client. How do I go and find the schema? Wait, I have to connect to your server Download the schema decode the schema into the schema definition language and read it. That's really difficult So by providing the schema up front, you're doing two things You're agreeing in that contract with the client and you're providing them with the service that they deserve You're providing them with that documentation that they need as as your client Why should we use graphql? Well, it's slowly becoming an industry standard I went on to the graphql website to do a little bit of research for this and they actually list off a variety of companies using it So it started at facebook But github has a graphql API as well Pinterest, Intuit, Coursera and Shopify are also using it as well And hopefully one day I'll add Bloomberg to that list There are conferences around for graphql The graphql europe conference is actually a few weeks time. Unfortunately, I can't make it And Meteor provide consultancy services around their Apollo ecosystem And there's even a back end of a service as a service called graphql That was such a cool name. They've recently changed it to prisma As well providing as I said a back end as a service So you don't even have to run your own infrastructure if you don't want to There's a strongly typed schema one of the big Criticisms that REST APIs often get is like what objects am I going to get back? Oh, just query the API and see what you get. Well, that's kind of not good enough to be honest The strongly typed schema gives you those guarantees that you need No more over or under fetching Again, one of the big criticisms of microservices is What gives this service has to be reused across a lot of clients. You either give me too much data i.e over fetching That could be slow It could use up the bandwidth it could expose data that that client just doesn't need Which in GDPR terms is a really bad thing Or it could not give you enough data i.e under fetching So this is a typical problem where you get a list of IDs back And for each ID you have to go and make another API request i.e the n plus one problem Graphql solves this by saying hey, tell me what information you need up front If you need the cities that belong to a country tell me that and tell me the information you need on those cities And i'll give it back to you in one go Now the server might have to make loads more queries to the database to do that But at least it's all contained in one place and if it proves costly enough the back end engineers can optimize it I hope so Rapid product development So rapid product development again comes from this schema the schemas agreed up front The clients can go away and say look Let me bring up a mock server with fixed results just so I can get the client going while you bring up The real server behind it and the back end engineers can go away write the server Now of course those two engineers might be the same person in some cases But it really decouples your development from your your client and your your back end Uh, it's composable This is a relatively no idea But if you've got the same entity represented in two graphql schemas rather than the client having to go to both entities Say to go to one api to get The number of car parking spaces currently available in a city and the other api to find out the location of the city You might provide a composed or emerged layer in front of it and uh dynamically dispatch the request to those two schemas themselves And finally there's a rich ecosystem I'm going to have to look at my notes for this one So server libraries are available in C sharp closure elixir url and go groovy java php scaler and ruby Not to mention the fact they all started in java scripts And there is a rich node uh ecosystem out there and of course there's a great python ecosystem too So the python support is generally around Uh, 23 repositories on the graphql python organizational on github I haven't actually had a chance to send a pull request their way yet unfortunately Um, and the main implementation the query passing the schema definition passing is all done in graphql call And then there's loads of satellite libraries around it That um, implements various things such as integration with common frameworks Uh, so the example i'll be showing today is uh asynchronous one based on sanic graphql Um, but I know that there was a jango workshop yesterday And there's a graphene jango integration layer as well that um, maybe you could go away and put a graphql api on the front of that uh website you developed yesterday Another library that i'm going to show you is called aio data loader And this is an asynchronous library. It's not specific to graphql But it allows you to, um, separate the data fetching layer from everything else in your Your application The api exposes is a load api you say Cityloader dot load and then provide The name of the city or whatever you want to load and behind the scenes it'll batch up a bunch of these calls together and as a as an implementer you implement the batch load function So as I said, uh, the illustrative example I'm just going to go quickly over is that of a city api make up the requirements in your head There are city objects. There are country objects. There's links between them. They have some parameters Uh, all the data is creative commons from, uh, the geo names database So what does the schema look like? Well, it's fairly fairly simple You start by defining what your types types are My country has an iso code. It has a name They're both strings They're both required That is if the client says hey, give me the name of this country the api guarantees it will get one back You can't send a null back in that case, but you only send it back if the if the client asked for it The city has a similar number of attributes and then there's these relationship fields between them A city has a a single country A country has multiple cities and you can see that in the list Syntax and of course there's lots of documentation about writing schemas and The the intricacies of thereof You can see the root type at the bottom the query type and the Formal declaration of what our schema looks like and so the schema also takes a mutation argument a subscription argument Where you can provide those types as well But i've just implemented a read-only service in this case The loader the country loader is relatively simple As I said, you can see the batch load function that you'll never directly call that's called by the data loader library And you can see the resolver underneath. I chose to do it as a member function But isn't there's no it's not necessary if you don't want and you can see the basic Format of context resolve info and then the keyword arguments that the client provided Then this is where we tie up the schema. So you've got your schema file I'm going to pass it and load it I've got rid of the intricacies of that if you want to have a look at the code there it's all on github Pass it and then I've written this make executable schema Utility that just connects the two together. So we've got our formal schema File it's been carved in stone somewhere the clients are basing basing their implementation on that And then in code we just say hey if you need a resolver for query country use this resolver You want a resolver for the cities use this resolver and it just connects them together. It's very simple There are various other examples online where they're set out slightly differently such as Automatically giving you the resolvers based on the database Schema and things like that. There are various ways to set set this up. This is just one example And then the server as I said most of the integration between the graph ql layer And the server has actually been done for you. I'm just Telling it really hey, you can go and find your schema here And in this case, I've used the the sanic graph ql view To allow me to override the context So like I said before the database connection is shared across All of the resolvers you don't want to open a separate database connection for every field that you want to go and grab And so I as I said I override the context of that effect and provide the database and the loaders at that level So let's Have a look at what it looks like So this is a little utility called graph graph iql or graph eql Can I make it bigger? Yes That was lucky wasn't it Um cool So as you can see I've got multiple queries here and hopefully I remembered to start my server And just by hitting uh command enter it runs the query on my back end This is really fast Iteration time. I you know change the server Hit enter and I'm testing it again And I've got a full suite of pie test. Uh, they're all medium tests. They're all hit the database um But you could write unit tests for it quite easily as well In in the um in the repository for everybody to have a look at And with that that brings me on nicely to my uh to my conclusion So graph ql is a fantastic way to define a contract between different parts of your system It could be from your front end to your back end from the ui service to your back end services It could be between your rabbit mq worker and your label translation system um It's just it's just a layer A schema layer a a an api language that you can use between different Actors in your system And the ecosystems is great in a variety of languages So you've got clients the servers in python But you've got them in all the of the technologies you might be using At your corporation as well So with that I'm going to say thank you very much I'll be around after the talk because I think I've used the full 25 minutes Probably going to hang out for a bit at the uh bloomberg booth if anybody wants to come and Talk to me about a graph ql or about jobs at bloomberg. I'd be happy to talk about either. Thank you