Boost your API Development with GraphQL & Prisma

Nikolas Burk

Recorded at GOTO 2018

all right so yeah my talk is about
graphical and charisma and I know that's
basically the last session for all of
you today I won't be mad if I see people
fall asleep but hopefully the the
content of the topics that is exciting
enough to keep you all awake so so my
name is Nicolas Burke and this here in
Berlin I work at a startup called Prisma
and we are building all sorts of tools
in the graph QL and database space you
can find me on github and on Twitter as
a particular smirk the the agenda for
the talk for the talk today is threefold
so I'm going to start with a graphical
introduction so that we're all on the
same page about the major concepts of
graph QL then I want to dive a bit
deeper and really want you to understand
how graphical servers actually work
under the hood and then I want you to
understand a bit better how he can build
graph QL servers with Prisma and to get
a bit of a feeling for the audience I
would like to know just by show of hands
who views a front-end developer okay few
front-end developers who is a back-end
developer all right I guess who's a
full-stack developer okay a few of those
people also raising their hands on the
backend side who have used using Java as
their primary language okay who's using
javascript and node and typescript maybe
also few people who is using a language
like go or Python or Scala maybe
something like that okay awesome
ok so I also will do a fair bit amount
of live coding actually and that will
all be in JavaScript but I think that
the code should be simple enough for
everybody to follow so let's start with
the graphical introduction and the big
question what's graphic here so so very
briefly stated it is a new API standard
that was developed by Facebook in 2015
and it basically is a specification for
it type system and for a query language
so it's just a long document actually
that you can read online where it's
precisely described how the type system
of graph Gale works and how the
corresponding query language actually
works and there are three core
primitives that we're going to learn
about and that are called query mutation
and subscription furies are the way in
graph kill how you can read data from an
API and mutations are the way how you
can cause some sort of side effect on
the backend and then we also have
subscriptions which are for real-time
operations but we won't really cover
them in this talk why would you want to
use graph here so first and foremost it
has a strongly typed schema for your API
and that's my personal favorite maybe
you've worked with REST API in the past
and if you use the tool like swagger or
what's called today I think open API and
there you get kind of similar benefits
but graph QL and has its own schema
definition language that will also see
later on which you use to declare the
schema and that strongly type schema has
a couple of advantages like
auto-generated auto-generated
documentation for your API that you will
always get out of the box if you're
using graft here so you're never left
questioning the API operations and kind
of the kind of variables you need to
provide for these API operations and
what the returned data structures
actually actually look like then one big
advantage and that's the advantage that
usually gets the front-end developers
hooked is that you can clearly exactly
the data that you need in a single
request so if we have the situation on
the front end where we need to implement
different three different rest endpoints
to get the data that we need in that
situation we have to make three Network
requests to get the data and then
locally on the front end we have to
actually like put the data into cache
and then eventually display it on the UI
with graph GL you can community exactly
the data that you need in a single
request by submitting what's called a
hurry to the server and that Cleary
resolves all the other requirements that
you have on the front end and then you
can display the data in the UI and
there's also really rich ecosystem and
great community around graph QL
despite the fact that it's really only
three years old so what does a graphical
Korean erection look like so here on the
Left we have front-end client and on the
back end we have the server and this is
what a graph Kure actually looks like so
it has a number of fields and these
fields describe the data requirements of
the front-end so translating this into
expressed by this query are basically we
are asking for a user with a particular
ID but we only want to retrieve the name
of the user and then there also is a
relation from a user type to a post type
and then we're asking for all the posts
of that particular user but only the
titles of the top so we can really on a
fine-grained level describe the data
that we actually want to receive from
the backend rather than being tied to
fixed to fix rest endpoints and here's
what a potential response might look
like so what's really important to
understand is that the query in the
graph theory dictates the shape of the
response that's going to be returned by
the server so the shape of the query is
identical to the response that we're
receiving from the server so one way of
looking at a graph cure one way of
as like an empty JSON object that you
sent over to the server where you only
have the keys of the fields that you're
interested in but not the values and
then just let the server fill in the
values for you and on the previous
slides I've mentioned three reasons why
you would want to use graph QL in this
article you actually have five reasons
and then if you want to learn more and
get a more thorough introduction I would
how to graphical outcome website where
there is a really thorough introduction
to the entire topic all right so that
brings me to the first part of the demo
I have prepared a little graphical
server for you and I want to show you
what graph tyrannies and mutations
actually look like in practice so here I
have a graphical server currently which
is running on my local machine and this
entire thing that you see here is called
a graphical playground graphical
playgrounds you can imagine as being
somewhat like a graphical IDE or a query
editor if you've worked with rest you
can compare it with a tool like postman
it basically allows you to send requests
to a graphical API and see we see the
response immediately and what's really
cool about graft and I've mentioned this
before already is that with every graph
get up you a PR you always get this this
auto-generated API documentation so here
I can click on the schema button and I
can see exactly what kind of operations
are available at that API so I don't
need to guess what kind of operations I
can now send but instead I can just look
them up so here on the right side it
says that we have one query and three
mutations that we can currently send so
let's try them out here I'll start with
the post query and just ask for the post
that are available and here is another
really cool feature of the graphical
playground which is also due to or
thanks to the graphical schema is that
the graph key or playground also has an
auto completion feature which is also
built-in so I can send this query and it
returns all the posts that the graphical
server currently has available so let's
go ahead and try a mutation so I have to
create draft mutation available and I'll
just create a post draft with some
asked for the idea in return and I'll
send this a couple of times if I now go
back to the post query and send that
again then the new posts that I just
created as draft so draft basically
means that the published field is set to
false these new drafts show up in the
response of the post way so I can now go
ahead and publish a draft by using the
and if I go back to the post we will see
that now the graphical server did what
we expected it said the published fields
are true and we also can use the neat
post mutation to delete a post I'll just
delete the very first one and going back
to the post query we see that the first
post disappeared
all right so much for how a graph kill
or how you can use graph key L in terms
of sending crews and mutations and what
a couple of these really cool tools that
you get for free when you're working
with graph kill actually look like so
let's move on to the next part and
understand how graphical servers are
implemented under the hood so one thing
upfront you can build a graphical server
in your favorite programming language so
it's not bound to a particular language
because graph deal itself really is only
in specification so it's just the
abstract specification of what a
graphical server actually looks like how
it needs behave and how it needs to
resolve its queries and no matter which
programming language you're using you'll
always find these three parts for your
graphical server so first you have the
API definition which is the graphical
schema then you have the concrete
implementation which are called resolver
functions and then you have the setup
for this so usually you'll probably want
to build your HTTP server in a way that
it speaks HTTP so that's like the most
common transport protocol that you're
using for graphical service today but
potentially you could also use another
transport layer so you're not bound to
http by the specification but most
graphical libraries that you'll find
today are using HTTP so let's take a
look at each of these three parts and
more detail so first the graph class
the graphical schema is strongly typed
and written in what's called the schema
definition language so it has its own
language to describe what a schema
actually looks like and it defines the
API capabilities and can be seen as the
contract for client-server communication
so whenever a client has access to some
graphical API it can read the schema and
it can infer all the operations that are
possible in the API and there are three
special route types that map to the core
primitives that are provided by graph
here that are called computation and
subscription and these route types
verifying the entry points for all our
operations and we'll see that later with
a practical example what that means and
here we go so on the left you have
probably the most simple graphical
schema that you could imagine for a
simple hello world app so this would be
stored on the server side somewhere and
the server would implement this
graphical schema if a server implements
this schema what does this tell me as
somebody who's access to the schema what
kind of careers I consent in this
particular case I can only send one
query and that also looks very simple
just like this and only uses the hello
route fields from the query type so this
is the query that a client could sent to
the server and then it could get a
response that looks like this
just a simple so just a simple object
that only has one field hello with
something inside of it and again the
shape of the query dictates the shape of
the shape of the response in this case
it's super simple because we only have
one field in the community we also only
have one field in the response object
here is a slightly more useful example
so here we are using the graph us in my
definition language to define crud
operations for a user so we first define
a user that has an ID and
name and then the Korea mutation types
they define the actual entry points for
our API so they define the actual
operations and in this case we have one
operation that lets us ask for one
individual user for a list of users so
these are the read operations and then
on the mutation type we have to create
user update user and delete user
mutations that allow us to perform the
create update and delete operations for
the user if we only look at the user
field right here what does this tell me
as the client of the API about what a
graphical query looks like that I can
send to the cure to the server it
basically tells me that I can send a
query that starts with the user field
and takes an ID parameter like this but
then because the return value or the
type of the user field on query this
itself user I can now nest more fields
inside the query and in this case I'm
just interested in the name of the user
with that particular ID and the server
again might respond with some data that
looks like this so this again is the
same shape as the query the JSON object
looks the same as the graph here to me
that was submitted let's now talk about
resolver functions because resolver
functions are the way how the graphical
server is actually implemented so what
happens when a graphic arrives at the
server and the data actually needs to be
fetched so this is the task or the
responsibility of resolver functions
they provide the concrete implementation
of the API and you basically have one
resolver function per field in the SDL
schema and this means that the query
execution process basically just becomes
a matter of invoking all the resolver
functions for the fields that are
contained in the incoming query and
actually graphical is sometimes compared
to remote procedure style systems which
is that which is a technology that
basically which which lets you invoke of
on your local machine but the execution
of the function is happening on a is
happening on a remote machine and
sometimes that feel is compared to these
kinds of systems because if you look at
it that way
that the graph q just like contains all
the function calls that are supposed to
happen on the back end
then it effectively is some some sort of
remote procedure call as well let's take
a look at an example again so here we
have our very simple hello world hello
world schema again and this is what I
corresponding resolver function would
look like in JavaScript so we define an
object that is called resolvers and that
resolvers object has a field that is
called query what you get is an object
that has a field that's called hello and
the hello world string what's important
about this setup is that the fields in
the resolver subject have the same names
as the fields inside your graphical
schema so it's important to write in
exactly the same way that you wrote it
in the graphical schema as well as the
hello function also needs to be written
in the same way as you have it in your
graphical in your schema what would it
look like for the crab unit user type
example so again we have the same
situation that we have and then again if
we follow the same structure and for
each field in the graphical schema we
have one resolver function on the right
so we have a resolver for both user and
users for the two queries we have a
creatives or update user and the user we
solve a function for those three
mutations and then we have also the
resolvers for the user type which if
they follow this very trivial pattern
you can actually admit because the at
least in JavaScript the the the
graphical JavaScript infinity is smart
enough to infer these reserves and then
you have the third part the setup so you
first need what's called a graphical
engine and the graphical engine is the
part in your breath
that is responsible to invoke all the
result functions for the fields that are
contained in the query when it's coming
in so the graphical engine markets at
the the graphical entered Orkut
orchestrates the resolver indications
then you need a network layer so if you
build your graphical server with HTTP
then you can use some common like web
framework in the in the example that I'm
going to show you later on I'm going to
use a graphical server library that is
called graphical yoga and that is based
on the Express framework so if you have
ever worked with node and build like web
server Earth node it's likely that
you've come across the Express framework
which is really popular in the node
space and graphical and yoga is built on
top of that so basically graphical
combines the HTTP capabilities of
Express with the graphical resolution
from the graph here a reference
implementation in JavaScript and then
you have your middleware that you can
integrate so that's also where you would
put in sorts of analytics logging crash
reporting all that kind of stuff
so let's put it all together and just
use the simple hello world example so
imagine this to be a very simple node
script where worked like the the most
simple graphical server that you could
write in a single file so here we define
the schema it's just a JavaScript string
that spans across multiple lines so we
use the backtick notation then we have
the resolvers object so these two things
we saw on the slides before and then
we're putting it together using the
graphical server that we import from the
graphic yoga library and then we start
and if you want to learn more about this
I recommend you this blog article graph
clear the schema which has a really
thorough introduction to how the
graphical scheme actually works under
the hood and also touches on how the
schema interacts with with all the
functions and then also a graphical
server tutorial on how to graphically
about coming up which brings me to this
second part of the demo where I'm going
to show you live how we graph your
server that I just showed you in the
previous demo actually is implemented
under the hood ok and here is the
implementation of the graphical server
so this was the graphical server as a
reminder we had these four operations
and here is now the implementation and
this graphical schema here that defines
these operations that we saw here in the
playground in the API documentation so
the so this API documentation precisely
is generated based on this graphical
schema right here we have one post query
we can actually also provide a search
string we can you can create a new draft
provide title and content of the new
draft we can publish a post and we can
delete a post here is the interesting
part so this is now the implementation
in index J yes here at the moment I'm
just using local post data for the
things that are happening in my server
so I don't have any persistence layer
setup at the moment and I just have one
post and that was the post that we saw
upon the initial query and here is how
its implemented them so the post queried
just returns the post data array if
there is no search swing provided if
filter for the title and the content of
all the posts
and only return those where the filter
applies then the create draft mutation
looks like this that I'm creating a new
JavaScript object that is called new
post I have this little helper here to
increment my IDs and then I pass the
title and the content that is provided
through the query I can read it with
this arcs argument here and then by
default set publish to false so that's
how we create a new post at drafts I put
this graft into the post date array and
then we turn it so that the caller who
submitted the mutation also gets the
data in return the publish mutation also
is fairly straightforward
so I'm looking for the post inside the
post date array of which the of which
the ID was provided through the mutation
I said the publish fields are true we
turn it and the lead post also fairly
straightforward just find the right post
deleted from the array and return either
didn't need it or now if there was no
such post so so I now restart the server
and remember because all the data is a
local if I restart it then the post we
just will show me the one post that I
store locally in my post data right and
it would actually be nice if I had a
query that would allow me to ask for a
single post by its ID so here I would
like to do something like this content
instead of instead of curing all the
posts I would want to create Ingle goals
but at the moment this won't work with
the current graphical schema
implementation because I don't have that
post operation yet so let's go ahead and
implement it the first thing that I need
to do for that is actually tell my
graphical schema or the graphical server
that I want to have this new operation
in my API and that works simply by
adding it to the graphical schema right
so the exclamation mark which I said
here is means that this parameter is
required so the graph your server will
reject any operations where the ID
parameter is not provided and then it
returns a post object and here I don't
put an exclamation mark because it might
be that the post with the provided ID
actually does not exist in the backend
so in that case we would return now and
for the implementation that's also
fairly straightforward I just add this
new resolver function that finds the
right post inside the post data array by
comparing the IDs
and that should be it
I'm restarting the server I am reloading
my schema and I see that the post has
been added to the auto-generated API
documentation and also these red
squiggly squiggly lines have disappeared
so I should now be able to use that
right it works all right so now you
understand what the graphical schema
definition looks like how resolvers are
being implemented
so let's now get to the next part
first what is Prisma so basically Prisma
is a strongly typed access layer for
your database think of it somewhat as an
ORM so it tries to solve a similar
problem but it has a lot more features
and it's also a lot more powerful than
traditional rhymes the way how you're
using Prisma for your database is that
there is a Prisma client that is
auto-generated based on the data model
that you provide the data model we'll
talk about it later will be mapped to
your database and it's also type safe so
one core goal of us that we have as
Prisma is to basically enable what we
understand as end-to-end type safety so
that your entire application should be
based on a coherent set of types from
the database to the front-end and graph
QL is what is making that possible and
grab and then Prisma also has a
declarative approach for for actually
modeling your data and for database
migrations and we'll see also what that
looks like
how does Prisma work so there are
basically these four steps when you get
started with Prisma first you have to
connect your or you are the database so
you can either use a new one or you can
use one that already has existing data
then you would go and define your data
model if you already have some data in
your data model then then Prisma will do
introspection of your database and will
actually also auto generate that data
model but you define you define the data
migrate the data base where prisma takes
a look at your and at your data model
and maps it to the underlying sequel
database or we actually also support
Mongo so it would also method to
basically the collections and Mongo next
up is that you generate the Prisma
client that allows you to actually talk
to your database through that type save
layer and then you can go and start
building whatever you want to build to
to give a bit more context of where
prizm actually fits into your stack in
the backend
I want to depict to graphically
architectures that are quite common but
there's also a spectrum in between these
two so these are two examples basically
of how you could build your graphical
application so the first one is what
would call a graphical monolith that's a
very standard architecture which has
these three very classic components that
we know from like three-tier
architectures with the client we have
the server and we have the database and
in this particular case Prisma sits
inside your graphical API server the
Prisma client and basically connects
your resolver functions to the database
so the entire goal of this is to
simplify the implementation of you
resolver functions so that you don't
have to write sequel or like things like
that inside your resolver functions and
make the resolver functions really long
and cumbersome if you use Prisma then
the implementation of your resolvers
will be fairly straightforward and then
the more complex one on the other side
of this on the other side of the
spectrum would be a micro services
architecture with a graphical gateway so
actually graph cure is like really often
also used as like this proxy technology
that you put on top of existing systems
so that your front-end developers have
this one career and API that they could
talk to one single endpoint and all the
of the more complex orchestration of
where the data is actually coming from
from which system that is happening
inside that gateway server and here you
can also use Prisma where we actually
also have a way that that basically
allows you to use Prisma as a standalone
server on top of the database that you
can deploy for example with docker and
that standalone server basically
provides a data
service out-of-the-box for your database
and then you can merge all of these
services inside the graphical gateway
for the example that we're building we
are very much on the left side so this
is the architecture that I'm using in
the live demo why graph command Prisma
is such a great set so first of all with
charisma you get really perform and
clearly resolution with graph killer on
the server side we often run into what's
called the n plus 1 problem which
basically means that if you're
requesting a particular user and then
you want to have all the posts of a user
database request to get information
about the user and all the post IDs and
then you need to make more database
requests for each post of that user and
that's called the n plus 1 problem and
the Prisma client has a built in way of
of basically alleviating that problem
with batching and caching and then with
Prisma you get crud and real-time
operations for your database
out-of-the-box so kind of similar
functionality as you also get with we
rethink TB for example when you get we
can receive life updates about events in
the database Prisma first dead as well
and then again the point about the point
about entrant type safety so you can use
Prisma also to build a REST API or some
kind of other tool where you would maybe
otherwise use the traditional object
relational mapper but this end-to-end
type safety approach is something that
you can really only get with WebGL and
that's what we're trying to enable and
actually only last week we released a
tool that is called graphical gem that
is a code generation tool that looks at
your graphical schema and scaffolds the
resolver implementations that you need
afterwards and it also makes your
resolvers entirely
safe so if you're using types good if
you're using go for example the prism
attract is also available we go
then this enables you to really have
type safe resolvers so you don't run
into so you don't run into any stupid
arrows at one time and if you want to
learn more about Prisma you can check
out the QuickStart in our documentation
or with the Prisma introduction let's
now get to the last part of the demo
where I want to show you how we can
adjust the implementation of the current
graphical server such that we actually
store the data and store the data and
then actual persistence persistence
layer that I'm going to set up with
prismo but first I want to just show you
that how Prisma works in a very simple
node script and for that I'm going to
going to create a new folder right here
in my project
and go to demo 1-2-3 and initialize a
new Prisma project and here using the
Prisma CLI so the Prisma seal I am is a
tool that you can install with homebrew
or with NPM and it allows or it helps
you with all the typical workflows that
now asked me a couple of questions about
how I want to setup Prisma for this new
project so I could either use an
existing database in which case Prisma
would introspect the database and then
generate the client API on top of that I
could go and start from scratch with a
new database that would be configured
with docker in this case but I want to
use a hosted database impress my cloud
to make things really really simple for
a particular demo here I'm just going to
answer a couple of questions and then
I'll say that I want to use the
JavaScript client since I'm using no TAS
in this application so let's see what
the Prisma init command now generated
for me three files to be precise we have
the Prisma llamo which is kind of the
main configuration that is used for
Prisma it points to a data model and
that data model is what I was mentioning
before when I was talking about
declarative data modeling and migrations
so here by default
prisoner put in this user type but for
our application what we actually need is
a post type that looks similar to the
one that we have defined in our
graphical schema and one thing you'll
notice also is that we're using the
graphical schema language also for the
data model right here in the future we
might open up the API that you can also
use some other kind of schema language
to define what what your data mall
should look like at the moment we are
using we're using graphical STL and it's
really suitable because it's super super
simple and intuitive and at the same
time it's also really powerful so it
supports constructs like interfaces and
unions as well so you can really express
a lot of things here and because this is
the data model that is going to be
mapped to my to my database that is
hosted in the cloud on the demo server I
can add some of these special directives
right here that express certain
constraints or extra functionality for
what's supposed to happen with these
types in my database and in this case I
want every idea of every post to always
be unique and I want that every post
that is not explicitly created as
published to have a default value of
false to put that API into place I need
to run the Prisma deployment and then go
ahead and generate my Prisma clients
and now I can go ahead inside my note
script and use that generated Prisma
client to perform operations against my
database so here is the code that was
that was generated for my FISMA client
and because we also put the types good
tight definitions in here I actually
also I actually also get auto completion
for the operations on the Prisma client
instance right here in my editor I'll
show you that in just a second I first
created this main function right here
and call it so that we can do so that we
can do asynchronous operations so let's
start by just requesting all the posts
that we currently have stored in the
database so I create a query on the
Prisma client and here my code editor
suggests me all the different operations
that I have available so already at this
point you basically take advantage of
this strongly typed layer for your
database despite the fact that I'm using
I still get Auto completion for the
operations that I can use on the prizm
our client which I personally find
pretty my pretty amazing so here we go
we just asked for all the posts and then
console and see what happens what do we
expect at this point actually we expect
an empty array but before I actually run
the script we need to do what JavaScript
developers love most and that is adding
new dependencies to the project so I'm
adding the prizm our client lifts and
gradually pendency and now I'm actually
sorry ah thank you thank you so much so
I'm doing live coding and please if you
catch any of these kinds of issues
I do not thank you all right we see that
at empty array is being printed exactly
as we expected because the new database
on FISMA cloud actually has no data in
it yet so let's go ahead and change that
by creating a new post using the create
post function right here again just
providing random data but always with
Auto completion and if I run this again
then we see that one post has been
created I can run it again and we see
that both posts are now part of the all
policy then I just quickly want to show
one more thing so here this post field
also allows me to provide a couple of
filters for for pagination or to just
filter according to specific properties
so here if I provide the wear filter I
can see all the different ways how I can
filter the posts and I could for example
do some filter for posts that contain
this in their title and then I expect
that I just get the one that I created
first back all right so far for the
Prisma client and now let's bring these
two worlds together
the Prisma client and my result of
functions to see how the Prisma client
helps me to implement my resolvers I'm
deleting all the previous
implementations because I don't need
them anymore
this and I'll start with just creating
the queries actually so put comments on
all mutations so that we can test
everything step by step so the way how I
now implement the posterior right here
is basically by just calling the post
query on my prisoner client but because
we have this search string right here so
here I want to make sure that I'm able
to filter for the right objects I want
actually have two conditions either the
title contains the search thing or the
content contains my search string and
for the post operation it's also fairly
straightforward I simply use the post
query that I have available here and
pass the ID that is provided in the
query let's test this so I'm starting my
graphical server and going back here and
now we were back in the playground that
I showed you in the very beginning where
this time if i refresh this because I
commented out all the mutations we just
have the posts and post that cure is
available at the moment but if I now
send the post query I expect to see the
two posts that I previously created in
the script so those two with with the
random content and the random title
there is a slight back at the moment
because I'm on the latest beta is that
sometimes mutation the client are
executed twice but that's on the beta so
you can still feel safe about all right
so the post query works let's actually
see if we can also
and there we go this curry also works so
let's go ahead and send the mutations
for the create draft mutation we just
use the create post mutation that was
generated by Prisma for the title we
provide the title and for the content
the content that were submitted through
you're using typescript then all of
these resolver arguments right here and
the return values will also be typed so
at the moment for me it's like a little
bit hard because I need to make sure
that I don't introduce any titles if I
were using typescript then the compiler
would catch all the issues that I
introduced in my resolvers form for the
published notation we are using the
update posts operation that's provided
by the Prisma client that take a where
argument to describe or to specify which
posts should be updated and then what
data we want to update update so we want
to set the published field to true and
finally for delete we have the delete
post mutation where we can also provide
the ID of the we need it let's start the
server oh so now graph your complains
because I only implemented the resolvers
and it's trying to match those resolvers
against the graphical schema but because
currently there is no mutation
complaints so I'm putting in the
definition of the mutation starting the
server refreshing the playground I see
that all my operations are back I can go
ahead and create a new draft
so this probably again was created yeah
and was created twice so let's use the
delete post mutation to get rid of one
of those and let's see now we should
only have one left that's the case all
right that's the demo how you can build
your graphical server with prisoner
before I let you go I quickly want to
add that we care a lot about the
graphical community and we're hosting
the graphical conf next year here in
Berlin so we rebranded what was formerly
actually called the graphical in Europe
conference this year we had around 500
attendees last year there were 300
Facebook from Twitter from Shopify from
Yelp so really high profile companies
that are using graphical in production
next we also had the gravity are
co-creators speak at the event so I can
only recommend if you're interested in
graphical and how you can introduce it
in your company that you get your
tickets for graphical context year and
that's all I have thank you so much