 Yeah, sure. So hi, everyone. Thank you for coming. This session is on amendment because the previous speaker is unable to come to attend FOSDEM. She sent her notice, but unfortunately, she won't be here. The session would have been bridge the physical words, Kotlin native on Raspberry Pi. But instead, it will be from Swagger to Kotlin via Gradle. If you leave the room, please pay attention to the chair because it's really noisy. And yeah, let's get it started. So my name is Nicola Corti. I work as an Android infrastructure engineer. That means that I basically work on libraries, framework, tools for other Android engineers. I mostly develop in Kotlin when possible, but I also have to deal a lot with Java. I probably know me that I'm more like a dog person rather than a cat person. And why this is important? This is important because I don't have a dog at the moment. I actually would love to get one at a certain point. I'm actually really in love with corgis. So I thought that maybe you can help me get one pet, actually, a corgi. So what happens next is that, yeah, I could actually go to the pet store, a pet store.swagger.io. And then they tell me that I can't just call get slash pet slash corgi because that's not valid. So today we're going to talk about Swagger and OpenAPI. So Swagger and OpenAPI are both tools to define in a machine and human-readable way the APIs for your backend services. So there is a little bit of confusion between OpenAPI and Swagger. If you go on the website, they will tell you that OpenAPI is actually the specification, while Swagger is all the tooling around it. In the community, it's more like connected to the fact that OpenAPI is related to the OpenAPI specification version three, while Swagger is whatever is related to the specification version two. So today we're going to mostly focus on Swagger. That means version two. What's the cool part of this? If you don't know Swagger, quick question. How many here are actually working or have projects that have Swagger APIs? Not everyone. So the cool part of this is that this is actually a tool to define your APIs with just a JSON or a YAML file, like one or more. And the cool part is that it's actually, as I said before, machine-readable so you can build infrastructure around it and tools. So let's make an example. And the example I'm going to make is actually the Pet Store. The Pet Store is the equivalent of hello, word, but for the API. So it's like a minimal set of endpoints that represents the basically feature set of this API specification tool. So we start with a YAML file. We define a version. As I said, we're going to work with Swagger two. And we have an info block. So inside the info block, it's like a little preamble where you can specify what this Swagger file is going to be about, so in this case, a description. The version of this spec file, so 1-0-0, in this case, a title, Swagger Pet Store. You can provide further information like a contact email or a license. Then you can define an host. In this case, we are going to be reachable a Pet Store Swagger I.O., a base path. Like you could have a slash v2 as a base path for all of your endpoints. And the supported schemes, like HTTP or HTTPS. That's all part of the introductory part of the spec. But let's go further, and let's actually define how our spec will look like. So usually within the spec, you will have to define two set of things, endpoints and models, like objects. So let's start with the definitions. Here you define your models. And we start by defining what is a pet. We can say that a pet is actually an object and has a set of properties. Specifically, an ID. And we can say there is a type integer, format int 64. And the name, there is a string. And define our reality. Obviously, also complex types are supported. For example, I could have a photo URLs. There is actually an array. And the items of the array are of type string. So I will receive like a list of URLs. I can specify which properties are required to make these definitions meaningful. In this case, I could say that name and photo URLs are actually required. So they should be there. I can have even more complex types. For example, a status. And if I don't want the status to just be a string, I could say I could provide a description. And I could say that this is actually an enum. So I could restrict the set of possible values to available and sold only. And the real power of Swagger is that I could actually define more than one model. So I could say that a pet has also a category. But a category is a reference to another definition. Like in this case, let's zoom back. Category is, again, an object. As some properties, again, an ID of type integer, format in 64, and a name of type string. So this is like a basic definition of two models. But let's go to the core part of the spec. Like, we would love to have some endpoints. So we go back to our YAML file at the top level. We define a paths property. And we begin enumerating our endpoints. So the first one is path, pet ID. Sorry, pet ID. And we can say that on this endpoint, we support the get operation. And we need to provide summary and description. Like, find a path by ID. And what it does, it returns a single path. In this context, it's also really useful to provide an operation ID. An operation ID is a string representation of this combination of endpoint and HTTP verb. So in this case, we will write get path by ID. And it's also helpful because it's just characters. There are no crazy symbols and slashes in between. We will see why we need it. And here, we define what our endpoint is doing. So for example, it's returning an application JSON. And it has some parameters. Like, one, there's pet ID. And is inside the path. It's actually the one that is between curly braces. And we can provide description. Like, all those descriptions are actually optional. You don't need to provide all of them. But obviously, if you provide it, it will have better specs, easier to maintain. And we can say it is actually required. Like, you need to provide that parameter. And specify the type. Integer and the format int64. So the last thing that we need to define here is actually what this endpoint will produce. So we have the responses block. So we can say that for 200, so for the successful response, we are gonna produce, so the description is successful operation. And for 404, the description is not found because there is no pet in our database whatsoever. We still haven't connected this endpoint with the definition that we provided before. So inside the 200, we can also provide a schema. And this will mean that the body will have this schema that we provide now, definitions, pet. So this is basically how we connect this endpoint to the object we just defined. So as I said before, the power of Swagger is that it comes with some tools that are really helpful. First of all, Swagger UI. It's basically sort of like a web server that shows you a web representation of your spec. And you can actually navigate through your endpoints and see the description of every endpoint. And also really useful, the Swagger Editor. This is really similar to the Swagger UI. There is the one on the right, but on the left you can actually see the spec file and edit them and see in real time how things are changing. So out of these, we actually discovered that we can't call get pet corgi because that parameter should be of type int. So we'd rather call get pet 42 or something like that. So as I said, Swagger comes with a lot of tools. And one tool that is also available is Swagger Codion. And that is the one we're gonna talk about today. So Swagger Codion is, yeah, again, open source, is available on GitHub. And it's basically a tool that allows to generate code out of your Swagger spec files. It's available on Swagger dash API slash Swagger Codion on GitHub. It's actually really active over there, so I really invite you to take a look. To give you super fast introduction to the project, it's basically composed by two parts. There is the generator code. So the code that is responsible of reading the spec file, like analyzing it. And then there are a set of templates file that will be populated with the value that are parsed by the generator. So there are actually a lot of templates that are already available online. You can use them as an inspiration. You can start from that, but it might not fit your needs. And also, Swagger Codion comes by default as a common line tool. So ideally you should call it like Java dash jar and the jar of Swagger Codion and then pass everything in. There are some plugins to plug it in some build system. But as an Android developer, I don't find it really, like it doesn't really fit my workflow. And then this is like why we will like, we ended up developing something different. This is the list of templates that are already available. There are templates for server, like you can generate your service stops, but there are also a lot of templates for clients. So yeah, Go, Java, Rust, whatsoever. There is actually Kotlin also, but the Java one, there are multiples. Specifically, there is OK HTTP, Retrofit 1x and Retrofit 2x, but there is nothing for Kotlin. Like there's just plain Kotlin. I don't know if that got updated recently, but yeah, that might not fit what is your actual stack. And this is how like a template looks like. It's actually a moustache file. So if you're not used to that, it's something like this. So you have like a lot of tags and these tags would be populated by property and you have some really limited computational logic. So for example, here, we are saying like if, like the tag with a hashtag, means if there is a description, print those characters, like slash asterisk asterisk, this is Java doc, and then print the description and then close this context. So it's like, it's not really handy to work with those template files. You might have to do some tricks. And that's why I ended up developing this tool called Swagger Gradle Codion. So it's open source. It's on Apache 2 license. It's available on GitHub. So I developed these as part of, like when I was in my former company, so you will find it on the Yelp org. But I'm actually, I'm not working there anymore, but I'm still like heavily contributing over there. And I find the project really interesting. So yeah, that's the reason why he's there. And what is actually Swagger Gradle Codion is actually a Gradle plugin that fits a bit better inside a classical, like Android or Kotlin library build system. And as some feature is actually input output aware. That means that the Gradle plugin is able to understand if it changes your spec and will rebuild stuff if needed or not, while a common line interface will just redo all the building every time. As a simpler API for the developer. So Swagger Codion, the original Swagger Codion is extremely powerful, but has a lot of properties. And the majority, a lot of them are actually not needed for Android engineers. So I sort of like hide a lot of them under like a simpler API to use. So the idea is just like plug and play, plug this plugin and you will be ready with your code in a couple of minutes. And the second important thing is that this tool is opinionated. Like this tool is built around the one that I consider probably the most common Android developer stack. There is Kotlin, Rx, Java 2 or Curtins, Retrofit, Moshi. So Retrofit for rest abstraction, Moshi for JSON parsing, and Treaty in ABP for dates. This might not fit your needs. Like if you don't use Moshi, this tool will not work for you. But nowadays I think this is like the most popular Android libraries out there. So the templates inside the project will use this. So let's go back to our Swagger's pack, this one, Pet and Category. And let's see what the generated code will look like more or less. So category. So yeah, obviously this will be represented by a class. We are in Kotlin so why not using a data class? It comes with a lot of handy functions out of the box. And there will be two properties, ID and name. From the format we can like infer the type. So it will be a ID of type long, name of type string. There are both optional. They are not required so we can mark the type as optional and we can actually initialize them as null. So obviously as I said, everything works with Moshi. So classes will be annotated with JSON so that the parser is more resilient and knows where to put everything. And this is basically how your class will look like. If you are a good developer and you have descriptions in your Swagger file as I suggested before, you will also have it populated in your K-Doc annotations. That is really, really handy because when you check the commentations and you have all those classes, you immediately see what those property are doing directly from your Swagger's packs. Let's go on the more complex one, like Pet. Again, a data class. Everything already annotated. There are a couple of things to notice here. So for example, the name was required so we can set the type as non-nullable string. And we don't need to, we can't initialize it to null so you need to provide a name. You can't create this class otherwise. The photo URLs. In the Swagger's pack we mentioned that it's an array and on Kotlin we convert it to a list because it's easier to deal with. And again, we have a category. So the generator is correctly linking this property called category to the class that we previously defined. And again, we have an enum. This enum is generated as an inline, sorry, as an inner enum. And yeah, it's available there and again everything is annotated. And again, provide documentation strings. It would be helpful for you. Like you will have it there. Then let's go to the end points. So get Pet, Pet, Pet ID. So as I said, we generate retrofit interfaces. So there will be the full TPI with a function called getPet by ID. This is where the operation ID comes handy because we need a unique name to identify this operation and we get it from the spec. And then we provide all the parameters. So in this case, there is only one. It's called Per ID is long and is annotated with the retrofit to annotation at path. So this will end up in the path. And again, also we have to annotate the function with our at get annotation and the property URL. There's one thing that is missing here is the return type. This is where the Rx Java 2 wiring happens. So in this case, if you use the Rx Java 2 template, this will generate a normal function that returns a single of a path. If you instead switch to use coroutines, this will generate a suspending function that returns just the path. And if you use retrofit 2.7, I think, it will work correctly. So you will have like the asynchronous pattern that you prefer. There is a header called xOperationID. This is like a header that we wanted to add on every request and is basically a way to pass over the operation ID. But you can change it if you want, just like add the template. And then again, you will add the documentation of your endpoint over there if you provide it. And this is basically how the final class will look like with all the imports, the package, and it really will compile. So how will you use this plugin? There are some used cases, like it's a Gradle plugin, so you can plug it to whatever is a Gradle module, basically. If you have just an app module, like you don't do modularization at all, you have a super small app, you can just plug it there and specify where you want your generated code to end up, and that will work. But if you have modularization, maybe you want to have a pure Kotlin module that contains this code, or an Android library project that contains, again, the code, all the modules and the API. And if you are in a bigger org, or you want a more structured approach, what I really suggest is to integrate these within your CI system. So let's see how you can configure the plugin and now you can integrate it in your CI. So you define the class path dependency for the plugin, Comeyal Cogen plugin, the latest version is 130, and then you need to provide this generate swagger block, and over there, all the properties that are needed for the generation. So specifically, there is only one required property that you need to provide, and it's the swagger spec file, like this plugin is not a wizard, like if you don't provide a spec file, nothing will actually work. So then the output directory, and other properties like which platform you want to use, the package name, and other stuff. So this plugin will basically do just one thing to your build system, will offer you one extra task that you need to call, we not do auto magic. This task is called generate swagger, and the fact that we don't modify the build system is actually intentional. We leave these, like, my idea was to leave this duty to the developer, like it's up to you to decide if you want to hook everything within your normal build and rebuild every time or not. So what you can do, you can say for example, pre-build depends on, and you get this generate swagger task. In that case, what will happen is that there is this, this is like a random assemble build, and you have this pre-build grill task, where you can hook everything there, that needs to be executed before the build starts. So you could say like, okay, before building, just call this generate swagger, generate all the code, and then actually build my app. And now let's see how you can actually generate your code inside a CI, and I have like a sort of a small pipeline to generate your code, and what are the benefits. So I assume you have your swagger specified somewhere, ideally in a Git repo or somewhere else, you'd need to have some sort of a webbook mechanism to trigger a CI build. So you will invoke your Jenkins, Trevis, GitLab CI whatsoever tool you want, and ideally you need to have like a skeleton project. You can take one that is inside the repo in the samples folder, or you can craft your own. So what's the idea behind this skeleton project? This skeleton project will, like your CI will be responsible of fetching the updated spec file inside this skeleton project, calling generate swagger, like calling cradle generate swagger, so all the code will be generated. Then you can actually run tests, like the power of this is that you can have integration tests that test your generated code against like a mocked environment or some environment that runs your swagger spec implementation. So like you test that what you generated is actually working. Once the tests are green, you call assemble, so you have like an archive, and yeah, so you have like basically a AAR or a jar based on what you want to build. And then once that is ready, you just call publish. And that it's on you if you want to put it like on a private Maven repository or on something public. Like if you're maintaining public APIs, like I don't know APIs for weather services whatsoever, you could actually have a pipeline that generates like an Android SDK implementation of that that it's rebuilt. Every time that you change the swagger spec. So at the end of the day, who is consuming those generated code will end up having something like this, like implementation, com, corgi, samples, generated API and the version. And the power of this is first that you have versioning, like you have a strict versioning system to go back in the history and knowing which version of the generated code is what. Like this swagger spec file generated this R and those are the files there inside. So you can actually go back in time. And yeah, basically the power is that you have this bundle with all of your retrofit APIs and the data classes. So and again, the fact that you consume this as a third party in library basically is that it's read only. So if you are in a bigger org or you are in a bigger project and you want to enforce that those files are like the same, they don't change. Like people can't actually touch them. This is like a great way to enforce that your network model and your network interfaces are actually one by one with the swagger spec file. So yeah, that's all. I want to spend a couple of minutes actually talking about challenges and future like a little bit of roadmap, like what's coming next. So challenges, when generating code you have to shift a little bit your perspective. I actually invite you to read one blog post from Jake Wharton that is called changing the mindset when doing code generation. But if you search Jake Wharton code generation you will find it is actually really interesting. And there are some scenarios or problems that arise only when you're actually generating code, not when you're writing it normally. The first one, this is actually not only for code generation but in code generation it's really dangerous. It's breaking changes like, or changes that are actually breaking the implementation of your app. Let's see an example. Let's say you have a get path by a D endpoint with two strings, name and surname, okay. And then for some reason, like you change something in, I don't know, your Zvagas spec file or the implementation of the generator. And you happen to invert the order of those two parameters. What we'll happen is that this code is both binary answers compatible on the user side. So people will just bump the library we'll get out of code. And on the code side is just get path by D string, comma string. So nothing will happen. But actually you're passing the name as a surname and vice versa. And this could be problematic if instead of having name and surname you actually have username and password. So that is a problem. And what I suggest for scenarios like these is actually having like static analysis tools Kotlin has a great feature called name parameters that prevents this kind of situation. So you could say like get path by D, surname equal whatever expression variable that represents the surname and name equal. And that will protect you against this kind of changes. So just like a detect rule that detects whenever you use a generated code and then like raise a warning if you're not using name parameters. Another problem is defining names. So in Swagger you can actually define models in line like you can have models inside models, inside other models. And those models don't have a name. It's like an anonymous in a class in Java. It's like anonymous. So but the generator needs to generate classes for that and needs a name. And you might end up with classes that are like ID to session info for customized result map to user UI interaction map. So it's not cool. Like if you use import as like if you have big names you can save yourself using import name of the class as network model and you sort of save yourself. But this is still a class. And you will find it when you like type in your auto-competition. So pay attention to make sure that every model has a proper name. And then accessing the raw response. Like what happens if you want to access a response header? Like how would you do that? Like in red feet what you need to do is wrap the response type inside our result or our response object. But this is coming from a template. Like if I change it for one endpoint I would change it for all the endpoints. And if I have like I don't know 1,000 endpoints yeah that's going to be complicated. So this is still an open challenge. Ideally one thing could be to like this is unsolved sort of. Ideally one idea could be to see if in the swagger spec you have a response header and if it's defined there then change like offer to only for that endpoint access the raw response. And yeah those are like some challenges that I faced. And then like I have here the guy over there with the red t-shirt there is another top contributor of this project and I wanted to discuss a little bit like what's coming next? Like what are the challenges? What are we working on? Yeah so January 21st this year so like couple of days ago we just released version 130. And that offer support for Kotlin Kotlin's that was actually requested a lot. Like I had a draft PR for Kotlin's and a lot of people wrote like hey I need this now like please ship it. And yeah we just didn't want it to like mess up with the project so we had to like do a little bit of refactoring but now it's live so you can use it. So there will be a version 14 coming soon like months probably I don't know. Yeah there will be support for Moshi Kojen. So right now this project is using Moshi Kotlin. They uses the Kotlin JSON Adapter Factory that inside uses Kotlin Reflect. So uses Reflection it's really heavy for the upsize and it's really heavy at runtime like creating like parsing stuff around. So there will be Moshi Kojen support. It will be like it will not be a breaking change but at a certain point like there will be a true X version of some time this year ideally. And we want to drop support for Moshi Kotlin. Like we want to have everything on Moshi Kojen because it's just better like we prefer this approach. Then another important thing there is a hot topic is models inheritance. So what happens if you have a model like Swagger allows you to say that you have a pet as a model and you have a cat and a dog as a model. So and you have like a discriminator field that comes through the wire so you will have like type and if it's a dog there will be the properties of a dog and if it's a cat there will be the properties of a cat. Yeah so in our case we decided to use data classes that don't play well with inheritance. So yeah we are working on a solution like specifically somewhere is working on that. It's working on a solution to have like a class year key with higher classes there are not data classes and lower classes there are actually like the son like the leaf of these three are actually data classes. These will come we are still discussing on implementation. We are actually more than welcome because a lot of the discussion happens online like on pull requests yeah and we are looking for contributors and that's all. Thank you very much and I'm happy to get questions. Thank you.