Well, this is a depressing title. RIP. Rest in peace, and I hope rest means, like, restful.
And not like this is the end of go, because I kind of like go. Anyway, this is going to
be a very interesting talk. Rodolfo Plaza, thank you.
Oh, actually I don't have my notes, so I'm going to swing it because I had to clone.
Anyway, hello everybody, thanks for coming. So I'm going to present a project of mine
that I created like maybe years back, a few years back now. It's called Rest in Peace,
and it's about to make rest in peace, oh ho. So in 2021, Jan Lans Taylor and Robert Grissmer
created a talk about how to use generics once they create implemented, actually implemented,
the generics in go. And they were like, basically, I don't know if I have audio. We'll see.
No. Anyway, so basically what Jan Lans Taylor is final words were, please use generics wisely.
So of course, when a figure of authority asks you to use something wisely, what do you do?
The total opposite. And people from CrowdStrike security company decided, I don't know if you
can read in the back, but basically they were like, created a channel on the discord.
It was a creative usage of generics contest submission, submit your worst implementation
of generics in go. Basically, everything that Jan's told us not to do.
So my, I did a thing I'm pretty proud, my, let's say to make the world the worst place,
was an, I think, await in go because who needs go routines and channels anyway.
Some people even did some try catch. If you're missing those good things from other languages.
I got a plush because, you know, when you do something, the world like gives you something
back called karma. And just for records, I listed everything that was attempted.
We had like monads and stuff like that. Anyway, but out of all of this, I created something
that thought was actually useful, use of generics, maybe not the one that was like supposed to be
because the current implementation is not optimized for this use case.
But I thought it was a nice anyway. So about me, I'm Tanguy, I'm from France.
I worked 17 years in IT and I'm also CEO of HTMX. Okay, one person knows about HTMX.
Anyway, so as you will see from this video, oh, we have sound now.
Anyway, I'm ready to make anything for money. So I'm a freelancer.
Specialized in go since 2015, worked in a normal consulting before that.
I worked mostly on classic restful APIs, backends, and I've done some blockchains.
And I stopped freelancing for a year, about a year to work a dagger.
You should check them out. I think what they're doing is pretty cool.
It's CI, CDS code. And I'm also very interested in pushing goes in more, I didn't say that, areas than just like
microservices and web backends, so GUI, game engines and stuff like that.
And the next talk will be about GUI. So I'll advise you to check it out.
So now, can anyone recognize this?
Basically, it's, yeah, thank you. Basically, it's the HTTP handler code that anybody does.
You might even have like a validation step if you're fancy.
And, but we do all of this code in the end, we decode the JSON and we encode the JSON for the response.
But all of this is just for this line right here.
For just this line, we do all of these gymnastics.
So that's a lot of code. And let's say we had another handler to deal with another type, another type in our API.
And now we do basically copy paste all of that previous code and change the code here, here and there.
Myzermanos, whatever. Anyway, and so again, I see like a lot and a lot and a lot of duplication.
And for me, like duplication, it's just, it's just something we should try to avoid as much as possible.
There are some of the few rules about the rules of two or three, which I think is good.
But when you create like a big API, you have more than two or three copies of that code.
So you can have a solution and abstract the handler and create like a very unsafe type to basically get whatever you want in it.
It can make it work, but then you call your back end, but you have to deal a lot in the back end.
And then the back end will deal with a lot of type casting everywhere and it can fail many times.
So you need to do a lot of hair handling.
And here I put like basically what we should do to convert from one type to another and make sure it works.
And it's all of this. All of this is, I don't know if I have the thing.
Yeah. So basically all of this is for two types, for a structure with two fields, A and B.
And for all of that, we have all of this boilerplate that basically take the dynamic code,
transform it into a type safe that you can actually use in your back end.
That's again a lot of code.
And then the real back end can be easy once you have the right types,
but we had to do all the way to here to be able to just call a simple back end.
And by the way, if your back end is just that and you can make money out of it, go for it.
So as I said, a lot of runtime reflect boilerplate to get back to types and potential reuse of the handler.
So we had a lot of durable potential. Not so sure about it.
So if finally we had a solution, thanks to Go 118, we have the generics.
And so that's when this ID popped out.
So the pro about generics, we have better type safety.
We have better performance than empty interface.
And as a wise person said, empty interface means nothing.
And for this user, sorry, mis-type, for this use case, for my use case, we don't have better performance.
There's an article from Vincent Marty that talk about this in depth.
But somebody told me maybe it has been improved since.
So maybe it's the procated. I don't know.
And in general, it's more readable code for the users.
And it allow more like don't repeat yourself all over your code base.
So for example, without generics, we have this.
So I just want to check the minimum between X and Y.
And can anyone tell me what it prints?
OK, not very interactive. OK.
Well, actually it doesn't print. It doesn't even compile.
Because mat.min accepts only float 64.
So you just have to do this.
I hate you, but I hate it.
So, I don't know. I do it disgruntly, whatever.
Not my native language, sorry.
And with generics, we have this function, which is way better.
It doesn't look like it, but it's way better.
So the library code is not that great to read.
That's for sure.
But you can get used to it.
And so you compare the previous one and this.
Like, yeah, it's not one reads better.
But the user code.
On the user code, it's really way better.
You don't have to cast those everywhere.
So it makes for a better code base.
So what about rest in peace?
OK, I'm checking.
OK.
So rest in peace.
The idea is to basically use generics to avoid all the...
this HTTP boilerplate that I presented.
For example, here we have some user code.
We just wrap strings.toUpper in a function
which is like an input, output.
I don't even remember the name.
But basically it takes a context, it takes a type,
returns another type, and an error.
And as long as your function respect this interface, you're good.
And you can just wrap it, send it to the rip.handle,
and you indicate the method, then you indicate you call this function.
And then you have like a route options.
And then you can just call curl on uppercase,
and it will just put your input into uppercase.
Magically you don't have to handle any HTTP about that.
Library code, less readable, I will admit.
So we have the type input, output, funk,
which is like the function that needs to be respected
to be used, then in the handle,
which takes the input, takes an output,
and put the method for this route,
and then you can just pass it like that.
But this was fun to do.
It was my first experiment, but I wanted really to go a little bit further,
because I do a lot of rest back-ends,
so there are a lot of routes to deal with for resources.
We need to create, delete, update them, et cetera.
So I wanted to automate that as well.
So rest in peace.
So the key concept of rest services is the notion of resource.
It's accessible via an URI,
an action on the resource URI via HTTP methods.
I mean, this is one implementation about rest.
Normally it doesn't have to be HTTP, but anyway.
And the current state is sent back through the same system,
which in this case would be HTTP.
So on the user code,
I create like a user provider, like an entity provider.
I pass it to here.
I decided this is the path I want,
and here I just take the default route options.
And thanks to that, we'll see what it will give us.
But so this user provider needs to implement this interface.
Okay?
So create, get, update, delete, list all.
I will update that because list all is a little bit too much.
I need to handle pagination and stuff like that.
It's not there yet.
But once you implement that on your code,
you can just use your code.
You don't have to deal with any HTTP whatsoever.
And you pass it to this function.
Then you have a whole slash user with all the bells and whistles,
which gives you all of this.
You can create the entity.
You can get the entity.
You can update the entity, delete, list.
And I recently added fields.
So now, because you can use patch, basically,
to update just part of your entity,
but the protocol is not defined.
So you have to define your own way of doing patch.
Is it like text-tips or something like that?
And it's a little bit quirky.
So I decided I found somebody talking about a pattern,
which I liked,
which is basically you take the whole path to the field,
and then you can just put and get from it.
And so that's how you update part of your resource.
And so you have your entity and the entity provider
thanks to a type inference that improves.
You don't even have to pass that.
You can just pass directly.
You don't have to put the square brackets and put those types.
So you pass the URL, the entity provider,
and the route options.
And here you go.
You're good to go.
What you get, creation of CRUD-HDP endpoints,
content negotiation for many encodings.
Right now we have JSON, XML,
Protobuf, MessagePack, HTML, HTML forms.
We have automated resource web pages
that can edit the resource.
Right now it's very nice UI.
You see this is not my major.
And a harmonious way of handling common scenarios,
and because I've worked on many projects,
and maybe because duplication, you do it once,
and then you forgot you need to update all those
boilerplates you've done, so then you forget.
And then the behavior between all your handpoints
are not really coherent.
So that makes a good thing, I think.
For example, this is just an implementation
of adding a new encoding to this platform.
That's the whole code to add the JSON encoding
on REST in piece.
So you just, I have like a facility like the RAP codec.
I use the JSON new encoder from the standard live.
JSON new decoder, then I define the MIME types.
That's it. You're good to go.
Most of the implementation are like that.
So RIP is to HTTP.
What an ORM is to SQL, me.
But I know that how many of you hate ORM
just to see if, okay, you might hate me as well.
Anyway.
But seriously, I hope it will help you
create services more easily
because I have a pain of repeating all this code all the time.
So here's the QR code.
Like, subscribe, click the back icon,
something like that.
Anyway.
And here's a demo.
Last time I did live code, it was awful,
so now I have a video.
Amazing.
So I just run the server.
And so all the logs that will print in yellow
are from the servers.
There is one that is from the logging handler
that is the logging middleware.
And the other one is from the backend code
that we just logged for ourselves.
So here I just get the list of users.
There is only one called Jean.
So here we see the backend.
Whoops. No.
No. Sorry.
Anyway.
We'll check on the next one.
So now we're going to create a new one named Cam.
Are you stopping, please?
Thank you.
I'm sorry.
All right.
Okay.
Mm-mm.
Did I check this video?
Maybe not.
Okay.
So maybe it will take a little longer.
I'm sorry about that.
Yeah, that's karma.
Are you serious?
Okay.
So, oh, yeah, but also there was no output.
So we just saved this new user.
So here is the log from the backend.
And this is the middleware, the logging middleware,
which is just a apache log style.
Then I go, then I released again to just confirm
that we have a new user in our list.
Then we have, we just get one user
and we decide to display as XML
because why not live in the past?
Because on each endpoint,
you can have multiple encodings
based on whatever I do content negotiation.
So if the browser or whatever client asked for,
and I have it, I will give it to you.
That's your problem.
If you want to XML anyway.
So here we're going to just modify the first users
and call him Philip instead of Jean.
So here he is.
Check is still Philip.
Yeah, good.
All right.
Now I just want the field.
So I just want the name of this entity.
And so it just returns it as a JSON string in green.
Now I'm going to, I don't know what I'm doing.
Oh yeah, the email address got thrown in a trash
because I did a full put on the entity
and didn't specify the email address.
So I'm going to just modify this field
to modify the address.
So now I do a put just on the field,
on the email address field.
And now I'm going to check again that it's correct.
And here now we have a correct email address
and correct name.
Then I delete and then I will just check
that we rightfully so deleted
and there is only one user left in the thing.
So yeah, so that's what you get.
Sorry, it switched this as well.
Okay.
So that's what you get with just like this one line
of handle entities and the whole backend implementation,
of course.
But yeah, I think it's pretty cool.
On route option, it's something that I added
since I did this talk in Golab.
So now each route can have their own set
of handle encodings and middlewares.
So that's pretty nice because before it was like a global state.
Not good.
Okay.
And for this to implement that,
for example, we need the entity,
which is just like the user struct.
And we implement those two method,
ID string, which return the ID as a string
because our ID is an int.
And the other way around, we need to convert
from an int to a string.
So if you have a better design,
come talk to me because I'm not very satisfied with this,
but it is what it is and it works pretty well.
Plimitation is quite simple.
And then on the entity provider,
so on this example, it's just like a map, memory map,
and we just, I just present you the updates.
So this is just the backend you have to write.
I put blogging because why not?
I get my user from the memory,
and then I just update it and that's it.
So that's the code you have to create.
So basically I tried, like with the memory map,
it's like 100 lines of code for this,
for all those method and implementation.
I did in SQL, it was 110, something like that.
So then you really reduce to just that.
So for the future, oh, I have time,
yeah, maybe I will have time for another thing,
but I'm going to just finish that.
So for the future, I would like to do nested resources,
but I've heard like even Django REST API doesn't do
nested resources, so maybe not.
I want to add pagination,
I want to add open API auto generation,
so then you could generate whatever client
for your system directly.
I would love even more 8 OIS,
I don't know how to pronounce that,
but to have links and stuff,
so the API is self-discoverable, I guess,
even more than open API.
And I would like to overly improve the API.
So since last time, I did like the route options,
the fields, I added protobuf during my way back from Italy,
and I would love to use a log and slog,
better handling and customization of HTML templates
because you will see.
And I would love also to generate GUI apps for that directly
so you don't have to also bother that, of course.
Simple GUI apps.
So let me check if I can do this.
Yes, yes, no, yes, yes.
Okay, so yeah, this is my beautiful HTML GUI skills.
So we have the user Jean.
For example, we decide to, I don't know, Jean Marc.
All right.
And we can add a new person,
see like a very well designed from the 90s,
as vintage as me.
Let's add Marc here.
All right.
Okay, we get back there.
Then we have our full list and we can just delete.
All this is thanks to HTMLX,
which is you should check it out.
It's pretty cool.
Anyway, so this is the thing.
I wish we could update those through by what you want, actually.
And then the last demo I have is I play with my daughters
a game called GoCraft, which is a implementation of,
simple implementation of Minecraft in Go.
And to bother them, I was like, how about I use my thing
and see how it's usable and just be able to create blocks
in the middle of their construction to annoy them.
Or I can just delete and yeah.
So for this, I'm just going to show the code at four last minute.
I created a block type, which the ID will be the coordinates,
XYZ.
So my ID is, maybe, yeah, I guess I can still see.
Yeah.
Okay.
So I split by X.
So the ID is basically, if I show this, it's like that.
I'm sorry.
So I just say like the coordinates in XYZ as the ID
and then I just have to marshal and then marshal this.
And then in the game, I didn't implement get,
I just implemented create.
I get the coordinates.
I create in the right format for the game.
And then I update the block, dirty block.
So this is really code just about the game.
I'm not doing any HTTP in there.
And here the delete, the same.
It's just like code about this specific go game.
That's it.
And it works.
And yeah.
So if you were excited to use it, talk about it or something,
go talk to me.
I have a bow tie.
You should recognize me.
And so I would love to talk about it.
If you have like a design ideas and stuff, I'm really up to it
because I think we could improve it.
And discuss about it, contribute anything.
All right.
And I want to thank the go team for the generics.
Without that, it couldn't have been possible.
The Ghostrasburg meetup because they had to suffer through my
first iterations of crappy slides.
The logo from a fellow Strasburg gopher.
You for coming here, you online.
I don't know where is camera.
I guess there anyway.
And for them in the go, they have organizer because like you're
really, really top and HTML for the mean, of course.
One of us.