Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1055 lines (743 sloc) 29.2 KB
FORMAT: 1A
HOST: http://api.appkr.kr
# Welcome to the myProject Api
myProject Api 에 오신 것을 환영합니다.
myProject 에서는 포럼 <sup>Forum</sup> Api 를 제공합니다. 포럼을 사용하는 사용자를 식별하고 권한을 제어하기 위해 사용자 등록 및 로그인 <sup>Authentication</sup> 기능도 제공합니다.
## Base URL
모든 Api 요청은 아래 Base URL 을 이용합니다.
```http
http://api.appkr.kr
```
## Current Version
현재 버전은 v1 입니다. [Authentication](#authentication) 을 제외하고 모든 Api 요청에 `/v1` 이 포함되어야 합니다.
```http
GET /v1 HTTP/1.1
Host: api.appkr.kr
```
## Request 101
REST 원칙을 따릅니다.
### Reqeust Headers
#### Accept (Content Negotiation)
v1 에서는 JSON 응답만 지원합니다.
```http
GET /v1 HTTP/1.1
Host: api.appkr.kr
Accept: application/json
```
#### Accept-Language (Language Negoation)
v1 에서는 ko_KR 만 지원합니다.
```http
GET /v1 HTTP/1.1
Host: api.appkr.kr
Accept-Language: ko-KR
```
### Request Payload
`multipart/form-data`, `application/x-www-form-urlencoded`, `application/json` 을 모두 지원합니다. `application/json` 사용을 권장합니다.
```http
POST /v1/articles HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
{"field": "value"}
```
## Response 101
### Collection Response
Collection 에 해당하는 리소스를 요청하면 Pagination 이 포함된 응답을 받습니다. `data` 키 아래에 포함된 내용이 Collection 입니다.
```http
GET /v1/articles HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```json
HTTP/1.1 200 OK
{
"data": [
{"key": "value"},
{"key": "value"},
{"key": "value"},
{"key": "value"},
{"key": "value"}
],
"meta": {
"pagination": {
"total": 20,
"count": 5,
"per_page": 5,
"current_page": 1,
"total_pages": 4,
"links": {
"next": "/v1/articles?page=2"
}
}
}
}
```
### Instance Response
Instance 에 해당하는 리소스를 요청하면 요청한 Instance 하나에 대한 응답을 받습니다. 이 응답은 JSON 키가 없습니다.
```http
GET /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```json
HTTP/1.1 200 OK
{
"id": 95280986,
"title": "example title"
}
```
### Successful Response
리소스 생성, 수정, 삭제 등의 요청을 성공하면 성공 응답을 받습니다.
```http
PUT /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
Authorization: Bearer header.payload.signagure
{"title": "modified title"}
```
```javascript
HTTP/1.1 200 OK
{
"success": {
"code": 200,
"message": "Updated"
}
}
```
성공 응답 목록은 아래와 같고, HTTP 응답 코드와 동일한 코드를 JSON 본문에도 포함합니다.
Response Code|Description
---|---
200|성공
201|새로운 리소스가 성공적으로 생성되었습니다.
204|요청한 리소스가 삭제되었습니다.
### Error Response
에러가 발생했을 때는 아래와 같은 응답을 받습니다.
```http
PUT /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
Authorization: Bearer header.payload.signagure
{"title": "modified title"}
```
```javascript
HTTP/1.1 403 Forbidden
{
"error": {
"code": 403,
"message": "Forbidden"
}
}
```
오류 응답 목록은 아래와 같고, HTTP 응답 코드와 동일한 코드를 JSON 본문에도 포함합니다.
Response Code|Description
---|---
400|요청에 오류가 있습니다.
401|인증 오류입니다. Authorization 헤더를 확인해 주세요.
403|권한이 없습니다. Authorization 헤더로 넘긴 토큰에 해당하는 사용자가 요청하신 Action 을 수행할 권한이 없습니다.
404|요청한 리소스가 없습니다.
405|잘못된 HTTP 메소드를 사용했습니다.
422|유효성 검사 오류입니다. 요청 본문에 데이터가 형식에 맞는지 확인하세요.
429|Rate Limit 를 초과했습니다. 잠시 후 다시 시도하세요.
500|서버에 오류가 있습니다. [관리자](mailto:junwonkim@me.com) 에게 신고해 주세요.
503|서버에 트래픽이 폭주했거나, 서버 유지보수 작업 중입니다.
## Rate Limit
[Authentication](#authentication) 요청은 1 분에 10 회 까지, 리소스 요청은 1분에 60 회까지 허용합니다.
```http
GET /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
```
## Caching
GET 동사를 이용한 요청은 `Etag` 헤더를 응답합니다.
> 대부분의 HTTP 클라이언트 라이브러리가 자동으로 모든 처리를 해 줍니다.<br/><br/>
> 다만, 여러분의 클라이언트가 `Etag` 기능을 지원하지 않는데, 캐싱의 이득을 보려면, 응답 받은 Etag 헤더를 파싱하여 요청 URL 과 응답 본문을 저장하고, 다음 요청시 `If-None-Match: Etag` 헤더를 전송해야 합니다.
아래 그림은 `Etag` 를 이용한 클라이언트-서버간 캐싱 동작 시퀀스 다이어그램입니다.
![](https://camo.githubusercontent.com/f5c800863972804dd7af6ef6a55343df3fb55b53/687474703a2f2f342e62702e626c6f6773706f742e636f6d2f2d4f6a3674794f74386167302f565934456b5878324f5a492f41414141414141414145492f37554a6e43503459384f452f733634302f65746167732e706e67)
### First Request & Response
처음으로 `Etag` 값을 받습니다. 클라이언트 저장소에 받은 `Etag` 값을 키로 요청 URL 과 응답 본문을 저장해 놓습니다. *(대부분의 클라이언트 라이브러리가 자동으로 처리해 줍니다.)*
```http
GET /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
```
```http
HTTP/1.1 200 OK
Etag: CtXS0QQlWJKY2dXe
```
### Second-on Request & Response - **No change in server resources**
요청 URL 에 해당하는 `Etag` 값을 `If-None-Match` 헤더에 달아서 보냅니다.
응답을 보니 리소스의 내용이 변경되지 않았으므로, 클라이언트 저장소에 저장된 지난 번 응답 본문을 그대로 사용합니다. *(대부분의 클라이언트 라이브러리가 자동으로 처리해 줍니다.)*
```http
GET /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
If-None-Match: CtXS0QQlWJKY2dXe
```
```http
HTTP/1.1 304 Not Modified
```
### Second-on Request & Response - **Server resource changed**
서버의 리소스가 변경되었습니다. 새로 받은 `Etag` 값과 응답 본문을 클라이언트 저장소에 저장합니다. *(대부분의 클라이언트 라이브러리가 자동으로 처리해 줍니다.)*
```http
GET /v1/articles/95280986 HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
If-Non-Match: CtXS0QQlWJKY2dXe
```
```http
HTTP/1.1 200 OK
Etag: F8tG872adeIC3zlf
```
**`WHY`** 모바일 환경에서 응답속도 개선 및 사용자 요금 절감을 위해 꼭 필요합니다.
## Sub Resource Inclusion
### Signature
`include` 쿼리스트링을 이용하면, 현재 요청하는 리소스의 자식 리소스의 Collection 또는 Instance 를 응답에 포함할 수 있습니다.
문법은 아래와 같습니다.
```http
GET /v1/parent?include=child_resource:limit(limit|offset):sort(sort|order) HTTP/1.1
# 여러 개의 자식 리소스를 포함할 때는 array 필드나 콤마 (,) 를 이용할 수 있습니다.
GET /v1/parent?include[]=child_resource_1&include[]=child_resource_2 HTTP/1.1
# --or--
GET /v1/parent?include[]=child_resource_1,child_resource_2 HTTP/1.1
```
Keyword|Description
---|---
`child_resource`|자식 리소스의 이름입니다. (Article 부모 리소스에 대해서는 `comments`, `author`, `tags`, `attachments` 자식 리소스가 가용합니다.)
`:`|파라미터를 구분하는 구분자입니다.
`limit`|예약어 입니다. `comments`, `author`, `tags`, `attachments` 등 Collection 형태의 리소스에만 적용 가능합니다.
`limit(offset\\limit)`|`limit` 반환 받을 Collection 개수 입니다. `offset` 건너뛸 Collection 개수입니다. **(기본값 `limit(3\\0)`)**
`sort`|예약어 입니다. Collection 형태의 리소스에만 적용 가능합니다.
`sort(sort\\order)`|`sort` 정렬 기준 필드로 현재는 `created`, `view_count` 두 개만 지원합니다. `order` 정렬 방향으로 `asc`, `desc` 를 쓸 수 있습니다. **(기본값 `sort(created\\desc)`)**
**`알림`** 위 표에서 `\\` 는 Apiary 의 마크다운 컴파일 에러를 방지하기 위해 `|` 대신 넣은 문자입니다.
### Example
아래는 Article 리소스의 자식 리소스인 comments 와 authors 를 포함하는 예제 입니다.
```http
GET /v1/articles/95280986?include=comments:limit(1|0):sort('created'|'asc') HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```javascript
HTTP/1.1 200 OK
{
"id": 95280986,
"title": "example title",
"content_raw": "example content",
"content_html": "<p>example content</p>",
"created": "2015-12-19T10:37:42+0000",
"view_count": 1,
"link": {
"rel": "self",
"href": "/v1/articles/95280986"
},
"comments": {
"data": [
{
"id": 95280986,
"content_raw": "example comment",
"content_html": "<p>example comment</p>",
"created": "2015-12-19T10:37:42+0000",
"vote": {
"up": 1,
"down": 1
},
"link": {
"rel": "self",
"href": "/v1/comments/95280986"
},
"author": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "http://www.gravatar.com/d4c74594d841139328695756648b6bd6"
}
}
]
},
"author": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "http://www.gravatar.com/d4c74594d841139328695756648b6bd6"
},
"tags": [
"laravel",
"eloquent"
],
"attachments": 1
}
```
## Partial Response
### Against Parent Resource
`fields` 쿼리스트링을 이용하면, 응답 필드를 골라서 받을 수 있습니다. 필드는 콤마 (`,`) 로 구분하고, 필드간에 공백이 없도록 주의하십시오.
```http
GET /v1/articles/95280986?fields=id,title,content_raw,author HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```javascript
HTTP/1.1 200 OK
{
"id": 95280986,
"title": "example title",
"content_raw": "example content",
"author": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "http://www.gravatar.com/d4c74594d841139328695756648b6bd6"
}
}
```
### Against Sub Resource
역시 `fields` 쿼리스트링을 이용해서 자식 리소스의 응답 필드를 골라 받을 수 있습니다. 부모 리소스에서와 달리, 필드 구분에 파이프 문자 (`|`) 를 이용합니다. 필드 사이에 공백이 없도록 주의하십시오.
```http
GET /v1/articles/95280986?fields=id,title,content_raw,author&include=comments:fields(id|created|vote) HTTP/1.1
Host: api.appkr.kr
Content-type: application/json
```
```javascript
HTTP/1.1 200 OK
{
"id": 95280986,
"title": "example title",
"content_raw": "example content",
"author": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "http://www.gravatar.com/d4c74594d841139328695756648b6bd6"
},
"comments": {
"data": [
{
"id": 95280986,
"created": "2015-12-19T10:37:42+0000",
"vote": {
"up": 1,
"down": 1
}
}
]
},
}
```
# group Welcome to myProject Api v1
myProject Api v1 에 오신 것을 환영합니다.
## Welcoming the Api v1 [/v1]
### Hello myProject Api v1 [GET]
- request
- headers
Accept: application/json
- response 200 (application/json)
{
"name": "myProject Api",
"message": "Welcome to myProject Api. This is a base endpoint of version 1.",
"version": "v1",
"links": [
{
"rel": "self",
"href": "/v1"
},
{
"rel": "api.users.store",
"href": "/auth/register"
},
{
"rel": "api.sessions.store",
"href": "/auth/login"
},
{
"rel": "api.v1.docs",
"href": "/v1/docs"
}
]
}
# group Authentication
<a name="authentication"></a>
사용자 등록 및 인증을 위한 Api 입니다. myProject Api 는 사용자 인증을 위해 JWT <sup>Json Web Token</sup> 을 이용합니다.
## `token` 의 발급 및 사용
사용자 등록 및 로그인을 통해 생성된 `token` 은 myProject 서버에 새로운 리소스를 생성, 기존 리소스 수정 또는 삭제를 위한 Api 요청을 할 때 꼭 필요합니다. 전술한 Api 요청을 할 때 `token` 을 HTTP Authorization Header 에 붙여서 사용합니다. (e.g. `Authorization: Bearer token`) `token` 이 없으면 401 Unauthorized 응답을 받습니다. 한번 발급된 `token` 은 120 분 동안 유효하며, 유효한 기간 동안은 로그인 없이 Api 요청을 할 수 있습니다. 그래서, Api 클라이언트는 사용자 등록 및 로그인에서 받은 토큰을 로컬 저장소에 저장하고 있어야 합니다.
## `token` 의 만료 및 갱신
`token` 이 만료되면 서버는 401 Unauthorized 응답 코드와 함께 `token_expired` 메시지를 응답합니다. `token` 을 사용하지 않은지 총 2 주일이 지나지 않았다면, 기존 `token` 을 이용하여 새로운 토큰을 받을 수 있습니다. 2 주가 지나 더 이상 갱신이 불가한 상태가 되면, 서버로 부터 401 응답을 받게 되며 이때는 사용자에게 로그인 UI 를 표출하여 로그인을 하도록 유도하여 `token` 을 발급 받아야 합니다.
## User Registration [/auth/register]
새로운 사용자를 등록합니다.
### User Registration [POST]
- request OK
- headers
Accept: application/json
Content-type: application/json
- body
{
"name": "New User",
"email": "new_user@example.org",
"password": "password",
"password_confirmation": "password"
}
- response 201 (application/json)
- Attributes
- success (object)
- code: `201` (number) - Http Status Equivalent Message Code
- message: `Created` (string) - Message
- meta (object)
- token: `header.payload.signature` (string) - Json Web Token
- request Invalid Data
- headers
Accept: application/json
Content-type: application/json
- body
{"email": "invalid-email-address"}
- response 422 (application/json)
- Attributes
- error (object)
- code: `422` (number) - Http Status Equivalent Message Code
- message (array)
- `name 은(는) 필수 입력 항목 입니다.`
- `email 은(는) 유효한 이메일 주소가 아닙니다.`
- `password 은(는) 필수 입력 항목 입니다.`
- request Duplicate User
- headers
Accept: application/json
Content-type: application/json
- body
{
"name": "John Doe",
"email": "john@example.com",
"password": "password",
"password_confirmation": "password"
}
- response 422 (application/json)
- Attributes
- error (object)
- code: `422` (number) - Http Status Equivalent Message Code
- message (array)
- `email 은(는) 이미 사용 중입니다.`
## User Login [/auth/login]
로그인을 하고 `token` 을 얻습니다.
### User Login [POST]
- request OK
- headers
Accept: application/json
Content-type: application/json
- body
{
"email": "john@example.com",
"password": "password"
}
- response 201 (application/json)
- Attributes
- success (object)
- code: `201` (number) - Http Status Equivalent Message Code
- message: `Created` (string) - Message
- meta (object)
- token: `header.payload.signature` (string) - Json Web Token
- request Invalid Credential
- headers
Accept: application/json
Content-type: application/json
- body
{
"email": "john@example.com",
"password": "wrong-password"
}
- response 401 (application/json)
- Attributes
- error (object)
- code: `401` (number) - Http Status Equivalent Message Code
- message: `invalid_credentials` (string) - Message
- request Invalid Data
- headers
Accept: application/json
Content-type: application/json
- body
{
"email": "invalid-email-address",
"password": "password"
}
email: invalid-email-address
- response 422 (application/json)
- Attributes
- error (object)
- code: `422` (number) - Http Status Equivalent Message Code
- message (array)
- `email 은(는) 유효한 이메일 주소가 아닙니다.` (string)
## Token Refresh [/auth/refresh]
만료된 `token` 을 갱신합니다.
### Token Refresh [POST]
- request OK
- headers
Accept: application/json
Authorization: Bearer header.payload.signagure
- response 201 (application/json)
- Attributes
- success (object)
- code: `201` (number) - Http Status Equivalent Message Code
- message: `Created` (string) - Message
- meta (object)
- token: `header.payload.signature` (string) - Json Web Token
# group Forum
Forum Api 는 HTTP 요청을 통해 여러분의 Api 클라이언트가 서버에 저장된 게시글 <sup>`Article`</sup> 과 댓글 <sup>`Comment`</sup> 리소스를 이용할 수 있도록 해 줍니다.
**`참고`** 댓글에 대한 생성, 수정, 삭제 Api 는 현재 구현되어 있지 않습니다.
## Articles Collection [/v1/articles]
### List All Articles [GET]
`Article` Collection 을 요청합니다. 사용할 수 있는 쿼리스트링은 다음과 같습니다.
<a name="available_querystrings"></a>
#### Available Querystrings
- `filter` - 필터 (선택, `no_comment`|`not_solved`)
```http
GET /v1/articles?filter=no_comment
```
- `limit` - 응답 받을 게시물 수 (선택, `1`~`10`, 기본값 `5`)
```http
GET /v1/articles?limit=3
```
- `sort` - 정렬에 사용할 필드 (선택, `created`|`view_count`, 기본값 `created`)
```http
GET /v1/articles?sort=view_count
```
- `order` - 정렬 방향 (선택, `asc`|`desc`, 기본값 `desc`)
```http
GET /v1/articles?sort=view_count&order=asc
```
- `q` - 풀 텍스트 서치 키워드 (선택)
```http
GET /v1/articles?q=hello%20api
```
- request OK
- headers
Accept: application/json
- response 200 (application/json)
- headers
Etag: aK08i2L8jQRdjBcd
- attributes
- data (array[Article])
- meta (Pagination)
- request Not Modified
- headers
Accept: application/json
If-None-Match: etag
- response 304 (application/json)
### Not-allowed Querystrings [GET /v1/articles?filter=not_existing_filter]
- request Not-existing Querystrings
- headers
Accept: application/json
- response 422 (application/json)
- Attributes
- error (object)
- code: `422` (number) - Http Status Equivalent Message Code
- message (object)
- filter (array)
- `filter 은(는) 유효하지 않습니다.` (string)
### Create New Article [POST]
새로운 `Article` 리소스를 생성합니다.
- request OK
- headers
Accept: application/json
Content-type: application/json
Authorization: Bearer header.payload.signagure
- body
{
"title": "some title",
"content": "some content",
"tags[]": 1,
"tags[]": 2
}
- response 201 (application/json)
- attributes
- success (object)
- code: `201` (number) - Http Status Equivalent Message Code
- message: `Created` (string) - Message
- request Token Not Provided
- headers
Accept: application/json
Content-type: application/json
- response 400 (application/json)
- attributes
- error (object)
- code: `400` (number) - Http Status Equivalent Message Code
- message: `token_not_provided` (string) - Message
- request Token Invalid
- headers
Accept: application/json
Authorization: Bearer invalid.token.signature
- response 400 (application/json)
- attributes
- error (object)
- code: `400` (number) - Http Status Equivalent Message Code
- message: `token_invalid` (string) - Message
- request Token Expired
- headers
Authorization: Bearer expired.token.signagure
Content-type: application/json
- response 401 (application/json)
- attributes
- error (object)
- code: `400` (number) - Http Status Equivalent Message Code
- message: `token_expired` (string) - Message
## Articles Instance [/v1/articles/{id}]
- parameters
- id: `95280986` (required, number)
### Fetch Article Instance [GET]
`id` 로 지정된 `Article` 리소스의 상세정보를 요청합니다.
`Article Collection` 과 동일한 [Available Querystrings](#available_querystrings) 을 사용할 수 있습니다.
- request OK
- headers
Accept: application/json
- response 200 (application/json)
- headers
Etag: 31Ba8Uuo29Za4s2v
- body
{
"id": 95280986,
"title": "example title",
"content_raw": "example content",
"content_html": "<p>example content</p>",
"created": "2015-12-19T10:37:42+0000",
"view_count": 1,
"link": {
"rel": "self",
"href": "/v1/articles/95280986"
},
"comments": 1,
"author": {
"name": "John Doe",
"email": "john@example.com",
"avatar": "http://www.gravatar.com/d4c74594d841139328695756648b6bd6"
},
"tags": [
"laravel",
"eloquent"
],
"attachments": 1
}
- request Not Modified
- headers
Accept: application/json
If-None-Match: 31Ba8Uuo29Za4s2v
- response 304 (application/json)
### Fetch Not-existing Article Instance [GET /v1/articles/{id}]
없는 `id` 이면 404 Not Found 응답을 받습니다.
- parameters
- id: `00000000` (required, number)
- request Not-existing Resource
- headers
Accept: application/json
- response 404 (application/json)
- Attributes
- error (object)
- code: `404` (number) - Http Status Equivalent Message Code
- message: `No query results for model [App\\Article].` (string) - Message
### Update Article Instance [PUT]
`id` 로 지정된 `Article` 의 내용을 수정합니다. 수정은 리소스의 소유자 또는 관리자에게만 허용되며, 이 조건이 충족되지 않을 경우에는 403 Forbidden 응답을 받습니다.
- request OK
- headers
Accept: application/json
Content-type: application/json
Authorization: Bearer header.payload.signagure
- body
{
"title": "updated title",
"content": "updated content",
"tags[]": "3"
}
- response 200 (application/json)
- attributes
- success (object)
- code: `200` (number) - Http Status Equivalent Message Code
- message: `Updated` (string) - Message
- request Forbidden
- headers
Accept: application/json
Content-type: application/json
Authorization: Bearer not.owner.signagure
- response 403 (application/json)
- attributes
- error (object)
- code: `403` (number) - Http Status Equivalent Message Code
- message: `Forbidden` (string) - Message
### Delete Article Instance [DELETE]
`id` 로 지정된 `Article` 을 삭제합니다. 삭제는 리소스의 소유자 또는 관리자에게만 허용되며, 이 조건이 충족되지 않을 경우에는 403 Forbidden 응답을 받습니다.
- request OK
- headers
Accept: application/json
Authorization: Bearer header.payload.signagure
- response 204 (application/json)
- request Forbidden
- headers
Accept: application/json
Authorization: Bearer not.owner.signagure
- response 403 (application/json)
- attributes
- error (object)
- code: `403` (number) - Http Status Equivalent Message Code
- message: `Forbidden` (string) - Message
# data structures
## Article (object)
- id: `95280986` (number) - 고유 키
- title: `example title` (string) - 제목
- content_raw: `example content` (string) - 본문 (Markdown 형식)
- content_html: `<p>example content</p>` (string) - 본문 (HTML 컴파일)
- created: `2015-12-19T10:37:42+0000` (string) - 생성일
- view_count: 1 (number) - 조회 수
- link (object)
- rel: `self`
- href: `/v1/articles/95280986` (string) - 상세 내용 요청을 위한 Api Endpoint
- comments: `1` (number) - 댓글 개수
- author (object)
- name: `John Doe` (string) - 작성자 이름
- email: `john@example.com` (string) - 작성자 이메일
- avatar: `http://www.gravatar.com/d4c74594d841139328695756648b6bd6` (string) - 작성자 아바타 URL
- tags (array)
- laravel
- eloquent
- attachments: `1` (number) - 첨부파일 개수
## User (object)
- id: `95280986` (number) - 고유 키
- name: `John Doe` (string) - 사용자 이름
- email: `john@example.com` (string) - 사용자 이메일
- avatar: `http://www.gravatar.com/d4c74594d841139328695756648b6bd6` (string) - 사용자 아바타 URL
- signup: `2016-01-12T06:18:10+0000` - 가입일
- link (object)
- rel: `self`
- href: `/users/95280986` (string) - 상세 내용 요청을 위한 Api Endpoint
- articles: `1` (number) - 포럼 게시글 개수
- comments: `1` (number) - 작성한 댓글 개수
## Comment (object)
- id: `95280986` (number) - 고유 키
- content_raw: `example content` (string) - 본문 (Markdown 형식)
- content_html: `<p>example content</p>` (string) - 본문 (HTML 컴파일)
- created: `2015-12-19T10:37:42+0000` (string) - 생성일
- vote (object)
- up: `1` (number) - 좋아요 투표 수
- down: `1` (number) - 싫어요 투표 수
- link (object)
- rel: `self`
- href: `/v1/comments/95280986` (string) - 상세 내용 요청을 위한 Api Endpoint
- author (object)
- name: `John Doe` (string) - 작성자 이름
- email: `john@example.com` (string) - 작성자 이메일
- avatar: `http://www.gravatar.com/d4c74594d841139328695756648b6bd6` (string) - 작성자 아바타 URL
## Tag (object)
- id: `95280986` (number) - 고유 키
- slug: `laravel` (string) - Slug
- created: `2015-12-19T10:37:42+0000` (string) - 생성일
- link (object)
- rel: `self`
- href: `/v1/tags/laravel/articles` (string) - 상세 내용 요청을 위한 Api Endpoint
- articles: 1 (number) - 태그에 해당하는 게시글 개수
## Attachment (object)
- id: `95280986` (number) - 고유 키
- name: `kEvzc4qBPwEze1mi.jpg`
- created: `2015-12-19T10:37:42+0000` (string) - 생성일
- link (object)
- rel: `self`
- href: `http://myproject.dev:8000/attachments/kEvzc4qBPwEze1mi.jpg` (string) - 첨부파일 다운로드 URL
## Pagination
- pagination (object)
- total: `20` (number) - 전체 게시글 개수
- count: `5` (number) - 현재 응답의 게시글 개수
- per_page: `5` (number) - 요청당 응답할 게시글 개수
- current_page: `2` (number) - 현재 페이지 번호
- total_pages: `4` (number) - 총 페이지 수
- links (object)
- previous: `/v1/articles?page=1` (string) - 이전 페이지 URL
- next: `/v1/articles?page=3` (string) - 다음 페이지 URL