https://github.com/donghl-dev/reactive-blog
Reactive-Programming을 이용한 비동기 Blog API 프로젝트
https://github.com/donghl-dev/reactive-blog
junit5 reactive-programming reactivemongo spring-boot spring-security spring-webflux
Last synced: 10 months ago
JSON representation
Reactive-Programming을 이용한 비동기 Blog API 프로젝트
- Host: GitHub
- URL: https://github.com/donghl-dev/reactive-blog
- Owner: donghL-dev
- License: mit
- Created: 2019-11-28T06:17:46.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2023-03-15T11:33:34.000Z (almost 3 years ago)
- Last Synced: 2025-02-05T11:52:09.239Z (11 months ago)
- Topics: junit5, reactive-programming, reactivemongo, spring-boot, spring-security, spring-webflux
- Language: Java
- Homepage:
- Size: 170 KB
- Stars: 2
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Project - Reactive Blog
===
> 리액티브 프로그래밍의 학습을 위해서 `Spring-WebFlux`, `Mono/Flux`, `Reactive-Monogo`를 이용하여 진행하는 비동기 Blog API 프로젝트.
## 개발환경
|도구|버전|
|:---:|:---:|
| Framework |Spring Boot 2.2.1 |
| OS |Windows 10, Ubuntu 18.04|
| IDE |IntelliJ IDEA Ultimate |
| JDK |JDK 1.8+|
| DataBase |MongoDB Server 4.2.1|
| Build Tool | Gradle 4.8.1 |
## 개발 방법
세부정보
* 개발과 관련된 모든 이야기는 [Issues](https://github.com/donghL-dev/Reactive-Blog/issues)에서 진행합니다.
* `API` 및 도메인 명세를 기반으로 개발을 진행하며, 명세에 변경사항이 생길 경우 빠른 시일내에 최신화 합니다.
* **Fork**를 통한 `PR`을 지향합니다.
* 아래와 같은 `Git Workflow`를 지향하며 지키려고 노력합니다. ([참고](https://nvie.com/posts/a-successful-git-branching-model/?))

## 실행 방법
세부정보
* 준비사항.
* `Gradle` or `IntelliJ IDEA`
* `JDK` (>= 1.8)
* `Spring Boot` (>= 2.x)
* 저장소를 `clone`
```bash
$ git clone https://github.com/donghL-dev/Reactive-Blog.git
```
* 데이터 베이스는 `MongoDB`를 사용해야 합니다.
* 프로젝트 내 `Reactive-Blog\src\main\resources` 경로에 `application.yml` 생성.
* 밑의 양식대로 내용을 채운 뒤, `application.yml`에 삽입.
```yml
spring:
data:
mongodb:
host: # 본인의 DB 서버 주소를 넣으면 되는데, 왠만하면 localhost입니다.
port: # 본인의 DB 서버 PORT 왠만하면 27017입니다.
database: # 본인의 데이터베이스 이름을 기재하시면 됩니다.
```
* `IntelliJ IDEA`(>= 2018.3)에서 해당 프로젝트를 `Open`
* 또는 터미널을 열어서 프로젝트 경로에 진입해서 다음 명령어를 실행.
* `Windows 10`
```bash
$ gradlew bootRun
```
* `Ubuntu 18.04`
```
$ ./gradlew bootRun
```
## Dependencies
세부정보
* `Spring Reactive Web`
* `Spring Data Reactive MongoDB`
* `Embedded MongoDB Database`
* `Spring Security`
* `Lombok`
## 도메인 명세
* [도메인 명세 문서](https://www.notion.so/dhlab/52ff6bb691934fbabeca5287bc32dffb)
## API 명세
세부정보
* 모든 `API`에 대한 반환은 `Content-Type: application/json; charset=utf-8`를 기본으로 합니다.
* 인증(`auth`)은 `HTTP` 헤더를 사용해서 진행됩니다.
| Key | Value |
|:---:|:---:|
| Content-Type | `application/json` |
| Authorization | `token` |
* `Response`
* `User`
```json
{
"user": {
"email": "...",
"token": "...",
"username": "...",
"bio": "...",
"image": null
}
}
```
* `Profile`
```json
{
"profile": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}
```
* `Single Article`
```json
{
"article": {
"slug": "...",
"title": "...",
"description": "...?",
"body": "...",
"tagList": ["...", "..."],
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"favorited": false,
"favoritesCount": 0,
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}
}
```
* `Multiple Article`
```json
{
"articles":[{
"slug": "...",
"title": "...",
"description": "...?",
"body": "...",
"tagList": ["...", "..."],
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"favorited": false,
"favoritesCount": 0,
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}, {
"slug": "...",
"title": "...",
"description": "...?",
"body": "...",
"tagList": ["...", "..."],
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"favorited": false,
"favoritesCount": 0,
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}],
"articlesCount": 2
}
```
* `Single Comment`
```json
{
"comment": {
"id": 1,
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"body": "...",
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}
}
```
* `Multiple Comments`
```json
{
"comments": [{
"id": 1,
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"body": "...",
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
},{
"id": 1,
"createdAt": "9999-99-99T00:00:00.000Z",
"updatedAt": "9999-99-99T00:00:00.000Z",
"body": "...",
"author": {
"username": "...",
"bio": "...",
"image": "...",
"following": false
}
}]
}
```
* `List of Tags`
```json
{
"tags": [
"reactjs",
"angularjs"
]
}
```
* `Errors and Status Codes`
```json
{
"errors":{
"body": [
"..."
]
}
}
```
* `Default Success Code`
```json
{
"body": {
"status": "200 OK",
"message": "Your request has been successfully processed."
}
}
```
* 대표적인 에러 코드
* `401 for Unauthorized requests`
* `400 for Bad requests`
* `404 for Not found requests`
* End Point
* 사용자 및 로그인
| Title | HTTP Method | URL | Request | Response | Auth
|:---:|:---:|:---:|:---:|:---:|:---:|
| `Registration` | `POST` | `/api/users` | `{ "user":{ "username": "sangkon", "email": "me@sangkon.com", "password": "qwer1234" } }` | `User` | `NO`
| `Authentication` | `POST` | `/api/users/login` | `{ "user":{ "email": "demo@demo.com", "password": "X12345678" } }` | `User` | `No`
| `Authentication expiration` | `POST` | `/api/users/logout` | | `Default Success Code` | `YES`
| `Current User` | `GET` | `/api/user` | | `Current User` | `YES`
| `Update User` | `PUT` | `/api/user` | `{ "user":{ "email": "me@sangkon.com", "bio": "Java developer", "image": "image URL" } }` | `User` | `YES`
| `Get Profile` | `GET` | `/api/profiles/:username` | | `Profile` | `NO`
| `Fallow User` | `POST` | `/api/profiles/:username/follow` | | `Profile` | `YES`
| `Unfallow User` | `DELETE` | `/api/profiles/:username/follow` | | `Profile` | `YES`
* 블로그 내용
| Title | HTTP Method | URL | Request | Response | Auth
|:---:|:---:|:---:|:---:|:---:|:---:|
| `List Articles` | `GET` | `/api/articles` | | `Multiple Articles` | `NO`
| `Filter by tag` | `GET` | `/api/articles?tag=springboot` | | `Multiple Articles` | `NO`
| `Filter by author` | `GET` | `/api/articles?author=demo` | | `Multiple Articles` | `NO`
| `Favorited by user` | `GET` | `/api/articles?favorited=demo` | | `Multiple Articles` | `NO`
| `Limit number of articles` | `GET` | `/api/articles?limit=20` | | `Multiple Articles` | `NO`
| `Offset/skip number of articles` | `GET` | `/api/articles?offset=0` | | `Multiple Articles` | `NO`
| `Feed Articles` | `GET` | `/api/articles/feed` | | `Multiple Articles` | `YES`
| `Get Articles` | `GET` | `/api/articles/:slug` | | `Single article` | `YES`
| `Create Article` | `POST` | `/api/articles` | `{ "article": { "title": "How to train your dragon", "description": "Ever wonder how?", "body": "You have to believe", "tagList": ["reactjs", "angularjs", "dragons"] } }` | `Single article` | `YES`
| `Update Article` | `PUT` | `/api/articles/:slugs` | `{ "article": { "title": "Did you train your dragon?" } }` | `Single article` | `YES`
| `Delete Article` | `DELETE` | `/api/articles/:slug` | | | `YES`
| `Add Comments to an Article` | `POST` | `/api/articles/:slug/comments` | `{ "comment": { "body": "His name was my name too." } }` | `Single Comment` | `YES`
| `Get Comments from an Article` | `GET` | `/api/articles/:slug/comments` | | `Multiple comments` | `NO`
| `Delete Comment` | `DELETE` | `/api/articles/:slug/comments/:id` | | | `YES`
| `Favorite Article` | `POST` | `/api/articles/:slug/favorite` | | `Single article` | `YES`
| `Unfavorite Article` | `DELETE` | `/api/articles/:slug/favorite` | | `Single article` | `YES`
| `Get Tags` | `GET` | `/api/tags` | | `List of Tags` | `NO`
## Reference
세부정보
* [Spring Seucrity 적용 및 JWT 토큰 관련 참고 페이지](https://medium.com/@ard333/authentication-and-authorization-using-jwt-on-spring-webflux-29b81f813e78?)