[3-1] 데이터 통신 기초
[3-2] HTTP
[3-3] JSON
[3-4] API
[3-5] CRUD
[3-6] API 명세서
보통 인터넷에 있는 데이터를 요청할 때에는 HTTP
라는 프로토콜을 사용하며, 주소(URL, URI)를 통해 API
에 접근할 수 있게 된다.
클라이언트와 서버는 웹에서 HTTP 프로토콜을 사용해서 통신한다.
클라이언트는 서버로 요청을 보내고, 서버는 요청에 따라 적절한 응답을 클라이언트로 회신한다.
필요에 따라 서버는 데이터베이스에 요청을 보내고, 회신 받은 응답을 활용한다.
💡 Client(클라이언트)란?
- 클라이언트는 인터넷에 연결된 사용자의 디바이스, 또는 웹에 접근할 수 있는 소프트웨어를 뜻한다.
- 대표적인 예로 브라우저가 있다.
- 브라우저는 HTML, CSS, JavaScript 등으로 작성된 코드를 내부 엔진으로 해독하여 사용자가 쉽게 이해할 수 있는 형태의 컨텐츠로 보여주는 역할을 한다.
💡 Server(서버)란?
- 서버는 클라이언트가 어떤 자원을 요청하면 해당 요청을 적절하게 처리하는 역할을 한다.
FTP
: 파일을 주고 받을때
SMTP
: 메일을 전송
HTTP
: 텍스트 또는 라이퍼텍스트 HTML을 전송
💡 HTTP란?
- 이렇게 클라이언트와 서버가 서로 요청과 응답을 주고받을 수 있는 것은 HTTP라는 통신 규약 덕분이다.
프로트에서 백엔드에 데이터를 요청하면 백엔드는 응답한다.
요청과 응답을 할때 그냥 보내는게 아니라 일정한 양식을 갖은 형태로 담아 전송한다.
주고받는 데이터 양식은 간략하게 헤더와 바디로 나눠진다.
헤더부분
: 보내는이, 보내는형태
바디부분
: 주요 내용
요청을 받은 백엔드는 DB에 저장된 자료를 찾아 응답한다.
응답역시 그냥 주는 것이 아닌 일정한 양식을 갖은 동일한 형태로 돌려준다.
💡 상태코드란?
- 상태 코드는 3자리 숫자로 만들어져 있으며, 첫번째 자리는 1에서 5까지 제공된다.
- 첫번째 자리가 4와 5인 경우는 정상적인 상황이 아니기 때문에 사이트 관리자가 즉시 알아야 하는 정보다.
- 간략하게 상태코드에 대해 설명하자면 다음과 같다
1xx(정보)
: 요청을 받았으며 프로세스를 계속 진행합니다.
2xx(성공)
: 요청을 성공적으로 받았으며 인식했고 수용하였습니다.
3xx(리다이렉션)
: 요청 완료를 위해 추가 작업 조치가 필요합니다.
4xx(클라이언트 오류)
: 요청의 문법이 잘못되었거나 요청을 처리할 수 없습니다.
5xx(서버 오류)
: 서버가 명백히 유효한 요청에 대한 충족을 실패했습니다.
💡JSON란?
서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식. 클라이언트가 사용하는 언어에 관계 없이 통일된 데이터를 주고받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 자기만의 방식으로 온전히 저장, 표시할 수 있는 것은 JSON 덕분이다.
JSON의 특징
우리는 실제로 앱을 만들때 통신을 한다는 건 필요한 도구들을 다운로드 받고 그 도구들을 활용하는 방식으로 통신하고 API가 바로 그것이다.
💡 API란?
이전에도 말했던 것처럼 API는 쉽게 생각해서 메뉴판이다.
- 클라이언트가 서버에 요청할 때는 정확한 주문 방법에 따라 요청해야한다.
- 서버는 클라이언트에게 리소스를 잘 활용할 수 있도록 인터페이스(interface)를 제공해줘야 한다.
- 클라이언트는 서버가 어떻게 구성되어 있는지 알 방법이 없기 때문에 서버가 인터페이스를 제공해야한다. 이것을
API(Application Programming Interface)
라고 한다.
API의 종류는 크게 rest-API
, graphql-API
로 2가지가 있다.
rest-API 와 graphql-API 는 몇가지 차이점이 있다.
1. 함수 이름의 차이
2. 응답 결과물의 차이
rest-API
는 응답 결과로 back-end 개발자가 만든 함수에서 보내주는 모든 데이터를 받아야만 한다.graphql-API
는 back-end 개발자가 만든 함수에서 필요한 데이터만 골라 받을 수 있다.이러한 이유로, 각 API에 전송을 요청하는 담당자도 다르다.
rest-API
에 요청하는 요청담당자는 axio 다.graphql-API
에 요청하는 요청담당자는 apollo-client 다.마지막으로 graphql
은 필요한 데이터만 골라 받을 수 있는 장점이 있어서, 효율적인 통신을 할 수 있다.
3. 설치해야 할 프로그램의 차이
CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다. 사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.
생성, 수정, 삭제, 조회에 따라 요청 명령어가 있는데 GRAPHQL은 생성, 수정, 삭제를 하나로 통합한다. 그러기에 MUTATION은 신중해야 된다.
실제 사용 방법은 위와 같다.
💡 한장에 정리
💡 API 명세서란?
- API 사용 설명서
- 홈페이지를 만들기 전, Back-end 개발자가 만들어 놓은 API 가 몇 개 있고, 어떻게 구성되어있는지 확인하기 위해 필요하다.
- API명세서는 Back-end 개발자에게 받아야 한다.
- Back-end 개발자는 자신이 만든 API를 직접
문서 형태
로 작성하거나,swagger
라는 프로그램을 설치해서 만든다.
📚 코드캠프
mutation{ createProfile(name: "철수", age: 12, school: "다람쥐초등학교"){ number message } }
query{ fetchProfile(name: "철수"){ name age school } }
mutation{ createBoard(writer: "영희", title: "안녕하세요~", contents: "반갑습니다"){ _id number message } }
query{ fetchBoard(number: 1204){ title contents } }
mutation{ createProduct( seller: "철수" createProductInput: { name: "마우스", detail: "정말 좋은 마우스", price: 3000 } ){ _id number message } }
query{ fetchProduct(productId: "da4be0d5-505b-4ffe-90a9-997db1d4c496"){ seller name price } }
mutation{ updateProduct( productId: "da4be0d5-505b-4ffe-90a9-997db1d4c496" updateProductInput: { name: "키보드", price: 100000 } ){ _id number message } }
query{ fetchBoardsCount }
import { useState } from "react"
//==============================================>게시물 수정
import {
Wrapper,
Container,
//--------------------> Box :)
InPutBox,
TwoBox,
HeaderBox,
AddressBox,
YoutubeBox,
AttachPicturesBox,
MainSettingBox,
RegistrationBox,
//--------------------> 기타 :)
Title,
Label,
Writer,
Password,
ZipButton,
Pictures,
RadioButton,
RadioLabel,
SubmitButton,
CancelButton,
PicturesOut,
RadioOut,
Error,
//--------------------> Text :)
WriterText,
PasswordText,
TitleText,
ContentsText,
ZipText,
AddressText,
YoutubeText,
} from "../../styles/Day2";
export default function BoardsNewPage() {
//-------------------------------------------------------> Input에 들어가는 문구 :)
const [writer, setWriter] = useState("")
const [password, setPassword] = useState("")
const [title, setTitle] = useState("")
const [contents, setContents] = useState("")
const [zip, setZip] = useState("07250")
const [youtube, setYoutube] = useState("")
//---------------------------------------------------------> Input error :(
const [writerError, setWriterError] = useState("")
const [passwordError, setPasswordError] = useState("")
const [titleError, setTitleError] = useState("")
const [contentsError, setContentsError] = useState("")
const [zipError, setZipError] = useState("")
//----------------------------------------------------------> event.target.value :)
function onWriter(event) {
setWriter(event.target.value)
if (event.target.value !== "") {
setWriterError("")
}
}
function onPassword(event) {
setPassword(event.target.value)
if (event.target.value !== "") {
setPasswordError("")
}
}
function onTitle(event) {
setTitle(event.target.value)
if (event.target.value !== "") {
setTitleError("")
}
}
function onContents(event) {
setContents(event.target.value)
if (event.target.value !== "") {
setContentsError("")
}
}
//---------------------------------------------------------------> 1. 검증하기
function onChangeSignup() {
if (writer === "") {
setWriterError("작성자를 다시 작성해주세요.")
}
if (password === "" && password.length < 3) {
setPasswordError("비밀번호를 다시 작성해주세요.")
}
if (title === "") {
setTitleError("제목을 다시 작성해주세요.")
}
if (contents === "") {
setContentsError("내용을 다시 작성해주세요.")
}
if (writer !== "" && password !== "" && title !== "" && contents !== "") {
alert("회원가입을 축하합니다!!")
}
}
//------------------------------------------------------------->HTML :)
return (
<Wrapper>
<Container>
<HeaderBox>
<Title>게시물 수정</Title>
</HeaderBox>
<TwoBox>
<Writer>
<Label>작성자</Label>
<WriterText type="text" onChange={onWriter} placeholder="이름을 작성해주세요." />
<Error>{writerError}</Error>
</Writer>
<Password>
<Label>비밀번호</Label>
<PasswordText type="password" onChange={onPassword} placeholder="비밀번호를 작성해주세요." />
<Error>{passwordError}</Error>
</Password>
</TwoBox>
<InPutBox>
<Label>제목</Label>
<TitleText type="text" onChange={onTitle} placeholder="제목을 작성해주세요." />
<Error>{titleError}</Error>
</InPutBox>
<InPutBox>
<Label>내용</Label>
<ContentsText type="text" onChange={onContents} placeholder="내용을 작성해주세요." />
<Error>{contentsError}</Error>
</InPutBox>
<AddressBox>
<Label>주소</Label>
<ZipText type="text" placeholder="07250" />
<ZipButton>우편변호 검색</ZipButton>
<AddressText type="text" placeholder="" />
<AddressText type="text" placeholder="" />
</AddressBox>
<YoutubeBox>
<Label>유튜브</Label>
<YoutubeText type="text" placeholder="링크를 복사해주세요." />
</YoutubeBox>
<AttachPicturesBox>
<Label>사진 첨부</Label>
<PicturesOut>
<Pictures>+</Pictures>
<Pictures>+</Pictures>
<Pictures>+</Pictures>
</PicturesOut>
</AttachPicturesBox>
<MainSettingBox>
<Label>메인 설정</Label>
<RadioOut>
<RadioButton type="radio" name="myaRadio" />
<RadioLabel>유튜브</RadioLabel>
<RadioButton type="radio" name="myaRadio" />
<RadioLabel>사진</RadioLabel>
</RadioOut>
</MainSettingBox>
<RegistrationBox>
<CancelButton>취소하기</CancelButton>
<SubmitButton onClick={onChangeSignup}>등록하기</SubmitButton>
</RegistrationBox>
</Container>
</Wrapper>
);
}
import styled from "@emotion/styled";
export const Wrapper = styled.div`
width: 1200px;
/* height: 1847px; */
border: 1px solid black;
margin: 100px;
padding-top: 80px;
padding-bottom: 100px;
padding-left: 102px;
padding-right: 102px;
display: flex;
flex-direction: column;
align-items: center;
border: none;
box-shadow: 0px 0px 10px gray;
`;
export const Container = styled.div`
width: 1000px;
`;
export const HeaderBox = styled.div`
font-weight: 700;
font-size: 36px;
line-height: 53px;
margin-bottom: 50px;
display: flex;
flex-direction: row;
justify-content: center;
cursor: pointer;
`;
export const InPutBox = styled.div`
margin-bottom: 50px;
display: flex;
flex-direction: column;
`;
export const TwoBox = styled.div`
margin-bottom: 50px;
display: flex;
flex-direction: row;
justify-content: space-between;
`;
export const AddressBox = styled.div`
`;
export const YoutubeBox = styled.div`
`;
export const AttachPicturesBox = styled.div`
`;
export const MainSettingBox = styled.div`
`;
export const RegistrationBox = styled.div`
display: flex;
align-items: center;
justify-content: center;
`;
export const Title = styled.div`
`;
export const Label = styled.div`
font-weight: 500;
font-size: 16px;
margin-bottom: 10px;
`;
export const Writer = styled.div`
`;
export const WriterText = styled.input`
width: 486px;
height: 52px;
padding-left: 20px;
`;
export const Password = styled.div`
`;
export const PasswordText = styled.input`
width: 486px;
height: 52px;
padding-left: 20px;
`;
export const TitleText = styled.input`
width: 1000px;
height: 52px;
padding-left: 20px;
`;
export const ContentsText = styled.input`
width: 1000px;
height: 480px;
display: flex;
padding-bottom: 430px;
padding-left: 20px;
`;
export const ZipText = styled.input`
width: 77px;
height: 52px;
margin-right: 20px;
padding-left: 18px;
`;
export const ZipButton = styled.button`
width: 124px;
height: 52px;
background: #000000;
color: white;
border-radius: 3px;
border: none;
cursor: pointer;
`;
export const AddressText = styled.input`
width: 1000px;
height: 52px;
margin-top: 15px;
margin-bottom: 20px;
padding-left: 20px;
`;
export const YoutubeText = styled.input`
width: 1000px;
height: 52px;
margin-bottom: 30px;
padding-left: 20px;
`;
export const PicturesOut = styled.div`
display: flex;
`;
export const Pictures = styled.button`
background-color: #BDBDBD;
width: 78px;
height: 78px;
margin-right: 20px;
margin-top: 10px;
margin-bottom: 30px;
display: flex;
justify-content: center;
align-items: center;
border: none;
cursor: pointer;
&:hover {
background: #aDaDaD;
}
`;
export const RadioOut = styled.div`
display: flex;
align-items: center;
margin-bottom: 50px;
`;
export const RadioButton = styled.input`
width: 20px;
height: 20px;
cursor: pointer;
`;
export const RadioLabel = styled.div`
margin-left: 10px;
margin-right: 20px;
font-weight: 500;
font-size: 18px;
`;
export const SubmitButton = styled.button`
width: 179px;
height: 52px;
background: #FFe600;
border: none;
border-radius: 3px;
font-weight: 500;
font-size: 16px;
cursor: pointer;
&:hover {
background: #FFd600;
}
`;
export const CancelButton = styled.button`
width: 179px;
height: 52px;
background: #BDBDBD;
border: none;
border-radius: 3px;
font-weight: 500;
font-size: 16px;
margin-right: 20px;
cursor: pointer;
&:hover {
background: #aDaDaD;
}
`;
export const Error = styled.div`
font-size: 13px;
color: tomato;
margin-top: 5px;
margin-left: 10px;
`;