Showing posts with label Laman. Show all posts
Showing posts with label Laman. Show all posts

Saturday, September 8, 2018

Akses request/response body pada Filter

Berkenaan dengan bahasan pada topik filter disini, kita melakukan logging pada request GET dan semua berjalan dengan lancar. Namun lain cerita ketika melakukannya pada metode lain yang memiliki body.
Request POST dengan body

Jika kita kirimkan request tersebut ke endpoint, maka akan mendapatkan pesan error sebagai response.
Log error pada terminal

Mengapa hal tersebut terjadi ? Mari kita telaah.

[Kenapa]
Pada gambar log error diatas, spring melakukan throw error IllegalStateException dengan pesan "getReader() has already been called for this request". Pengeluaran error tersebut terjadi ketika handler akan melakukan proses tertentu.
Jika dilihat kembali pada log error, terdapat pemanggilan getInputStream(). Berdasarkan dokumentasi, ketika suatu method telah melakukan pemanggilan method getReader() maka tidak dapat melakukan pemanggilan getInputStream() [dapat diakses disini]. Pada implementasi filter yang dicontohkan, terdapat pemanggilan getReader() untuk kebutuhan logging.
Pemanggilan InputStream pada log

Lalu bagai mana cara untuk mengatasi hal tersebut ? Ada beberapa cara tentunya. Namun dalam tulisan ini, hanya akan dibahas dengan menggunakan objek pembungkus pada request dan response.

[Request/Response Wrapper]
Kenapa kita menggunakan wrapper ? wrapper berfungsi untuk melakukan adaptasi fungsionalitas objek terhadap kebutuhan. Untuk mengimplementasikan wrapper pada kasus diatas, terlebih dahulu kita membuat sebuah kelas yang mengekstensi HttpServletRequestWrapper untuk request atau HttpServletResponseWrapper untuk response.
Implementasi wrapper pada request

NostraRequestWrapper merupakan inner class yang akan membuat request beradaptasi terhadap kasus. Kita dapat melakukan overriding method sehingga sesuai dengan kebutuhan.
Jika dilihat pada konstruktor kelas, NostraRequestWrapper melakukan penyimpanan informasi dari request pada field dengan menggunakan getReader() beserta mendefinisikan getter untuk field tersebut. Kemudian kita melakukan overriding method getInputStream() sehingga filter lain atau endpoint akan memanggil method getInputStream() hasil adaptasi. Pada contoh ini, kita hanya membuat sebuah input stream baru berdasarkan informasi yang sebelumnya disimpan dalam field.
Untuk menggunakan wrapper tersebut, kita membuat sebuah objek dengan argumen request, kemudian melempar objek wrapper, dan bukan request original, ke chain doFilter().
Penggunaan wrapper

Ketika dicoba, proses tidak mengalami masalah yang serupa.
Proses request aman dan terkendali

Prinsip yang sama juga digunakan pada response.

[Kesimpulan]
Dalam proses logging, kita tidak dapat melakukan akses data begitu saja pada filter. Perlu melakukan proses terlebih dahulu sehingga informasi pada request tersebut dapat diakses oleh filter berikutnya atau endpoint. Wrapper HttpServlet dapat digunakan untuk melakukan proses tersebut dengan proses overriding pada method yang diperlukan.

Happy Learning, Happy Programming, Happy Sharing
- Laman -

Resource
[1] HttpServletRequestWrapper API. Dapat diakses di https://docs.oracle.com/javaee/1.3/api/javax/servlet/ServletRequestWrapper.html
[2] BufferedReader API. Dapat diakses di https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html

Friday, September 7, 2018

Filtering Servlet dalam Spring Boot

[Filter]
Apa itu filter ?. Filter merupakan sebuah objek yang melakukan intercepting pada request sebelum akses ke resource dan sebaliknya. Pada proses intercepting tersebut dapat dilakukan proses terhadap request/response sehingga disesuaikan terhadap bisnis.
Pernah nonton ke bioskop ? tentu terdapat seorang staff yang melakukan validasi tiket kita dan kemudian menandainya sebelum diperbolehkan masuk ke dalam studio. Kita dapat ibaratkan staff tersebut sebuah filter yang melakukan intercepting. Staff tersebut sebagai filter didefinisikan untuk melakukan pencegatan terhadap penonton (objek) dan melakukan proses yaitu validasi dan modifikasi tiket.
Skema Filter


Pada gambar skema filter, posisi filter berada diantara client dan endpoint. Posisi ini digunakan filter untuk melakukan pencegatan request sebelum menuju endpoint yang dalam spring merupakan dispatcherServlet dan response sebelum dikirimkan ke client.


[Kenapa Filter]
Ada beberapa alasan penggunaan filter yang pada intinya memudahkan kita dalam membuat dan melakukan pemeliharan
Karena filter merupakan komponen yang dapat dengan mudah dilepas atau pasang sesuai dengan kebutuhan bisnis. Kita dapat membuat berbagai filter dengan berbagai macam fungsionalitas dan memasang atau melepasnya dengan mudah.
Dengan menggunakan filter, memudahkan kita untuk melakukan proses yang bersifat general tanpa harus mengubah source code file yang banyak.
Selain itu, filter sangat bersifat decouple terhadap resource.

[Use Case Filter]
Pada umumnya filter digunakan untuk melakukan logging pada request yang diterima dan response yang akan dikirimkan oleh server. Namun beberapa contoh penggunaan lain dari filter di antaranya adalah :
> Konversi request dan/atau response sesuai kebutuhan bisnis
> Modifikasi request dan/atau response sesuai kebutuhan bisnis
> Pengamanan data dengan enkripsi dan dekripsi
> Validasi request yang masuk secara general
Perlu diketahui juga bahwa infrastruktur dari spring web security menggunakan filter dalam melakukan pencegatan terhadap request yang masuk dan dilakukan proses autentikasi dan autorisasi kemudian memberikan response tergantung hasil proses proses tersebut.

[Implementasi Filter]
Sebagai engineer, tentu harus memberikan hasil sebagai bukti konkrit. Maka dari itu, subbab ini akan dijelaskan bagaimana cara untuk mengimplementasikan filter dan menunjukan hasil penggunaan filter, pada spring tentunya.
Secara garis besar, hanya dua langkah saja untuk mengimplementasikan filter. Langkah pertama adalah membuat filter itu sendiri dan yang kedua melakukan registrasi filter sehingga dapat terbaca dan berjalan pada spring.
Demi kebutuhan contoh, mari kita siapkan sesuatu sederhana. Katakanlah kita ingin melakukan logging setiap request yang diterima. Kemudian, kita ingin menambahkan header untuk setiap response yang akan dikirimkan.



First Step : Definisi Filter

a) Membuat kelas yang mengimpementasi Filter Servlet
Kelas Filter
Interface Filter memiliki 3 metode, yaitu init(), doFilter() dan destroy().
> init()
metode ini akan dipanggil pertama kali sebelum proses filter dapat digunakan. Terdapat FilterConfig berisikan informasi untuk filter pada saat proses inisialisasi seperti parameter.
> doFilter()
metode ini yang akan mendefinisikan proses yang akan dilakukan ketika request dan response dilakukan pencegatan.
metode ini menerima request dengan objek ServletReqest dan mengirimkan response dengan objek ServletResponse kemudian FilterChain yang memungkinkan filter untuk melemparkan request/response ke entity filter lain atau resource.
> destroy()
metode ini untuk membebaskan penggunaan sumber daya dengan catatan proses filter tidak akan berjalan kembali.

b) Mendefinisikan proses pada doFilter()
Karena kita ingin melakukan logging dan modifikasi header response, kita harus mendefinisikan proses tersebut pada metode doFilter().
Implementasi Proses pada Filter

Terkait contoh kasus yang sebelumnya didefinisikan, dalam filter kita melakukan logging atas request dan melakukan modifikasi header response. Kita dapat melakukan casting Servlet menjadi HttpServlet sehingga dapat mengakses metode yang diperlukan seperti mengambil informasi url atau set header untuk response.

Step Two: Registrasi Filter
Sebuah komponen filter, tidak akan dijalankan sebelum dilakukan registrasi. Terdapat beberapa cara untuk melakukan registrasi, diantaranya adalah :
> web.xml
> @WebFilter
> @Component
> FilterRegistrationBean
Pada kesempatan ini, kita menggunakan FilterRegistrationBean seperti pada gambar.
Registrasi Filter

[Hasil]
Berikut hasil logging dan modifikasi header yang telah dilakukan dengan menggunakan filter.
Hasil Proses Filter

Berdasarkan proses yang didefinisikan, terdapat log dengan empat tag :[REQUEST] -> logging informasi request seperti method (GET), url (http://localhost:8080/ping), body null
[RESPONSE] -> logging informasi response sebelum modifikasi header
[MODIFYING] -> melakukan proses modifikasi header
[MODIFIED RESPONSE] -> hasil response setelah dilakukan modifikasi
Hasil Pada Postman

Berikut hasil yang didapatkan dari postman. Terdapat header yang telah set pada filter.

[Kesimpulan]
Dapat disimpulkan dengan filter kita dapat mendefinisikan sebuah proses sebelum request tersebut masuk ke dalam servlet dan sebelum response tersebut ditransmisikan ke client. Penggunaan filter juga mudah dengan kemampuan yang beragam dan powerfull. Filter juga sangat plugable, kita dapat melepas atau memasang filter dengan konfigurasi yang sederhana.

Happy Learning, Happy Programming, Happy Sharing
- Laman -

Resource
- [1] API Java. Dapat diakses dari https://docs.oracle.com/javaee/6/api/overview-summary.html
- [2] Filter Servlet. Dapat diakses dari https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/Filter.html
- [3] The Essestials of Filter. Dapat diakses dari https://www.oracle.com/technetwork/java/filters-137243.html
- [4] Servlet Filter. Dapat diakses https://www.javatpoint.com/servlet-filter