mojo's Blog

REST API 구현 본문

JSP

REST API 구현

_mojo_ 2022. 1. 5. 19:57

JAX-RS로 REST API 서버 구현

 

1. JAX-RS 설치

'pom.xml'의 <dependencies> ... </dependencies> 사이에 다음과 같은 필요한 라이브러리를 추가한다.

 

 

2. [Maven Dependencies]에 관련 라이브러리가 나타난다. (확인해보자)

 

 

 

※ 서비스 구현

먼저 설정 클래스부터 구현한다.

JAX-RS 서비스가 톰캣의 jwbook 웹 애플리케이션에서 동작하기 때문에 JAX-RS 서버 모듈을 톰캣에서 등록해줘야 한다.

 

3. [ch12] 패키지를 생성하고 RestConfig 클래스를 생성한 후 다음과 같이 작성한다.

package ch12;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class RestConfig extends Application {
	public Map<String, Object> getProperties() {
		Map<String, Object> properties = new HashMap<String, Object>();
		properties.put("jersey.config.server.provider.packages", "ch12");
		return properties;
	}
}
  • JAX-RS와 관련된 패키지는 꼭 javax.wr.rs.*를 사용해야 한다.
  • @ApplicationPath : REST API 서비스 진입점을 의미한다.
  • properties.put("jersey.config.server.provider.apckages", "ch12") : [ch12] 패키지 의 클래스 에서 REST API 서비스를 찾는다는 설정으로 속성 이름인 "jersey.config.server.provider.packages"를 정확하게 작성해야 하는 점에 주의한다.

 

4. 다음으로 서비스 클래스를 생성한다.

여기서는 [ch12] 패키지의 클래스만 REST API로 동작하도록 했기 때문에 다른 패키지를 사용하면 안된다.

클래스 이름은 RestAPIExample로 생성한다.

package ch12;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Produces;

@Path("/test")
public class RestApiExample {
	@GET
	@Produces(MediaType.TEXT_PLAIN)
	public String sayHello() {
		return "Hello API Service";
	}
	
	@POST
	public String sayHello(@QueryParam("msg") String msg) {
		return msg + "API Service";
	}
}

RestConfig 클래스에서 기본 진입점을 "/api" 로 했기 때문에 @Path로 추가한 ("/test")를 포함하게 되면 전체 요청 경로는 /jwbook/api/test가 된다.

여기서는 동일 요청에 대해 GET, POST 요청을 구분해서 동작한다.

POST의 경우 쿼리 파라미터, 즉 HTML 폼이나 HTTP Body를 통해 전달되는 name=value 형태의 파라미터를 읽어와 사용하고 있으며 이 외에도 /jwbook/api/test/hello 와 같이 경로 형식의 파라미터도 처리할 수 있다.

 

5. 실행 및 결과 확인 (GET 방식만 테스트)

REST API의 경우 이클립스에서 바로 확인할 방법은 없고 톰캣을 실행한 다음 규격에 따른 URL(localhost:8080/jwbook/api/test)을 요청해야 한다.

GET 방식의 경우 웹 브라우저에서도 바로 확인이 가능하지만 POST 방식은 별도의 form을 만들거나 REST API 테스트 도구를 사용해야 한다.

 

 

 

Postman으로 REST API 테스트

 

 

※ Postman 설치 및 워크스페이스 설정

먼저 postman을 설치해야 한다.

윈도우, 맥, 리눅스 모두 지원하며 별도의 프로그램 설치 없이 웹에서도 사용이 가능하다.

하지만 설정 및 작업 공간 동기화를 위해 계정을 생성하고 프로그램을 다운로드해 설치한다.

 

1. postman 프로그램을 다운로드 하기 위해 https://www.postman.com/downloads/ 에 접속하여 <Download the App> 을 클릭한다.

 

 

 

2. 프로그램 설치 후 로그인을 하면 Postman의 메인 화면으로 이동하게 된다.

[WorkSpaces] -> [New WorkSpace] 메뉴를 선택해 작업 공간을 먼저 만든다.

<Visibility> 설정은 'Personal'로 변경해야 한다.

  • Name : jwbook
  • Visibility : Personal

 

 

우선 이전 실습에서 만든 API를 Postman에서 테스트해본다.

정상적 테스트를 위해서는 이클립스에서 톰캣이 실행되어 있는 상태여야 한다.

 

3. GET 방식 테스트

Postman 워크스페이스 화면 오른쪽 상단 [+]를 이용해 테스트할 항목을 생성한다.

먼저 GET 방식으로 테스트를 진행하기 위해 다음과 같이 GET을 선택하고 테스트할 URL(localhost:8080/jwbook/api/test)을 입력한 다음 <Send> 버튼을 클릭한다.

테스트에 성공할 경우 하단의 "Response Body" 부분에 API로부터 전달된 값이 출력된다.

 

 

4. POST 방식 테스트

다음은 POST 방식을 테스트해본다.

GET을 POST로 변경하고, API 설계에 따라 msg라는 파라미터 값을 전달하기 위해 Query Params 항목을 다음과 같이 설정한다.

설정을 완료하면 <Send> 버튼을 클릭한다.

파라미터 값을 입력하면 자동으로 URL 부분에 포함되어 나타난다.

  • Key: msg
  • Value: Java Web

Response Body 부분에 msg로 전달한 값이 포함된 결괏값이 출력되면 테스트가 정상적으로 완료된 것이다.

 

 

 

뉴스 REST API 서버 구현

 

이전에 만들었던 뉴스 서비스에 REST API를 추가하여 본격적으로 REST API 서버를 구현해보도록 한다.

예를 들어 웹 기반의 뉴스 서비스를 스마트폰 앱으로도 제공해야 하는 경우 기존 서비스에 REST API 부분만 추가하면 스마트폰과 웹 모두 지원되는 서비스 구현이 가능해진다.

 

1. API 설계

웹을 통해 제공되는 뉴스 등록, 삭제, 목록, 상세 보기 기능을 모두 API로도 구현하며 세부 API 사양은 다음과 같다.

기본 경로는 /jwbook/api 가 된다.

기능 Method URI 설명
뉴스 등록 POST /news 뉴스 등록을 위한 데이터를 JSON 형태로 HTTP Body로 전달
뉴스 삭제 DELETE /news/aid 뉴스 삭제를 위한 aid를 경로 파라미터로 전달
뉴스 목록 GET /news 전체 뉴스 목록을 JSON 형태로 응답
뉴스 상세 보기 GET /news/aid 특정 뉴스의 aid를 경로 파라미터로 전달

 

2. API 구현

기본 클래스 구조를 생성하고 먼저 뉴스 등록 부분부터 구현해본다.

① 클래스 생성 및 뉴스 등록

패키지 [ch12]에 NewsApiService 클래스를 생성하여 구현한다.

API 시작 경로는 "/news"이며 생성자에서 뉴스 데이터베이스 연동을 위한 NewsDAO 객체를 초기화한다.

패키지 [ch10]에서 만든 NewsDAO를 사용하는 것이기 때문에 [ch10]를 import 해야 한다.

package ch12;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;

import ch10.News;
import ch10.NewsDAO;

@Path("/news")
public class NewsApiService {
	NewsDAO dao;
	
	public NewsApiService() {
		dao = new NewsDAO();
	}
	
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public String addNews(News news) {
		try {
			dao.addNews(news);
		} catch(Exception e) {
			e.printStackTrace();
			return "News API: 뉴스 등록 실패!!";
		}
		return "News API: 뉴스 등록됨!!";
	}
}
  • @POST : POST 방식 요청 처리
  • @Consumes(MediaType.APPLICATION_JSON) : 클라이언트 요청에 포함된 미디어 타입의 유형을 지정한다. 여기서는 JSON 규격을 사용하겠다는 의미이다.
  • addNews() 메서드의 인자로는 News 타입이 요구되는데 @Consumes 설정에 따라 HTTP Body에 포함된 JSON 문자열이 자동으로 News로 변환된다. 이를 위해 JSON 문자열의 키와 News 객체의 멤버 변수명이 동일해야 한다.

 

② 뉴스 삭제

뉴스 삭제를 위해서는 삭제할 뉴스의 aid가 전달되어야 하는데 여기서는 경로 파라미터를 이용해 삭제할 아이디 값을 전달한다.

예를 들어 21번 기사를 삭제할 경우 요청 URL은 다음과 같다.

DELETE /jwbook/api/news/21

 

요청 메서드는 DELETE로, 만일 GET으로 삭제를 요청한다면 동작하지 않으므로 주의한다.

경로 파라미터는 @Path로 지정하고, 인자에 @PathParam 애너테이션을 사용해 데이터가 전달되도록 한다.

뉴스 등록 코드 부분 다음에 아래 코드를 입력한다.

	@DELETE
	@Path("{aid}")
	public String delNews(@PathParam("aid") int aid) {
		try {
			dao.delNews(aid);
		} catch(Exception e) {
			e.printStackTrace();
			return "News API: 뉴스 삭제 실패!! - " + aid;
		}
		return "News API: 뉴스삭제됨!! - " + aid;
	}

 

 

③ 뉴스 목록 조회

전체 뉴스 목록 조회는 JSON 배열 형태로 전달되어야 하는데 List 타입을 리턴하면 자동으로 변환되기 때문에 별도의 작업이 필요 없다.

뉴스 삭제 부분 다음에 이어서 작성한다.

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public List<News> getNewsList() {
		List<News> newsList = null;
		
		try {
			newsList = dao.getAll();
		} catch(Exception e) {
			e.printStackTrace();
		}
		return newsList;
	}
  • @Produces: 응답 콘텐츠의 타입으로 앞에서 요청 처리에 사용된 @Consumes와 같은 개념으로 볼 수 있다. @Produces에서 지정한 타입에 따라 리턴 객체를 처리하는 방법이 달라진다.

 

④ 목록에서 특정 뉴스를 선택할 때 상세 정보를 제공하기 위한 요청은 GET 방식을 사용하고 삭제와 동일하게 경로 파라미터를 사용해 aid를 전달한다.

	@GET
	@Path("{aid}")
	@Produces(MediaType.APPLICATION_JSON)
	public News getNews(@PathParam("aid") int aid) {
		News news = null;
		
		try {
			news = dao.getNews(aid);
		} catch(Exception e) {
			e.printStackTrace();
		}
		return news;
	}

 

 

3. 실행 및 결과 확인

톰캣을 실행하고 Postman에서 API를 호출해 결과를 확인하면 된다.

GET 방식의 경우 브라우저만으로도 간단하게 테스트할 수 있다.

 

▶ 뉴스 목록 조회

기존에 뉴스 정보를 조회해본다.

실행하면 응답 Body 부분에 JSON 배열로 된 뉴스 데이터를 확인할 수 있다.

url 부분에 localhost:8080/jwbook/api/news 를 입력하여 결과를 확인해본다.

 

▶ 뉴스 등록과 상세 정보 조회

뉴스 등록은 POST 방식으로 설정한다.

그리고 [Body] 메뉴에서 'raw'와 'JSON'을 선택한다.

다음과 같이 추가할 뉴스 기사 내용이 들어가야 한다.

이때 aid 값은 DB에서 자동으로 처리되므로 aid 필드가 포함되지 않도록 해야한다.

JSON 규격에 따라 키와 값 모두 " "로 감싸야 하고 각 필드 끝에는 ','가 들어가야 한다.

이때 마지막 데이터에는 ','가 들어가면 안 된다.

또한 이미지의 경우 직접 업로드 하는 방식이 아닌 이미지의 URL을 사용한다.

등록할 기사와 관련된 사진의 URL을 복사하여 붙여넣는다.

 

뉴스 등록까지 테스트되었으면 이제 뉴스 상세 정보를 요청해보도록 한다.

GET 방식으로 경로 파라미터로 aid 값을 넣어준다.

즉 url 부분에 localhost:8080/jwbook/api/news/aid 값을 입력하여 결과를 확인해보도록 한다.

 

▶ 뉴스 삭제

마지막으로 뉴스를 삭제해본다.

메서드를 DELETE로 하고 상세 정보 요청과 마찬가지로 경로 파라미터로 aid 값을 지정하면 된다.

 

 

 

NewsApiService.java 코드

 

package ch12;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.PathParam;

import ch10.News;
import ch10.NewsDAO;

@Path("/news")
public class NewsApiService {
	NewsDAO dao;
	
	public NewsApiService() {
		dao = new NewsDAO();
	}
	
	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public String addNews(News news) {
		try {
			dao.addNews(news);
		} catch(Exception e) {
			e.printStackTrace();
			return "News API: 뉴스 등록 실패!!";
		}
		return "News API: 뉴스 등록됨!!";
	}
	
	@DELETE
	@Path("{aid}")
	public String delNews(@PathParam("aid") int aid) {
		try {
			dao.delNews(aid);
		} catch(Exception e) {
			e.printStackTrace();
			return "News API: 뉴스 삭제 실패!! - " + aid;
		}
		return "News API: 뉴스삭제됨!! - " + aid;
	}
	
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public List<News> getNewsList() {
		List<News> newsList = null;
		try {
			newsList = dao.getAll();
		} catch(Exception e) {
			e.printStackTrace();
		}
		return newsList;
	}
	
	@GET
	@Path("{aid}")
	@Produces(MediaType.APPLICATION_JSON)
	public News getNews(@PathParam("aid") int aid) {
		News news = null;
		try {
			news = dao.getNews(aid);
		} catch(Exception e) {
			e.printStackTrace();
		}
		return news;
	}
}

'JSP' 카테고리의 다른 글

REST API  (0) 2022.01.05
리스너와 필터  (0) 2022.01.03
프로젝트 : 뉴스 기사 관리 웹 서비스  (5) 2022.01.03
SQL 및 JDBC 기본 구조와 API  (0) 2022.01.02
데이터베이스와 JDBC  (0) 2021.12.31
Comments