๐ก API ๋ฌธ์: API ์ฐ๋ ๋ฒ์ ๊ธฐ์ ํด๋์ ๋ฌธ์, ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๊ธฐ ์ํ ๋ฐฉ๋ฒ๊ณผ ๊ท๊ฒฉ์ ์ ๊ณตํ๋ ๋ฌธ์.
#URL sample
[GET] /repos/{owner}/{repo}/commits
https://api.github.com/repos/OWNER/REPO/commits
//๋์ ๊นํ commits API URL
https://api.github.com/repos/coastby/java-project2/commits
owner
stringRequired : The account owner of the repository. The name is not case sensitive.
repo
stringRequired : The name of the repository. The name is not case sensitive.
sha
string : SHA or branch to start listing commits from. Default: the repositoryโs default branch (usuallyย master
).
path
string : Only commits containing this file path will be returned.
author
string : GitHub login or email address by which to filter by commit author.
since
string : Only show notifications updated after the given time. This is a timestamp inย ISO 8601ย format:ย YYYY-MM-DDTHH:MM:SSZ
.
until
string : Only commits before this date will be returned. This is a timestamp inย ISO 8601ย format:ย YYYY-MM-DDTHH:MM:SSZ
.
per_page
integer : The number of results per page (max 100).
Default:ย 30
page
integer : Page number of the results to fetch.
Default:ย 1
Status code | Description |
---|---|
200 | OK |
400 | Bad Request |
404 | Resource not found |
409 | Conflict |
500 | Internal Error |
?
๋ค์ ์ฟผ๋ฆฌ์คํธ๋ง(query string)์ โ{key}={value}โ
ํํ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.//๋ณ์๋ฅผ ํตํด value๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
@RequestParam String name
//์ด๋ค ๊ฐ์ด ๋ค์ด์ฌ ์ง ๋ชจ๋ฅด๋ฉด Map์ ์ด์ฉํ๋ค.
@RequestParam Map<String, String> param
์ฟผ๋ฆฌ์คํธ๋ง์ ์ด๋ค ๊ฐ์ด ๋ค์ด์ฌ์ง ๋ชจ๋ฅธ๋ค๋ฉด Map์ ํ์ฉํ ์ ์๋ค.
@GetMapping(value = "/request2")
public String getRequestParam2 (@RequestParam Map<String, String> param){
param.entrySet().forEach((map) -> {
System.out.printf("key : %s, value : %s", map.getKey(), map.getValue());
});
return "ํธ์ถ์ด ์๋ฃ๋์์ต๋๋ค.";
}
http://localhost:8080/api/v1/get-api/request2?name=hoon&weight=7.6
๊ฒฐ๊ณผ
a. client ํ๋ฉด
b. console
key : name, value : hoon
key : weight, value : 7.6
๐ซ Error 400: ์๋ฒ ๋ด๋ ธ๋ค๊ฐ ๋ค์ ์ฌ๋ ค์ผ ํ๋๋ฐ ๋ฐ๋ก ํจ
๐ก VO ๊ฐ์ฒด
- ์ปค๋งจ๋ ๊ฐ์ฒด:
HttpServletRequest
๋ฅผ ํตํด ๋ค์ด์จ ์์ฒญ ํ๋ผ๋ฏธํฐ๋ค์ setter ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ๊ฐ์ฒด์ ์ ์๋์ด์๋ ์์ฑ์ ๋ฐ์ธ๋ฉ์ด ๋๋ ๊ฐ์ฒด- ์ปจํธ๋กค๋ฌ๋ ์๋ฐ์ ๋ชจ๋ ์๋ฃํ์ ๋ฐ์์ฌ ์ ์์. VO ๊ฐ์ฒด ๋ํ ๊ฐ๋ฅ!
- VO ๊ฐ์ฒด๋ ํ๋๋ช ์ด ์ค์! ํด๋์ค์ ๊ฐ๊ฐ์ ํ๋๋ช ์ด ์กด์ฌํ๊ฒ ๋๋๋ฐ, ํ๋๋ช ์ ์ด์ฉํด์ ์๋ฃ๋ฅผ ์ ๋ ฅ๋ฐ์ (๊ฐ์ฒด๋ช ๊ณผ ๋ฌด๊ด)
- ๋ฉ์๋์์ ํด๋์ค๋ VO๊ฐ ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด์ค๋ฉด ํผ์์ ํด๋์ค ํน์ VO๊ฐ ์๋ค~๊ทธ๋ฅ ๋ฌด์ํ์~๊ฐ ์๋๋ผ
- VO๋ฅผ ๋ง๋๋ ์๊ฐ ์ด! VO ๊ฐ์ฒด๋ค? ๊ทธ๋ผ ๋ณ์๋ช ์ ๋ค์ฌ๋ค๋ณผ๊น? ํด์ ๋ณ์๋ช ์ผ๋ก ๋งค์นญํด์ค
๐ย MemberDto
: ํ๋๋ณ์
, constructor
, getter,
toString()
๋ง ๊ตฌํ
public class MemberDto {
private String name;
private String email;
private String organization;
public MemberDto(String name, String email, String organization) {
this.name = name;
this.email = email;
this.organization = organization;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getOrganization() {
return organization;
}
@Override
public String toString() {
return "MemberDto{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", organization='" + organization + '\'' +
'}';
}
}
๐ย Controller
: ํ๋ผ๋ฏธํฐ๋ก DTO๋ฅผ ๋ฐ์
a. DTO ํด๋์ค์ ์ ์ธ๋ ํ๋๋ ์ปจํธ๋กค๋ฌ์ ๋ฉ์๋์์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์ ํค์ ๋งคํ๋๋ค.
b. ์ฟผ๋ฆฌ์คํธ๋ง์ ํค๊ฐ ์ ํด์ ธ ์์ง๋ง ๋ฐ์์ผ ํ ํ๋ผ๋ฏธํฐ๊ฐ ๋ง์ ๊ฒฝ์ฐ DTO ๊ฐ์ฒด๋ฅผ ํ์ฉํด ์ฝ๋ ๊ฐ๋
์ฑ์ ๋์ ์ ์๋ค.
@GetMapping(value="/request3")
public String getRequestParam3(MemberDto memberDto){
return memberDto.toString();
}
API tester
http://localhost:8080/api/v1/get-api/request3?name=hoon&email=bob@gmai.com&organization=yeji
Controller
์์ฑ@PostMapping(value = "/member")
public String postMember(@RequestBody Map<String, Object> postData) {
StringBuilder sb = new StringBuilder(); //Builder Pattern
postData.entrySet().forEach(map -> {
sb.append(map.getKey()+" : "+map.getValue() + "\n");
});
return sb.toString();
}
http://localhost:8080/api/v1/post-api/member
b. BODY {
"name" : "hoon",
"email" : "sleeping@gmail.com",
"organization" : "yeji"
}
name : hoon
email : sleeping@gmail.com
organization : yeji
๐ซย ์๋ฌ
2022-10-27 14:09:03.978 WARN 34200 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character (''' (code 39)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): was expecting double-quote to start field name<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 2, column: 4]]
JSON ํ์์ด ๋ฌธ์ ์๋ค. ๋ฐ์ดํ๋ก ์ผ๋๋ฐ ์๋ฐ์ดํ๋ก ์จ์ผํ๋ค.
Controller
@PostMapping(value = "/member2")
public String postMemberDto(@RequestBody MemberDto memberDto) {
return memberDto.toString();
}
API tester
http://localhost:8080/api/v1/post-api/member2
{
"name" : "hoon",
"email" : "sleeping@gmail.com",
"organization" : "yeji"
}
๊ฒฐ๊ณผ BODY
{
"name" : "hoon",
"email" : "sleeping@gmail.com",
"organization" : "yeji"
}
โญ๏ธ PUT API
GET/member โ select * from member between , limit 100 โ list(๋ชฉ๋ก)
GET/member/{id} โ select * from member where id = ?
POST/member โ insert RequestBody
PUT/member โ update RequestBody
DELETE/member
PATCH/member โ put๊ณผ ๋น์ท
๐ก ์ถ๊ฐ ๋ด์ฉ
API ๋ฉ์๋์์ return์ ๊ฐ์ฒด๋ก ํ๋ฉด Content-Type์ดapplicatioin/json
ํ์์ผ๋ก ์ ๋ฌ๋๋ค. (@ResponseBody
)
โญ๏ธ HttpEntity ํด๋์ค
์คํ๋ง ํ๋ ์์ํฌ์ ํด๋์ค
Header์ Body๋ก ๊ตฌ์ฑ๋ HTTP ์์ฒญ๊ณผ ์๋ต์ ๊ตฌ์ฑํ๋ ์ญํ ์ ํ๋ค.
ResponseEntity๋ ์๋ฒ์ ๋ค์ด์จ ์์ฒญ์ ๋ํด ์๋ต ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์ฑํ๋ค.
์์ฑ์ ์ด์ฉ
return new ResponseEntity<>("success", HttpStatus.OK);
// ๋จ์ํ ๋ฉ์ธ์ง์ ์ํ์ฝ๋ ๋ฆฌํด
HttpHeaders headers = new HttpHeaders();
headers.add("TOKEN","XXXXXX");
return new ResponseEntity<>("Custom header set", headers, HttpStatus.OK);
// header์ ์ํ์ฝ๋ ๋ฆฌํด
Message message = Messgae.builder() // Messgae ๊ฐ์ฒด๋ ์ง์ ๋ง๋ ๊ฑฐ.
.message1("์ฒซ๋ฒ์งธ ๋ฉ์ธ์ง")
.message2("๋๋ฒ์งธ ๋ฉ์ธ์ง")
.build();
return new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR);
// ๋ฉ์ธ์ง์ ์ํ์ฝ๋ ๋ฆฌํด
static method ์ด์ฉ
return ResponseEntity.ok();
return ResponseEntity.status(HttpStatus.OK)
.header("Custom-Header","foo")
.body("Custom header set");
Controller
@PutMapping("/member3")
public ResponseEntity<MemberDto> postMemberDto3(@RequestBody MemberDto memberDto){
return ResponseEntity
.status(HttpStatus.ACCEPTED) //์๋ต ์ฝ๋ 202
.body(memberDto);
}
API tester
a. URI
http://localhost:8080/api/v1/put-api/member3
b. BODY
{
"name" : "hoon",
"email" : "sleeping@gmail.com",
"organization" : "yeji"
}
๊ฒฐ๊ณผ
๐ก Annotation ์ ๋ฆฌ
pom.xml - ์์ dependency ์ถ๊ฐ
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
ํ๋ก์ ํธ ์๋์ configuration
ํจํค์ง ์์ฑ - SwaggerConfiguration
ํด๋์ค ์ถ๊ฐ
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class SwaggerConfiguration {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
2022-10-27 15:20:55.045 WARN 36418 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
2022-10-27 15:20:55.064 INFO 36418 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2022-10-27 15:20:55.088 INFO 36418 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-10-27 15:20:55.119 ERROR 36418 --- [ main] o.s.boot.SpringApplication : Application run failed
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
http://localhost:8080/swagger-ui/ ๋ค์ด๊ฐ๋ฉด ์๋์ ํ๋ฉด์ด ๋์จ๋ค.
์๋์ ๋ด๊ฐ ๋ง๋ API๋ค์ ๋ณผ ์ ์๋ค.