 Thanks, Johnny. So if you've met me, my name is Hermann Velasco. But my name is Bell German, and it's the German guy. But I am not German, so please don't speak German to me. I'm actually from Bolivia, so I speak Spanish. What I want to talk to you about today is building your own web framework in Elixir. And how this came about is because I work at Thoughtbot. And Thoughtbot work consultancy, traditionally done Rails. We've been doing a lot more Phoenix over the last couple of years. And even though I've looked at the internals of Rails, I've looked at the source code, I've looked at the internals of Phoenix, I've looked at the source code, there is a different understanding that comes about when you roll something on your own. So I wanted to do this with Elixir. I wanted to just sort of peel a layer off Phoenix, which is what I had been using, to get a better understanding of what's out there, what can we do with Elixir. And my experience was so wonderful, because I was doing this just for fun, that I decided to make it into a talk to share with people. So what I want to do today is I have all the code in this repository. I'm not expecting you to go there right now and try to follow along, because it'll be pretty intense. But what I want to do is try to replicate that experience with you a little bit, because it's a pretty powerful experience. At least it was for me, just to see how wonderful Elixir is for building web applications. And I hope that something you get out of this is realizing how nice or how complete the plug toolkit is. And as we go along, and I'll explain a little bit more what we're going to do, I hope you get one of two things out of this. One is maybe a better understanding of what Phoenix is doing underneath the hood, if you use Phoenix. And two, gain some confidence that maybe for simple things or maybe for complex things, you could roll your own. It is something that's doable, that Elixir allows us to do pretty easily. There's a lot of the tools ready. So that's what I want to do. So if you come out of this talk and you say, gee, that sounded pretty straightforward, I think that'll be good. That'll be a job well done. So I say we're rolling from scratch, but really we're going to be standing on the shoulder of giants. We're going to use Cowboy for our web server. We're going to use Plug Heavily, and we're going to use EEX for our templates. If you're wondering about the Legos, it's because when I program, and especially when I do Elixir, I feel like I'm building Legos. I'm back to my childhood, so that's what we're doing. Just a quick show of hands. How many people here actually use Phoenix? Wow, OK. So how many people have written their own plug in Phoenix to do something? So I'll go over this very briefly, then, just what plug is, since we're going to use it. But it seems like most people probably know what it is and have used it. Plug is both a specification and a set of modules and functions that help you interact with plug and a connection stroke. So can people see this syntax highlighting? Is it OK? OK. So basically, a module plug, the specification for it, requires you to define an init function that takes a set of options and returns a modified set of options, or in our case, the same set of options. It also requires you to define a call function that takes two arguments, a connection struct, which has all the request response data, and the set of options. So the init function gets called once, the call function gets called all the time. And those options are the ones that are coming out of the init. And the last thing you need to do is return a connection struct. That's basically the specification. We also have function plugs, and all they need to satisfy is essentially what the call function does in the module. All right. So where we're going? I'm sort of breaking this up into five sections. What I want to do is build an application from scratch with you. And as we go along, sort of refactor and peel off some layers that are more like a web framework. So we'll look at the basics first, which is sort of the routing and stuff like that. We'll then extract controllers, views, templates, something that looks more familiar. Then we'll handle forms, which I think is sort of the core of a CRUD application. Then we'll do a little bit of refactoring to have more of a web framework type feeling. And then we'll handle sessions and static assets, because I think those are kind of important. And the application we'll be building is super, super simple. It's not something that you would probably ship. But it's essentially just posting post to a timeline. Pretty common thing. So let's go ahead and get started, dive in. If you can't read the code, please let me know, because I can change the style really quickly. And there's going to be a lot of code. So hang in there. All right, we're going to start a new application. Call it Days, since we're in Elixir Days. And we're going to pass the supervisor flag, so it creates that for us. We're going to go to our mixed file. As a side note, this is how I'm trying to denote which file we're working on in directory. So you'll be seeing that a lot, but it'll go by fast. And let's add our dependencies. So in our application, we're going to add Cowboy and Plug, sorry, in our mixed file. And we're going to add the dependencies. Let's get those dependencies. And we're good to go. The first thing we want to do is add Cowboy to our supervision tree. So let's go ahead into our application module. And for top level supervisor, we're going to add Cowboy. Here, Plug is already doing a lot of the heavy lifting for us. This is all we need to do with Cowboy is use the adapter. We'll use the HTTP scheme. You can use HTTPS, but it's a little more configuration. We'll expose it through port 4001. And the last thing we need to do, well, this is an adapter for Plug. We need to pass a plug to it. So we will pass a module that needs to satisfy the plug specification. So let's go ahead and define that module. Again, directory structure. We define a module. And the first thing we're going to do is use PlugRouter. This gives us a lot of things. First of all, it defines a plug. So it satisfies the specification. So we can actually pass it to the Cowboy adapter. Second, it gives us a set of pipelines that you are familiar with in Phoenix. So you can define plugs that are executed sequentially in the order in which they're defined. And third, it gives us a nice little DSL to match our routes. So this is something like Sinatra if you come from the Ruby world. So let's look at it. In order to use PlugRouter, we have to use two plugs that it exposes, Match and Dispatch. What these do are very simple. Match will match, say, a get request to the root path with an implementation that you've defined. It'll save that, and then Dispatch will actually call that implementation. So you can imagine putting plugs in between those two and doing some stuff, and we'll do that. The last thing that PlugRouter does is gives us that nice DSL. So let's go ahead and define a get request. Or let's match for a get request to the root path. And we're going to send a response, a 200, and say we have a router. That send response is coming from the PlugConnection module that PlugRouter is importing. Super basic, let's run our server. We'll run it with MixRunNoHalt. And we go to Locaholes4001, and sure enough, we have a router. I think this is already pretty cool. I don't know. I was pretty impressed. But if you look at our logs, we don't know if we're getting a get request. So Plug has our back, and we can use PlugLogger. It's just another plug. It defines it. It satisfies the specification, and we get logging for free. But if you're like me, one of the first things I did was I hate typing MixRunNoHalt. I really like how it's Mix Phoenix Server or something like that. So we're going to define a little mix task for ourselves. We'll use the mix task and run it. And just whatever arguments would pass, we'll just attach that noHalt flag. While we're here, let's add a little logging to say that we're starting a day server. So now we type in Mix Day Server. It starts, we make a get request, and it looks nice. So it's already pretty cool. But if you get an error, it looks like this. And this is pretty crappy. If you're familiar with Phoenix, you have those nice error pages in development. And so I wanted to know, does Plug have this for us? And it does. We'll only use it in development environment, but we just use PlugLiBugger. This will wrap the call function. And it'll give us a nice error message. You can also customize this to change the colors and include images and stuff like that. I added some colors that will look pretty ugly, but just so you get the point. And now our errors look like this. So already looking better. So I consider that the basics. So we could match some routes and render some pages. But let's go ahead and make it more to a traditional web application with controllers, views, templates. So let's go ahead and extract the controller logic first. So that we have a router, that little piece. PlugRouter allows us to define a plug that we want to invoke when we match that route instead of directly defining the specification there. So that's pretty cool. As a side note here, the architecture that I went with controllers is a little bit different than traditional. So usually, Phoenix or Rails will have a set of actions defined in a controller. I always find that those don't share a lot of code sometimes. And I wanted to try something different. So every module will be its own action. And that plays really nicely with plug, because we're just going to pass that. So we're going to create a module called Days Actions Post Index. It's a little verbose, but I think it gets the point across. So let's define that. And this is just another plug. So we'll import the plug connection to get some helper functions. We'll define that init function and send a 200 back with plugs all the way down. We render, and it's working. I think at this point, we already see some of the modularity of plug really coming into play and how nicely it is designed in terms of you're using a module in the library that defines a pipeline that takes other modules from that library, and then you can extend it on your own. So I think that's kind of cool. But we want to render templates. So let's look at that. One of the really interesting things that I found about Phoenix when I first came into it and kind of blew my mind was the notion that templates are just functions. And I looked at a bunch of tutorials and stuff like that, and when I looked at it, I kind of got it. But this was one of the places where rolling my own gave me a way better understanding. And when I was first doing this, I didn't know if it was possible or if there was something complicated that Phoenix was doing. So it was really nice to see that EEX has this out of the box. So instead of rendering plugs all the way down, we want to pass a template or do something like that. So we're going to require EEX and use a macro. We're going to call this thing function from file. And well, EEX can also evaluate strings at runtime and stuff like that, like you might see in Rails, for example. But that's pretty costly. And so it has this superpower that I call it, super power, where it compiles the template to a function. So it's exactly what we're doing in Phoenix. We're going to tell it to compile a public function, call it index. We're going to pass the template that we want to compile. And then we're going to pass it the number of variables we're going to pass to that function when we call it and how we're going to reference them in the template. So in this case, we're going to call it adjective. You'll see why in a second. So now we can call this function just by calling index and we pass in coolest. So we're going to reference coolest in a template as adjective. So let's go ahead and define that template. And it's going to be super simple. And we're just going to say EEX is the adjective. So if you remember, we're passing coolest. Sure enough, it works. So this is already pretty cool, but it leaves something to be desired. What if we want to pass more arguments, maybe two adjectives? Then we have to update this in several places, the template, when we're compiling it, when we're calling it. It's not ideal. Also, these are positional arguments. So you can mix them up, kind of lead to weird bugs. What I wanted to see was if we could do something like Phoenix has, where it has that nice at value, like an instance variable looks like in Ruby. And it turns out EEX has that. So EEX comes with this thing called a smart engine. And it comes out of the box. So you don't have to do any configuration. That's a default engine. And so if you pass a signs as the variable that you're going to call, you can actually pass in a keyword list in your function. So now we pass adjective 1, cool list, adjective 2, fastest in the index invocation. And now in the templates, we can reference these variables with that app macro. So I thought this was really, really neat. And as a sanity check, everything's still working. So I found EEX pretty simple to use and really powerful. So I was super happy about that. But let's go ahead and extract that into a view, because I do like how Phoenix has templates, views, and controllers. I think it separates the logic nicely. So let's go ahead and define views. Essentially what we're going to do is just grab that code that we just wrote, remove it, and throw it into that view that we're about to define. So we grab it, and we throw it in there. So side note, I'm just wrote it vertically so you could actually read it. It's not the nicest style, but whatever. So now that we've put it in here, let's update our action. We're going to alias this post, this view, and we're just going to call it. So it was at this point that rolling my own really gave me clarity on this is just a module, and we're calling a function in that module and passing arguments. And it just so happens that that's the template having been compiled. So I don't know if that makes it more clear to you, but it really did to me. And so that was really neat to see about rolling my own that, huh, that is just a function. So we run a sanity check and everything works. OK, now that we have templates, let's go ahead and handle forms. By the way, if anybody knows what we're building in the background in Legos, you can shout it out when you know. What? Wow, that's really good. I thought you were never mind. OK. All right, let's handle forms. How do you, OK. You must have one. OK, so it'll be a simple form. We'll post to post to create a post with a post, sorry, and an author. Now the way we need to handle this, so we need a way to parse this information. And again, plug has our back. We're going to define plug parsers, or we're going to use plug parsers between the match and dispatch. And you can define what type of parsing you want, you could parse JSON or whatever. We really only need URL encoded and multi-part. And what this will do is it'll parse the body, but it'll do a little bit more. So a connection struct, amongst other things, has a query params key, a body params key, and a params key. And so what the plug parsers will do is it'll fetch the query params for us, because you need to fetch them before you access them. And it'll parse the body params, and then it'll combine them into the params key. So then we have that really nice pattern matching that you're used to in your controllers. You just pattern match the values that you care about out of con params. So we'll do that. So I think that's a really nice extra that plug parsers gives you. So now that we can handle that, let's go ahead and add the route so we can create our post. So we define the route, and let's go ahead and define the module. It's going to start looking repetitive, which is kind of the idea. We're going to import plug connection, define the init function. And here we use that pattern matching to get out of con params the values that we care about. Next let's write the redirect logic. So we'll redirect to the route path, grab the connection, put the response header for the location, put the content type, and we'll send a 302 telling them that they're being redirected to that URL. Now, since we're creating something, presumably we want to persist it somewhere. And I didn't mention Ecto in the standing on the shoulder of giant slide because I don't want to use it just for the demo. I think it's a phenomenal library if you need something for the database. For this demo, we're just going to fake a repository with an agent. So we'll put it in there. It'll be sort of like a key value thing. And it'll do for now. Since the repository is not super crucial to what we're doing to this talk, I'm going to go through it kind of quickly. So just bear with me. So we'll define an insert function. The author will be the key, and that map will be... We're going to put them in a list so that each author has a list of all the posts they've made. So let's define this repository. We're going to use an agent. We're going to define a way to start it. We're going to start it with a map. We're going to define that insert function. Again, it's a key value thing, but it's not really key value. It's a key, and then you're going to put all the maps into a list. And then we're also going to define an all function to retrieve all of the posts, regardless of who the author is. So again, this is not super important. You probably would be using Actor or something else. Last thing we're going to do, we're just going to throw this into our supervision tree so it gets started automatically, and we don't have to worry about it. So let's go to our index action now. Since we're creating and redirecting to our index page, let's go ahead and use this in our index action. So we'll retrieve all the posts and we're passing it to our template. So let's go ahead and update our template to make use of these posts now. This is going to look super familiar now if you've done Phoenix. If you have those posts, we're going to iterate through them and we're going to render the body and the author. So if we render our page and now it looks like this, I type in a post and an author, and it redirects and it works. We'll do a demo at the end. I'm not doing it as I go along just because of time, but the reason why I'm showing everything, even the agents, because I want to show that I'm not pulling your leg. There's nothing underneath that I'm doing that's not here. So, okay. So we're handling forms now. This is pretty cool. What I want to do next is to extract a little bit of the functionality that is more like a framework, something you might get, so that when we do our sessions and we add a sign in page and stuff like that, we make use of that and see how it feels to use just like we might have a framework. So we're going to define a day's action. And first of all, let's extract the super common things that we're doing across all our actions. So our index action, we're importing the plug connection and that init function, the same thing that creates. So let's grab those two things out and throw them into a day's action. So let's define that. We're going to use a using macro and throw them in there. But, so that's okay. But one of the things I want to do is, usually in an action or in a controller, you do one or two things. So either you render something or you redirect. So I want to see if we can generalize those things from what we already have and put them in here. So in our index action, this is the rendering logic. The only thing that changes here is that post index. So we're going to extract that and we're going to extract it into a function called render. And if you look at that, that's pretty generic. Of course, yeah, that's generic enough that I think we can throw that into our day's action. So let's go ahead and do that. We're going to do it in a, I think in a cleaner way, but we'll define an action, sorry, day's action helper, so a module within this day's action. We're just going to import that when we're using the using macro. Side note, I'm not the greatest with macro, so this might not be the best way to do things, but hey, so we'll define the module helpers and throw that render function there, just like that. So now our index action looks like this. And I kind of like this. It looks a lot more like something I'm used to. We're using day's action and we get all the posts and render them, simple. So let's go ahead and do the same thing with the create action. That's the generic part and since we had already extracted the URL, this is already generic. So we put into a function just to make sure it looks nice. Yes, I do like the thing from Phoenix, redirect the connection to the URL, so I did that. And let's just throw that into our day's action underneath that render. So that's the part we added. Looking back at our create action, now it looks a lot like something we might know, right? We're pattern matching the values, we're persisting them and redirecting. So that's pretty cool. Let's do something similar with the day's view. Now I have to admit that this is not as clear to me as the action, but anyway, I'll talk as I go along. So this is what we currently have. There's a lot of boilerplate maybe, that's wrong. The index and the, oh, that's awful. Okay, anyway, the syntax highlighting maybe a little off. The index and so the name of the function and the template are the only two things that are changing, right? So let's go ahead and pull those out. I'm gonna move that, all right. And we're gonna do the following. The root path, we're gonna leave it the same always. You could put this in a configuration file or whatever. And we're gonna define a macro. Again, I'm not the greatest macro writer, so hey, maybe this is not the way to do it, but we're gonna call something def template. We're gonna pass in the template name and the function name that we wanna map it to. We're gonna join that to the root path and then we're just gonna essentially throw that on the ex function from file. So we'll call our public function. We're gonna unquote those things and pass in that a science key. Since you could just import this into your view and it would work, but people like using that use word, so we'll just do that. So now our view looks like this. As a side note, I did another implementation that did it more based on configuration. So if you were using the days view and view posts, it would just grab all the templates under posts and compile them. And I found that a little too magic because, I don't know, it was a little magic. You could do it other ways, but what I'm doing is not meant to be a prescriptive way of how to do this, is just show you maybe a way to do it and see if you wanna do it your own way. So this looks okay. We run a sanity check and everything's still working. All right, let's go ahead and handle sessions. This is when I thought people would guess that it was a death star, but. Yeah, so sessions are a little more configuration, but plug again has our back. So plug, plug, plug, plug, plug, plug. I kinda like plug, or at least it's a very complete toolkit. I'm looking at you, Peter. So we're gonna use plug session and it allows us to store it either in an ETS table or a cookie, we'll use the cookie. We're gonna pass the key for the cookie and we also have to define a signing salt. So we'll do that. And something else that this requires us to do, in order to access the session, we have to put a secret key base. So we'll just use a plug, a function plug to do that. I also think at this moment, this is something really nice about plug, the fact that we are mixing plugs that are defined in the plug library and we're also defining our own function plugs, our own module plugs, so it's really versatile. And all we have to do here is put in the connection secret key base and put a giant string. Obviously you wouldn't wanna do that in your application, but I did it for the demo. And by the way, I generated that with how Phoenix generates their secret key bases. I did steal that. One last thing I wanna do with sessions is the session in the connection struct is one of those things you always have to fetch before you use it, before you get anything out of it or post anything to it, you have to fetch it. So we're just gonna add a plug to do that for us so that we don't have to do it all the time. So now that we can handle sessions, let's go ahead and define our sign-in page and interactions. And I hope that now you see how, this is gonna look repetitive and that's kind of the point. And I hope this sort of shows what it would feel like to use our own rolled up framework. So let's go ahead and do it. We're gonna define a route to sign in to the session's new action. Let's go ahead and define that. We're gonna use the days action and just define a call function, render that and call the new function on the sessions view. Let's define that session's view. It's simple like that. There's not much to it anymore. So I like that. Let's go ahead and define that template, sessions new. So it would be under days template sessions new. And this will be pretty simple. Just an email and a password and we can create that. So when you render that, it looks like this. But if you click sign in, everything breaks because we don't have the route. So let's go ahead and do that. We're gonna create the post sessions route to sessions create. Again, this is how we're using our framework now. We're gonna use the days action, pattern match the email. I am gonna ignore the password because we're not gonna do authentication. This is just a demo. So I am cheating. But we'll just grab the email, grab the connection, put the session in there with the current user email and redirect to the root path. Again, I don't know about you, but this seems like pretty normal now. So since we're redirecting, let's make use of this session in our index action. This is how it looks right now. So let's get that session, get that current user email and we're gonna pass it to our template or to our function, really, it's not template. Let's go ahead and update our template to make use of this. So if we have the current user email, we're gonna say welcome to that email. Otherwise, let's put a link to the sign in page. So you render and now we have that little sign in link. We click on it, it redirects us. I sign in with my username and my super secret password that we're just throwing away and it redirects us back here. So it's pretty cool, but I bet you can't sell this to your client yet because there's no CSS or images and we wanna make things look pretty. So let's add some static assets. Again, plug has our back. So we're gonna use plug static and we're gonna use it before our match because what it's gonna do is it's gonna traverse, it's gonna look for a static asset and if we can't find it, then it'll go through the rest of our plugs. We're gonna tell it to look at the root directory of our days application, that's the days atom and it's gonna start at the root of our path, of our request path. So this expects to look under priv static in your root directory. You can modify that but it's pretty standard. The other thing that this allows you to do is limit which directories under priv static to look in. So that way you don't have to traverse a whole bunch of stuff that you don't want to do. So we're gonna only look under images in CSS because that's all we're adding right now. So let's go ahead and add a link to our style sheet. Notice that the style sheet is CSS app CSS so it's gonna expect to find that under priv static CSS app CSS and this is at the root of our application. We'll throw some CSS in there that I hope you can't read because I'm not a designer so it won't be pretty, I promise. It'll be prettier but not great. And we'll also add an image. Notice it's under images, elixir days and we'll throw that image in there. I do apologize for having stolen the elixir days logo. I hope Johnny's not mad about that but now that we're here instead of just showing you another page, I can actually show a demo. So let's see how this goes. You can see that? Nice. Throw that there. All right, so now we sign in. I actually can't see this on my computer so my super secret password, it redirects me and say I love elixir days. Who's saying that? Jernsville. Oh, come on. You can't see that. Ha, this is a great, oh wow, okay. Presentation says no one. Of course I say it but you know, whatever. So there you go, it works and it's pretty simple but I think it kinda gets at the core of what a CRUD application does. So let me go back to my demo. All right, so you just saw that. So just some final notes as we go here. Obviously this is not a complete web framework, complete web application. There's a lot that it doesn't handle but what I wanted to get out of this or what I hope you get out of this is a glimpse of how easy and fun it can be to do this with elixir. Building it from scratch, of course it's not fully from scratch but peels off a layer. I hope you sort of gain an appreciation for plug. It's a really complete toolkit so I would recommend you go and look at the documentation. It has a ton of stuff that I didn't get to cover, like plug builder allows you to make your plugs into pipelines, has CSRF protection, requests ID, obviously can handle uploads, all that kinda good stuff. And I also hope this sort of gave you a better understanding of what Phoenix is doing underneath the hood. So if you go look at Phoenix Endpoint, I think that's a file, you would see a lot of the similar code that a router has. And last but not least, I hope this gave you maybe some confidence that for some simple CRUD apps, you can actually do this on your own. And it's not like elixir does it, makes it so it's really nice and easy for us and plug and EEX have already established a really good foundation for us to build upon. So if it's something you're interested, I hope you can do that. Again, the code is in this repository. If you're interested, go and look at it. There's some other stuff that I did there. And if you have any questions or anything else, I am jernsvill in Twitter. And thank you so much for your time, appreciate it.