All right, so next song is the editing and the audio.
Thanks.
Thank you.
I'd like to see so many of you here.
I didn't expect this amount of attendance here,
but it's good to see so many people interested in a topic like
David Drake, Stephen Aki, I tools.
Let me say a few words about myself.
I am, oops.
This is not working.
Then I am going to use the keyboard.
My name's Eric.
I'm a software engineer at Profilment Tools.
And in my free time, I'm an open source maintainer in the GraphQL space.
I mainly work on GraphQL in Python,
so that includes the libraries like Graphene and Strawberry.
And let me say a few words about Strawberry first.
Strawberry is a GraphQL framework,
which enables you to easily build GraphQL applications in Python.
It was created by Patrick Aminio.
And it follows an implementation first approach,
which is a subset of code first, GraphQL libraries.
And it's basically inspired by data classes,
and it really makes you implement a GraphQL way,
GraphQL API in a very pathonic way.
And Strawberry offers integrations for Django,
Cicral, Cami, Pedantic, and more.
And if you've been in the Python space,
and you see Python, Django, and Cicral,
you probably know where this is headed a bit.
Just our curiosity, who here has used,
or who is using Python actively.
In an API project, that's nice.
And who here has used GraphQL in Python before?
Okay, not so many.
Maybe I can inspire a few of you to give it a try in the future.
But let's get to the topic,
and have a look at today's API development
and how many of you probably develop your APIs.
And that is using an API first approach.
So basically, you create a concept for something
you want to add to your application.
In this case, we have an example,
API over user, and a post, for example, for block application.
And you can see you have a couple of types, a user type,
which has an ID, and the user name, and the list of posts,
as well as a post type, which consists of, of course,
the title, the content, and you can also fetch the author for a post.
And down here, we enable the user,
or enable any API consumer to fetch users from the API.
This case by ID, and it will turn a user.
If you want to start off when doing sort of API first,
you create a contract, you say, this is our API.
So the consumers know how to use it,
and then you start implementing it.
So basically, instead of implementing this API,
it would look something along the way.
It's lines of this.
Very similar, as you can see, you can see the user class.
You can see the post class, and then to resolve the posts of a user.
You add to certain data resolvers.
Like over here, you call the post service to load the post of a user
with the given user ID.
And you do the same for your queries.
So down here, you add a result to get a user by its ID.
And all of this is manual, you have to add it step by step.
And usually, in order to be able to do that,
you need to implement the methods that are called here.
In this case, we have a service layer, including a post service, a user service,
and this service layer, again, needs to access the database below that
to actually fetch the data.
So after declaring all of this, you again have to make another declaration
step and declare some database models.
In this case, I'm using a Django flavor to just declare the models.
And over here, we have the models for a user and post again.
As you can see, they're very similar.
And they, again, describe how the data is mapped to SQL Arcami,
and to SQL SQL database, I'm sorry.
And yeah, if you map the two SQL, it would look something like this.
And if you remember the schema I showed you, it's very similar,
especially in this overview.
And the question I always have when working on applications like these,
where you have a strict layer separation,
doesn't it feel kind of redundant to declare your types two or three times
with minimal differences in the fields?
Okay, I'm not going to argue against clear separation of concerns
and applications that's an important pattern,
and it has its sense.
But in very quite heavy applications,
just pulling your username through with the same type through all of your layers
and your application can sometimes feel exhausting,
and it can take up a lot of your development time.
You could use for other valuable things like actual features.
So I wonder, doesn't it feel redundant to do it a bit?
And let's examine this further a bit at first,
by looking at the control flow of such an application as the one I've shown you.
So right here on the left side we have a sample query,
which just gets the user of the ID one
and touches all of the posts associated to that user.
And this query is usually passed by a GraphQL execution engine,
which then calls the appropriate data resolvers to you have defined in your schema.
So in our case, it was the user resolver.
And then, next the user resolver,
it calls the user service to actually fetch this user
from the database.
And then the data flow goes on to the object relational method,
the Django models, I've just shown you,
to generate a SQL query to actually fetch the user from the database.
So in this case, we can see select ID username from users is one.
So next up, we need to fetch the posts connected to the user over here.
So once again, after the user is resolved,
neglected execution engine goes ahead and resolves the posts,
fields of the users.
And again, here the user post resolver is called.
It invokes the post service to get all of the posts from the database.
And again, another SQL query over here is formulated.
So when you build such an application,
basically you need all of your service layers.
You need your database access layer,
and you need your schema layer.
And then you need to glue it together.
Using a lot of glue code, right?
Calling all of the services from each other.
And this is where database revenue APIs come in.
Because the paradigm has just shown you,
basically has a workflow from the left side to the right side.
You start with an API schema,
and you end up at a database schema,
which fits the kind of API you want to provide to your consumers.
And as we've just seen, for many cases,
like the one over here, the database schema already contains
enough information to infer an API schema from it.
Right? We have the database types.
For example, strings, we know primary keys are IDs in our schema.
We know the relationships.
For example, by foreign key relations,
we know which types are connected to each other
in our GraphQL schema.
So basically, in database revenue APIs,
we want to go from this to this,
and actually infer the API schema
for what we have in our database schema.
In this case, for our strawberry-based approach,
we would want to take this Django model.
We formulated for our database schema,
and it somehow generated the GraphQL schema out of it.
And for strawberry Django, it's easy
as replacing the code with this.
So now over here, you can see a lot of things have changed.
I removed all of the fields from the user and post type,
and we changed the annotation up here to a strawberry Django type.
And in that case, it tells strawberry Django
to actually take all of the fields from the post model
and put them into the GraphQL schema.
There are some static methods, for example,
for the foreign keys, for the chart fields, and for the text fields,
which are mapped to appropriate GraphQL scalers
in the GraphQL schema.
And the most magical thing about this
is that you don't have to care about data
resolving any more either.
Because now you can just plug in
that strawberry Django field into your query type,
and everything we have done before
to fetch a user by its ID or to fetch a list of users
is automatically handled for you by the framework.
I'll show you that in a second.
Basically, having a look at our control floor
from before again, all of this glue code you had to write before.
You can remove it with strawberry Django.
You don't need a user service or a specific user
resolver for your example anymore.
It will be handled for you by the framework.
Instead, you plug it in, and you get some new features
like query optimizations.
So if you look at the query before,
you have two separate queries which are called
and that is kind of inefficient.
You want to use or leverage the query planner
that is provided to you by the database
as much as possible.
Like you cannot write a more efficient query
than any of your business logic,
then it's already present in any database you're using.
And frameworks like strawberry Django
are able to read the GraphQL query
to analyze what's field you request it
which relationships need to be joined onto the query
and generate a corresponding SQL query
out of it to optimize the way you fetch your data.
And it's all automatically done in the background
you don't have to do anything for it.
The next feature you just get for free
is a pagination interface.
Basically, if you know about cursor-based pagination,
it's all implemented there.
You could also add other pagination styles and
flavors and have that automatically generated for you.
Another nice feature is automated filtering
because at least I also have a lot of struggles
with adding a lot of filters to my API.
Because it's kind of annoying.
It's very simple.
You have to edit in all of the layers in your usual code base
and with sorry Django, all the filters that are available
on your SQL model are automatically available in your API
if you choose to do so.
For example here, I can filter all use by a user name
that starts with Eric and then that will work.
One of the nice things about strawberry Django
is that you can automatically create track mutations.
Basically create update, delete mutations,
which insert the entities based on the database schema.
So with this, you have already covered a large part
of basic application functionality.
Like reading data, reading lists of data
and modifying the data.
But many applications have custom requirements.
You don't want any type to have any filter available
or maybe any field in your database should be accessible.
For example, a password hash, if you start in your database
for some reason, shouldn't really be accessed accessible
in the API.
That is where customization plays an important role.
And shortly, Django, it's really easy to do that.
Over here, you can see our post type again.
And I've added the fields back.
However, I haven't added the back exactly as in the example
in the beginning.
You can see here, I added the title fields.
But I annotated the type of the title fields as auto.
And auto just tells the framework
to resolve the type based on the schema type in the database.
I wanted to modify the content field to a type called Markdown
just to signify that this requires some additional
parsing.
And I can do it as simple as changing the type here.
And the framework will automatically
still resolve it back to the database type.
Another thing I can do is use other nice features of strawberry
like automatic handling of permissions
and add them to the fields in the database.
And it will be resolved for you.
So it's really fluent.
The kind of customization you can do from a purely database
oriented type to some type with a little bit of business logic.
You choose how much you want to add.
And the next important part after customization
is extension of your API.
Maybe sometimes the database type is not enough.
You need some custom logic on top of it.
That's why accessibility is very important to do easily
in such frameworks.
So this example, you can see that I added a resolver for a post
caption to all the post five.
And as you can see, you can just use the data provided
in the database model inside of these resolvers.
For example, here the caption's just the title with the current date.
And I can access all of the database fields in these resolvers
and do not have to worry about any missing data,
not being present.
So far so good.
We've now talked about an extensible approach
to generate your objective graphical schema from a database schema.
Right?
You are starting off with a strawberry code base.
You have your web server hooked up.
And you have all the configuration already present.
And then you plug in strawberry Django.
And the Django or M to actually infer any models.
And infer this database schema from those models.
And then up cases where you don't actually want that.
Or you don't need that.
You just have your database.
And you want to get a graphical schema that actually enables you
to do what you want.
And this case is actually very important because in many,
there's a lot of use cases nowadays.
For example, grab your APIs.
I use an LLMs or AI use cases in general.
And you just want access to the data,
but not to the raw database.
And this is where tools like Post Graphile come in very handy.
Because they enable you to create a GraphQL schema just
from a Postgres database without any additional framework
or wiring.
You have to do around it.
You just install it.
And it works.
But still it's as extensible as the approach I've shown you before.
And what Post Graphile does is it reads the Postgres schema
that is stored in the database to automatically generate the API.
So you don't even have to define any models.
It's automatically read from the schema.
And similar to Strawberry Django,
Quad mutations, and all of the nice logic and the nice extras
like filtering, pagination are added automatically for you.
And you can extend it even further using a right variety of plugins.
I want to give you a little comparison.
It's going to be a bit harder to read,
but between Strawberry Django and Post Graphile.
So on the one hand, in Strawberry Django, you see I added some documentation
to the Post type.
And I also added some other information.
For example, I might have excluded a field here.
And all of this is handled via smart text in the database in Post Graphile.
So up here, for example, you can see the first tag is a comment
which I added on the Posts table.
And basically this will also lead to the Posts table being documented
in the GraphQL schema.
When I want to exclude fields, again, it's a smart tag.
It's the omit tag.
And here, I am extending a certain private field from the post type
by omitting it for reading from the API.
And you can do the same for filters, pagination,
or actually relationships, and maybe even whole types in your database,
schema that you don't want to expose in the API.
And also, this is logic is possible to be implemented.
Like down here, the caption of the post,
is just represented via a SQL.
We are post based function, which again, we solve status.
And you can automatically plug that into your schema.
So let's compare the two approaches on a basic level.
Both are very extensible.
You start with a set of features that every application needs,
and you are good to go in minutes.
But the main difference is that strawberry agenda really requires you
to have your strawberry up around it,
and your Python ecosystem of tools to get it going.
Our post graph is up and running right away.
You can, however, extend it and extend it with no JS code
to actually add more business logic, add more custom features,
and extend the schema, but it just works right out of the box.
Another big difference is that post graph
are really focused on having business logic in the database,
utilizing as much of the database as possible,
what strawberry Django is really focused on the features
that are present within an ORM.
So basically the database schema and the relationships you define.
And another difference is that post graph is just made for post graphs,
and strawberry Django supports all SQL implementations,
which are supported by Django or RAM.
But if you ask me a nowadays world,
it's probably always best to use post graphs for most use cases,
and it's not meant much of a mis to not have support,
for example, my SQL in those applications.
So let's talk about a few common pitfalls.
I get a lot of questions about migrations.
For example, many people are concerned
when coupling your database a bit tighter to your schema
on how to do migrations.
And actually my answer to that is pretty straightforward
when you're doing migrations in an application,
especially in a distributed system.
You also have to worry about not breaking things
based on the consumers of that database.
You have to be very careful if you're removing fields,
changing field types, and you have to do that incrementally.
For example, if you change the name of a field,
you have to keep the old name there.
And with tools like strawberry Django and post graph file,
it's very easy to add smart tags or custom logic to change field names
and map to the old fields first,
and after the migrations completed,
you have to make an API breaking change.
Because while the GraphQL schema is met to the database schema,
there are ways to customize it,
and there are ways to actually direct the data to the point
where you want it, and to use the database columns
that you're actually interested in.
This was mostly focused on GraphQL for now.
Since I'm working GraphQL, I'm a bit biased,
but I'm probably telling you the best way to do this is via GraphQL,
but there's great tools out there to do this in REST APIs as well.
First example is Postgres, which enables you to build a REST API
from your Postgres databases.
For example, the Python ecosystem,
there's a two like SQL model, which will also decrease the amount of workload you have
or the amount of layers you have to go through to map a database model
to an API model that is actually validated.
So, some of the database-driven APIs
derive an API schema from the database schema,
and they generate API types from the native types in your database.
And tools like Postgres file can leverage native database features
to use your technology as efficiently as possible,
without having to duplicate any types throughout the layers of your applications.
And by doing that, you are able to iterate rapidly.
I told you, you just have to start the tool and the API is going,
and then you can start with customization.
Usually, when you're developing an application,
you're adding a new feature, for example, a post feature,
you first need to edit everywhere, you code it,
and then, at some point, you can integrate it with Post GraphQL,
or Strawberry Django, everything is there immediately.
So, when we're talking about database-driven API tools,
we should also talk about when not to use database-driven API tools.
And for me, the answer is,
it really depends on the kind of application you're building.
And I really see it as a spectrum from pure-cut applications
on the one hand, which just have data you put into the database,
that's created, update, and delete mutations to modify that data,
and on the other hand, there's very behavior-centric apps,
very domain-driven applications with lots of business logic
custom code inside.
And I think for pure-cut applications, it's obvious.
Try it out, see if it works for you,
and it can save you a lot of time,
and bring you a lot of features, make your API greater than it ever used to be.
However, I don't think it only is only a good choice for pure-cut applications.
I think the separation point is somewhere around here,
because from my experience, even very behavior-centric applications,
with a lot of domain logic, contain a large part that is purely cut
for many types that are in the application.
And for this part of the application, you can still benefit largely
from using a database-driven API tool.
So, why should you use database-driven API tools?
Basically, you can utilize your technologies effectively,
save a lot of time, and get going with minimal boilerplate or blue code
in your application.
Additionally, you can make sure your database schema
is at all times consistent to your API schema,
where you want it to be consistent,
and you don't have any duplicate types you need to work on.
And this, all in all, enables you to innovate rapidly,
and build nice tools faster and easier than ever before.
Thank you.
Over here, you find the QR code to my LinkedIn,
feel free to contact me with any questions,
and here you can find two links to the docs of the tools I presented.
Any questions?
Yes?
There are any, or, are you aware of any kind of authorization
or access to the management?
So, I haven't gone too deep into this because the lack of time,
but I'm post graph, how you can do authorization also within Postgres.
There's a good feature.
I'll ask Benji back there for more details.
He's a maintainer of post graph files.
And post strawberry, for strawberry, Django and strawberry,
and all those database tools,
it's very easy to just plug it into the existing strawberry provision system
that we have going.
Yes?
You talk about migrations.
What do you know about provision?
Is it possible?
How is it used?
Okay.
So, since this talk is more focused on GraphQL,
the general recommendation in GraphQL is to not version your entire schema,
but to keep your schema evolving and back what's compatible is much as possible over time.
There's no real versioning strategy that I have in mind,
like right from the back, it would depend on the specific use case probably.
General recommendation I can give is to version by field,
so basically at a new type, next to your old type,
if you want to make breaking changes to the API schema.
Yes?
Yeah?
Are you going on a little bit to the opposite direction of what GraphQL,
or is you want to do an extra from the database?
And I want to try to kind of attempt the end,
I always end up having to sort of choose to give a dive version
and then I can use the tools anymore,
and I have them in interest.
I like the question,
because when many people first discover GraphQL,
they think, oh, nice, it's a big database.
I can use to access all of my data without limits.
And this is not what GraphQL should be.
These tools might enable you to do that.
What I maybe didn't mention here enough
is that you should still stick to certain best practices,
do not expose everything, do not expose every relationship
and every field in your database schema,
expose the data that is necessary to deliver your application
the way you want it to be delivered.
And that is the big advantage of these tools.
You are able to build a database,
like a database access tool,
out of them, because they are so powerful,
but with great power comes great responsibility,
and after all, at some point,
you really need to,
if you stick to best practices,
you will not run into these risks.
Any more questions?
Then, thanks everyone.
There's some stickers.
Thank you.