Java Spring Boot REST API

Merhaba, bu yazıda Spring Boot ile basit bir Rest Api oluşturacağız. Daha sonra oluşturduğumuz servisi Postman ile test edeceğiz. Hali hazırda java ve spring boot ortamının kurulu olduğunu varsayarak devam edeceğim. İlk olarak, Spring initializr kullanarak ya da VSCode kullanıyorsanız Spring initializr eklentisini kullanarak bir spring boot projesi oluşturalım.(Ben VSCode eklentisini kullanmayı tercih ediyorum. Bu şekilde çok daha pratik bir şekilde spring boot projesi oluşturabilirsiniz.) Aşağıda proje ayrıntılarını görebilirsiniz:

Şimdi kodlamaya geçebiliriz. Benim proje dizinim aşağıdaki gibi, siz de classları bu şekilde oluşturabilirsiniz:

Rest Api den client lara sunacağımız veriyi bir veritabanından almak yerine asset olarak eklediğimiz bir .json dosyasından okuyacağız. Kullanacağımız json dosyasının formatına göre bir model sınıfı oluşturacağız. Json formatımız şu şekilde:

Bu formata göre oluşturduğumuz Country sınıfı ise aşağıdaki şekilde olacak:

package com.example.countries;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Country{
  private String id;
  private String name;
  private String nativeName;
  private int phoneCode;
  private String continent;
  private String capital;
  private String currency;
  private List<String> languages;
  private List<Byte> flag;
}

Şimdi assets içerisindeki .json dosyasını ve flags klasöründeki ülke bayraklarını dosya okuma işlemleri ile okuyalım ve Country nesnelerimizi oluşturalım. Her bir ülke için oluşan nesneleri bir listeye atalım ve api tarafından kullanılmak üzere geri döndürelim.

package com.example.countries;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.IntStream;

public class CountryInitializer {

  static CountryInitializer countryInitializer = new CountryInitializer();

  public List<Country> initializeCountries(){
    String root = System.getProperty("user.dir");
    System.out.println(root);
    List<Country> countries = new ArrayList<>();
    try {
      //parse json to country models and add them to list
      File jsonFile = new File(root+"/asset/countries.json");
      HashMap result =
      new ObjectMapper().readValue(jsonFile, HashMap.class);
      //Stream for flag data
      InputStream in = null;
      //all country codes.
      Set keySet = result.keySet();
      for (Object id : keySet) {
        Map<String, Object> m = (Map<String, Object>) result.get(id.toString());
        String name = m.get("name").toString();
        String nativeName = m.get("native").toString();
        int phone = Integer.parseInt(m.get("phone").toString());    
        String continent = m.get("continent").toString();
        String capital = m.get("capital").toString();
        String currency = m.get("currency").toString();
        List<String> languages = (List<String>) m.get("languages");
        in = new BufferedInputStream(new FileInputStream(root+"/asset/country_flags/" + id.toString().toLowerCase(Locale.ENGLISH) + ".svg"));
        Country c = new Country(id.toString(), name, nativeName, phone, continent, capital, currency, languages, toList(in.readAllBytes()));
        countries.add(c);
      }
      in.close();
      Collections.sort(countries);
    }
    catch(Exception e){}
    return countries;
  }

  private List<Byte> toList(byte [] bytesArr){
    Byte[] b = IntStream.range(0, bytesArr.length)
    .mapToObj(i -> bytesArr[i])
    .toArray(Byte[]::new);
    return Arrays.asList(b);
  }
}

Yukarıdaki kod parçasıyla localden okuduğumuz json datasını map e çevirdik ve keySet() metodu ile bütün id leri bir Set içerisine attık. Daha sonra döngü ile Country nesneleri üreterek listeye ekledik. Sonrasında bir InputStream oluşturduk, bu stream ile ülkelerin bayrak görsellerini byte listesi olarak server a göndereceğimiz json a gömeceğiz. Byte Array’ini Byte listesine çevirmek için ise toList( ) isimli bir metod yazdık.

Şimdi Controller tarafını kodlayalım,

package com.example.countries;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CountryController {

    //İlk olarak istemci(client) lere göndereceğimiz ülke listesini init edelim:
    List<Country> countries;

    public CountryController(){
        countries = CountryInitializer.countryInitializer.initializeCountries();
    }

    //localhost:8080/countries 'e istek atıldığında çalışması gereken metodu yazalım.
    @GetMapping("countries")
 public List<Country> countries(){
        return countries;
    }

    //id ile istenen tek bir ülkenin istemciye iletilmesi için gerekli metodu yazalım.
    //Örnek : localhost:8080/countries/TR
    @GetMapping("countries/{id}")
    public Country country(@PathVariable String id){
        return countries.stream().filter(f -> f.getId().equals(id)).findFirst().orElse(null);
    }

    //continent, currency, phoneCode parametrelerine göre filtreleme işlemi yapan metodu yazalım.
    //Aynı zamanda ülke telefon kodlarına göre sıralama yapabilecek.
    //Örnek = localhost:8080/countries/params?continent=AS --> sadece asya kıtasındaki ülkeler gelecektir.
    @GetMapping("countries/params")
    public List<Country> countriesByParams(@RequestParam(value = "continent", defaultValue = "") String continent,
                                           @RequestParam(value = "currency", defaultValue = "") String currency,
                                           @RequestParam(value = "phoneCode", defaultValue = "") String phoneCode,
                                           @RequestParam(value = "order", defaultValue = "") String orderBy){
        List<Country> queriedCountries = continent.isEmpty() ? countries : countries.stream().filter(f->f.getContinent().equals(continent)).collect(Collectors.toList());
        queriedCountries = currency.isEmpty() ? queriedCountries : queriedCountries.stream().filter(f->f.getCurrency().equals(currency)).collect(Collectors.toList());
        queriedCountries = phoneCode.isEmpty() ? queriedCountries : queriedCountries.stream().filter(f->f.getPhoneCode() == Integer.parseInt(phoneCode)).collect(Collectors.toList());
        queriedCountries = orderBy.equals("desc") ? queriedCountries.stream()
                                                                        .sorted(Comparator.comparingInt(Country::getPhoneCode).reversed())
                                                                        .collect(Collectors.toList()):queriedCountries.stream()
                                                                        .sorted(Comparator.comparingInt(Country::getPhoneCode))
                                                                        .collect(Collectors.toList()) ;
        return queriedCountries;
    }
}

İşlemimiz tamam, şimdi projeyi çalıştıralım ve localhost:8080/countries url sine bir sorgu atalım. Tarayıcıdan da atabilirsiniz fakat gelen json datası çok anlaşılır olmayacaktır. Ben Postman kullanıyorum. Postman ekranını aşağıya ekliyorum:

Ülke koduna özel olarak attığımız isteğin sonucu da aşağıdadır:

Sadece Asya kıtasındaki ülkeler için bir istek atalım:

Telefon kodu 1 olan ve sadece Kuzey Amerika’da bulunan ülkeler için bir istek atalım:

Son olarak da para birimi olarak sadece USD kullanan ülkeler için bir istek atalım ve bu ülkeleri telefon kodu büyükten küçüğe doğru oalcak şekilde sıralayalım:

Kaynak kodlara ve assetlere aşağıdaki github linkinden ulaşabilirsiniz:

https://github.com/aedemirsen/countries-be

Bu java projesini bir sonraki yazıda Docker Container içerisinde nasıl çalıştıracağız bunu anlatacağım. Daha sonra bir React projesi ile de bu rest apiyi kullanacağız.

İyi çalışmalar.

Leave a Reply

Your email address will not be published. Required fields are marked *