Building URL Shortening Service frontend - P4
In this blog, we are going to learn to build a form using Kotlin.HTML to frontend and using the existing APIs.
This is the last part of the series(an optional one). In this one, you are going to build a basic form using HTML using Kotlin.HTML template engine.
This is going to be a very rudimentary blog of building a frontend without any style (like CSS). It would be a very basic HTML form.
In this blog, you are going to learn,
- Setting up Kotlin.HTML in the project.
- Setting up the project
- Building an HTML form using Kotlin.HTML.
- Submitting the form to a dedicated API route.
- Final Steps
Setting up Kotlin.HTML in the project.
To integrate Kotlin.HTML in your project, add the following dependency to your build.gradle.kts
like,
implementation("io.ktor:ktor-html-builder:$ktor_version")
This will help you to use HTML in a DSL way in the project.
Setting up the project
You have already built, the url
feature in the project. For this, create a new package called frontend
,
features -> frontend -> views
and in that, you are going to have views
and a file called FrontendRouting
.
Basically, you are going to build one new route to submit the data using the HTML form, and using that route itself, you will fetch the response as well.
Here, let us add another route in the UrlEntity
as,
const val FORM_URL = "/v1/form"
And using this URL, create another Location known as FormUrlLocation
which looks like,
@KtorExperimentalLocationsAPI
@Location(UrlEntity.FORM_URL)
class FormUrlLocation
You don't need to create any other use case for this as you are going to use CreateShortUrlUseCase
to create your short URL.
Create two files LandingPage
and ResponsePage
in the views
folder. Here, LandingPage
will have the HTML form and ResponsePage
will show the shortened URL using HTML.
Building an HTML form using Kotlin.HTML
Firstly, create an Application's extension function landingPage
and inside this, you will have a routing
function like,
fun Application.landingPage() {
routing {
}
}
You will create your Kotlin.HTML form inside the routing function with a GET call and a route like,
routing {
get("/") {
//the HTML form will be rendered here
}
}
The above block of code means, that the default page of the base URL will open this form. For Eg. https://himashoe.com/
will open the form.
Now, let us render the form. For this, use call.respondHtml
like,
call.respondHtml {
head {
title {
+"Welcome to URL Shortener"
}
}
body {
form(
action = UrlEntity.FORM_URL,
method = FormMethod.post,
) {
label {
input(
type = InputType.url,
name = "url",
) {
placeholder = "Enter your url"
required = true
}
}
button(
classes = "primary",
type = ButtonType.submit,
) {
+"Shorten"
}
}
}
}
Here, inside the block, you have head
and inside that, you have title
which is responsible for adding that title "Welcome to URL Shortener" to the Browser tab-like
Then you have the body
function, which renders a form
with an input
field and a button.
The form
takes action
and method
as parameters where action represents the endpoint the data has to be submitted and method means the HTTP method which in your case is UrlEntity.FORM_URL and POST respectively.
In the input field, you have the type of data you need, i.e URL
. You can also have other options like Number, date, etc. and other is name
which is set to "url". The value of this form will be set like,
url: " the input data"
And, at last, you have a placeholder
which means what to show if the form is empty
and required
which means it's mandatory to have data there before pressing the button.
With that being said, you have Button
with type = ButtonType.submit
and text on Button is Shorten
.
The form looks like,
Submitting the form to a dedicated API route
Now, create an Application's extension function responsePage
with parameters DomainProvider
and ExceptionProvider
like,
fun Application.responsePage(domainProvider: DomainProvider, exceptionProvider: ExceptionProvider) {
routing {
}
}
Inside routing, use the FormUrlLocation
to create a POST
request and inside that render the HTML based on the response. This FormUrlLocation
acts as the API you used in the above step to submit the form.
Hence, you will receive the url
in this POST request.
Using the location the POST request looks like,
routing {
post<FormUrlLocation> {
}
}
Inside this, you have to receive the url
parameter which you are passing from the HTML form.
To receive the parameters in the route, use:
val params = call.receiveParameters()
and using this you can get the url
params like:
val params = call.receiveParameters()
val url = params["url"] ?: ""
Here, url
variable holds the url
parameter coming from the form.
Now, you need to do nothing new. You will do what you did early by first validating and then passing it to the use case.
Now, the complete code of the POST request using FormUrlLocation
looks like:
post<FormUrlLocation> {
val params = call.receiveParameters()
val url = params["url"] ?: ""
if (isValid(url)) {
val response =
domainProvider.provideCreateShortUrlUseCase().invoke(url)
call.respondHtml {
body {
p {
if (response is SuccessResponse) {
+"Short url is: /${response.data}"
}
}
}
}
} else {
call.respond(
HttpStatusCode.BadRequest,
exceptionProvider.respondWithGenericException("Url is not valid!")
)
}
}
Here, if you see first you are validating the url
. If the URL is valid then pass it to the CreateShortUrlUseCase
using the domainProvider
.
If the response is successful, then render it in HTML using call.respondHtml
and print it in Paragraph.
The response on the browser looks like, if you pass the https://himanshoe.com/series/short-url-service
URL in the form,
Final steps
As the final steps, register both the routes in FrontendRouting
file, like:
fun Application.frontendRouting(domainLocator: DomainProvider, provideExceptionProvider: ExceptionProvider) {
routing {
landingPage()
responsePage(domainLocator, provideExceptionProvider)
}
}
and finally register the frontendRouting
in the configureRouting
function like:
fun Application.configureRouting() {
install(Locations)
routing {
frontendRouting(domainLocator.provideDomainProvider(), exceptionLocator.provideExceptionProvider())
urlRoutes(domainLocator.provideDomainProvider(), exceptionLocator.provideExceptionProvider())
}
}
Here, now in configureRouting
you can see that both of your routes for URL and frontend are registered.
Rest all the things remain the same in the project.
This is all about building your own URL Shortening Service using Ktor. This is just a sample to showcase how to use the template engine in Ktor.
If you like the series, do share it with people :)
Check the code here.
Thank you for reading :) Hope you learned something from my experience.
If you have anything more to discuss, I will be happy to get connected at hi_man_shoe.