Skip to content

Latest commit

 

History

History
1143 lines (944 loc) · 21.9 KB

File metadata and controls

1143 lines (944 loc) · 21.9 KB

Ddaom API 명세

공통

응답 형식

모든 API는 아래 구조로 응답합니다.

{
  "code": "SUCCESS",
  "message": "성공",
  "data": { }
}

인증

🔒 표시된 API는 JWT 인증이 필요합니다.
요청 헤더에 아래를 포함해야 합니다.

Authorization: Bearer {token}

Auth

Google 로그인

POST /api/auth/google

Request Body

{
  "idToken": "Google ID Token"
}

Response Header

Authorization: Bearer {jwt_token}

Response Body

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "email": "user@example.com",
    "nickname": "홍길동",
    "profileImage": "https://...",
    "followerCount": 0,
    "followingCount": 0
  }
}

User

유저 프로필 조회

GET /api/users/{userId}

Path Variable

이름 타입 설명
userId Long 조회할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "email": "user@example.com",
    "nickname": "홍길동",
    "profileImage": "https://...",
    "followerCount": 10,
    "followingCount": 5
  }
}

내 정보 조회

GET /api/users/me 🔒

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "email": "user@example.com",
    "nickname": "홍길동",
    "profileImage": "https://...",
    "followerCount": 10,
    "followingCount": 5
  }
}

닉네임 변경

PATCH /api/users/me/nickname 🔒

Request Body

{
  "nickname": "새닉네임"
}

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "email": "user@example.com",
    "nickname": "새닉네임",
    "profileImage": "https://...",
    "followerCount": 10,
    "followingCount": 5
  }
}

프로필 이미지 변경

PATCH /api/users/me/profile-image 🔒

multipart/form-data로 요청합니다.

Request Parts

이름 타입 필수 설명
image File Y 변경할 프로필 이미지 파일

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "email": "user@example.com",
    "nickname": "홍길동",
    "profileImage": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/profile-images/abc123.jpg",
    "followerCount": 10,
    "followingCount": 5
  }
}

유저 검색

GET /api/users/search?query={query} 🔒

닉네임 또는 이메일로 검색합니다. 최대 20건 반환됩니다.

Query Parameter

이름 타입 필수 설명
query String Y 검색어 (닉네임 또는 이메일)

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "userId": 1,
      "email": "user@example.com",
      "nickname": "홍길동",
      "profileImage": "https://...",
      "me": false,
      "following": true
    }
  ]
}

Follow

팔로우

POST /api/follows/{followingId} 🔒

Path Variable

이름 타입 설명
followingId Long 팔로우할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

팔로우 취소

DELETE /api/follows/{followingId} 🔒

Path Variable

이름 타입 설명
followingId Long 팔로우 취소할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

팔로워 목록 조회

GET /api/follows/{userId}/followers 🔒

나를 팔로우하는 유저 목록입니다.

Path Variable

이름 타입 설명
userId Long 조회할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "userId": 2,
      "email": "user2@example.com",
      "nickname": "이순신",
      "profileImage": "https://...",
      "me": false,
      "following": false
    }
  ]
}

팔로잉 목록 조회

GET /api/follows/{userId}/followings 🔒

유저가 팔로우하는 목록입니다.

Path Variable

이름 타입 설명
userId Long 조회할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "userId": 3,
      "email": "user3@example.com",
      "nickname": "강감찬",
      "profileImage": "https://...",
      "me": false,
      "following": true
    }
  ]
}

팔로워/팔로잉 수 조회

GET /api/follows/{userId}/counts 🔒

Path Variable

이름 타입 설명
userId Long 조회할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "userId": 1,
    "followerCount": 10,
    "followingCount": 5
  }
}

Photo

사진 업로드

POST /api/photos 🔒

multipart/form-data로 요청합니다. request 파트는 Content-Type: application/json으로 전송합니다. 최대 업로드 크기는 파일 10MB, 요청 전체 12MB입니다.

Request Parts

이름 타입 필수 설명
image File Y 업로드할 이미지 파일
request JSON Y 사진 메타데이터

request JSON

{
  "photoSpotId": 1,
  "sourcePhotoId": 10,
  "tip": "오후 2시에 빛이 가장 예뻐요",
  "mood": "CALM",
  "timeTag": "AFTERNOON",
  "photoType": "LANDSCAPE",
  "crowdLevel": "RELAXED",
  "photoVisibility": "PUBLIC"
}
필드 타입 필수
photoSpotId Long N 포토스팟 ID
sourcePhotoId Long N 따오기 원본 사진 ID. 일반 업로드에서는 생략
tip String N 촬영 팁
mood Enum Y CALM COZY EMOTIONAL LONELY ROMANTIC DREAMY VINTAGE FRESH HEALING SENTIMENTAL MODERN CINEMATIC QUIET BRIGHT NIGHT NOSTALGIC
timeTag Enum Y MORNING AFTERNOON SUNSET NIGHT
photoType Enum Y FULL_BODY UPPER_BODY SELFIE FOOD LANDSCAPE ETC
crowdLevel Enum Y RELAXED NORMAL CROWDED HARD_TO_SHOOT
photoVisibility Enum Y PUBLIC FRIENDS PRIVATE

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "photoId": 1,
    "userId": 1,
    "photoSpotId": 1,
    "photoSpotTitle": "Main gate bench",
    "placeId": 1,
    "placeName": "Inha University",
    "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
    "tip": "오후 2시에 빛이 가장 예뻐요",
    "mood": "CALM",
    "timeTag": "AFTERNOON",
    "photoType": "LANDSCAPE",
    "crowdLevel": "RELAXED",
    "photoVisibility": "PUBLIC",
    "createdAt": "2026-06-09T12:00:00",
    "ddaomCount": 0
  }
}

사진 단건 조회

GET /api/photos/{photoId} 🔒

Path Variable

이름 타입 설명
photoId Long 조회할 사진 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "photoId": 1,
    "userId": 1,
    "photoSpotId": 1,
    "photoSpotTitle": "Main gate bench",
    "placeId": 1,
    "placeName": "Inha University",
    "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
    "tip": "오후 2시에 빛이 가장 예뻐요",
    "mood": "CALM",
    "timeTag": "AFTERNOON",
    "photoType": "LANDSCAPE",
    "crowdLevel": "RELAXED",
    "photoVisibility": "PUBLIC",
    "createdAt": "2026-06-09T12:00:00",
    "liked": false,
    "likeCount": 10,
    "ddaomCount": 3
  }
}

내 사진 목록 조회

GET /api/photos/me 🔒

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 1,
      "userId": 1,
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
      "tip": "오후 2시에 빛이 가장 예뻐요",
      "mood": "CALM",
      "timeTag": "AFTERNOON",
      "photoType": "LANDSCAPE",
      "crowdLevel": "RELAXED",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T12:00:00",
      "liked": false,
      "likeCount": 0
    }
  ]
}

유저 사진 목록 조회

GET /api/photos/users/{userId}

Path Variable

이름 타입 설명
userId Long 조회할 유저 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 1,
      "userId": 2,
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
      "tip": "오후 2시에 빛이 가장 예뻐요",
      "mood": "CALM",
      "timeTag": "AFTERNOON",
      "photoType": "LANDSCAPE",
      "crowdLevel": "RELAXED",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T12:00:00",
      "liked": false,
      "likeCount": 0
    }
  ]
}

팔로잉 사진 피드 조회

GET /api/photos/following 🔒

내가 팔로우하는 유저들이 최근 1주일간 올린 사진 목록을 최신순으로 반환합니다.

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 2,
      "userId": 3,
      "nickname": "이순신",
      "profileImage": "https://...",
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc456.jpg",
      "tip": "해질 무렵이 가장 예뻐요",
      "mood": "ROMANTIC",
      "timeTag": "SUNSET",
      "photoType": "LANDSCAPE",
      "crowdLevel": "NORMAL",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T18:30:00",
      "liked": false,
      "likeCount": 0
    }
  ]
}

장소별 사진 목록 조회

GET /api/photos?photoSpotId={photoSpotId} 🔒

Query Parameter

이름 타입 필수 설명
photoSpotId Long Y 조회할 포토스팟 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 1,
      "userId": 1,
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
      "tip": "오후 2시에 빛이 가장 예뻐요",
      "mood": "CALM",
      "timeTag": "AFTERNOON",
      "photoType": "LANDSCAPE",
      "crowdLevel": "RELAXED",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T12:00:00",
      "liked": false,
      "likeCount": 0
    }
  ]
}

인기 사진 목록 조회 (좋아요 TOP 12)

GET /api/photos/likes/top

최근 1주일간 좋아요가 가장 많은 사진을 최대 12개 반환합니다.

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 1,
      "userId": 1,
      "nickname": "홍길동",
      "profileImage": "https://...",
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
      "tip": "오후 2시에 빛이 가장 예뻐요",
      "mood": "CALM",
      "timeTag": "AFTERNOON",
      "photoType": "LANDSCAPE",
      "crowdLevel": "RELAXED",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T12:00:00",
      "liked": false,
      "likeCount": 0
    }
  ]
}

사진 좋아요

POST /api/photos/{photoId}/likes 🔒

Path Variable

이름 타입 설명
photoId Long 좋아요할 사진 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "photoId": 1,
    "liked": true,
    "likeCount": 10
  }
}

사진 좋아요 취소

DELETE /api/photos/{photoId}/likes 🔒

Path Variable

이름 타입 설명
photoId Long 좋아요 취소할 사진 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "photoId": 1,
    "liked": false,
    "likeCount": 9
  }
}

사진 삭제

DELETE /api/photos/{photoId} 🔒

사진 작성자만 삭제할 수 있습니다. 삭제 시 사진 좋아요/저장 참조를 먼저 정리한 뒤 Photo 레코드를 삭제합니다. S3에 저장된 이미지 객체도 함께 삭제를 시도합니다.

Path Variable

이름 타입 설명
photoId Long 삭제할 사진 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

내가 좋아요한 사진 목록 조회

GET /api/photos/likes/me 🔒

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "photoId": 1,
      "userId": 1,
      "photoSpotId": 1,
      "photoSpotTitle": "Main gate bench",
      "placeId": 1,
      "placeName": "Inha University",
      "photoUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photos/abc123.jpg",
      "tip": "오후 2시에 빛이 가장 예뻐요",
      "mood": "CALM",
      "timeTag": "AFTERNOON",
      "photoType": "LANDSCAPE",
      "crowdLevel": "RELAXED",
      "photoVisibility": "PUBLIC",
      "createdAt": "2026-06-09T12:00:00",
      "liked": true,
      "likeCount": 5
    }
  ]
}

Place

장소 등록

POST /api/places 🔒

Request Body

{
  "name": "경복궁",
  "address": "서울 종로구 사직로 161",
  "category": "문화유적",
  "latitude": 37.579617,
  "longitude": 126.977041
}
필드 타입 필수 설명
name String Y 장소명
address String Y 주소
category String Y 카테고리
latitude BigDecimal Y 위도
longitude BigDecimal Y 경도

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "placeId": 1,
    "name": "경복궁",
    "address": "서울 종로구 사직로 161",
    "category": "문화유적",
    "latitude": 37.579617,
    "longitude": 126.977041,
    "photoSpotCount": 0,
    "photoSpots": []
  }
}

장소 목록 조회 (지도)

GET /api/places 🔒

지도 화면의 범위(위경도)와 카테고리로 필터링합니다. 파라미터를 생략하면 전체 조회됩니다.

Query Parameters

이름 타입 필수 설명
minLatitude BigDecimal N 최소 위도
maxLatitude BigDecimal N 최대 위도
minLongitude BigDecimal N 최소 경도
maxLongitude BigDecimal N 최대 경도
category String N 카테고리

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "placeId": 1,
      "name": "경복궁",
      "address": "서울 종로구 사직로 161",
      "category": "문화유적",
      "latitude": 37.579617,
      "longitude": 126.977041,
      "photoSpotCount": 5,
      "thumbnailUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photo-spots/thumb.jpg"
    }
  ]
}

장소 상세 조회

GET /api/places/{placeId} 🔒

Path Variable

이름 타입 설명
placeId Long 조회할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "placeId": 1,
    "name": "경복궁",
    "address": "서울 종로구 사직로 161",
    "category": "문화유적",
    "latitude": 37.579617,
    "longitude": 126.977041,
    "photoSpotCount": 5,
    "photoSpots": [
      {
        "photoSpotId": 1,
        "title": "근정전 앞",
        "description": "정문에서 바라보는 근정전",
        "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photo-spots/spot1.jpg",
        "photoCount": 3
      }
    ],
    "saved": false
  }
}

장소 수정

PUT /api/places/{placeId} 🔒

Path Variable

이름 타입 설명
placeId Long 수정할 장소 ID

Request Body

{
  "name": "경복궁",
  "address": "서울 종로구 사직로 161",
  "category": "문화유적",
  "latitude": 37.579617,
  "longitude": 126.977041
}
필드 타입 필수 설명
name String Y 장소명
address String Y 주소
category String Y 카테고리
latitude BigDecimal Y 위도
longitude BigDecimal Y 경도

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "placeId": 1,
    "name": "경복궁",
    "address": "서울 종로구 사직로 161",
    "category": "문화유적",
    "latitude": 37.579617,
    "longitude": 126.977041,
    "photoSpotCount": 5,
    "photoSpots": [
      {
        "photoSpotId": 1,
        "title": "근정전 앞",
        "description": "정문에서 바라보는 근정전",
        "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photo-spots/spot1.jpg"
      }
    ]
  }
}

장소 삭제

DELETE /api/places/{placeId} 🔒

Path Variable

이름 타입 설명
placeId Long 삭제할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

장소 좋아요

POST /api/places/{placeId}/likes 🔒

Path Variable

이름 타입 설명
placeId Long 좋아요할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

장소 좋아요 취소

DELETE /api/places/{placeId}/likes 🔒

Path Variable

이름 타입 설명
placeId Long 좋아요 취소할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

내가 저장한 장소 목록 조회

GET /api/places/saves/me 🔒

저장한 최신순으로 반환합니다.

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": [
    {
      "placeId": 1,
      "name": "경복궁",
      "address": "서울 종로구 사직로 161",
      "category": "문화유적",
      "latitude": 37.579617,
      "longitude": 126.977041,
      "photoSpotCount": 5,
      "thumbnailUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photo-spots/thumb.jpg"
    }
  ]
}

장소 저장 (북마크)

POST /api/places/{placeId}/saves 🔒

Path Variable

이름 타입 설명
placeId Long 저장할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

장소 저장 취소

DELETE /api/places/{placeId}/saves 🔒

Path Variable

이름 타입 설명
placeId Long 저장 취소할 장소 ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

PhotoSpot 등록

POST /api/places/{placeId}/photo-spots 🔒

특정 Place에 PhotoSpot을 추가합니다.

두 가지 요청 방식을 지원합니다.

  • application/json: POST /api/uploads/images로 먼저 S3 URL을 받은 뒤 imageUrl로 전달합니다.
  • multipart/form-data: 이미지 파일을 직접 함께 전송하면 S3에 업로드한 뒤 반환된 URL을 저장합니다.

multipart 방식의 최대 업로드 크기는 파일 10MB, 요청 전체 12MB입니다.

Path Variable

이름 타입 설명
placeId Long PhotoSpot을 추가할 장소 ID

Request Body (application/json)

{
  "title": "근정전 앞",
  "description": "정면 구도로 찍기 좋은 위치",
  "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/uploads/images/example.jpg"
}

Request Parts (multipart/form-data)

이름 타입 필수 설명
image File Y PhotoSpot 대표 이미지 파일
request JSON Y PhotoSpot 메타데이터

request JSON

{
  "title": "근정전 앞",
  "description": "정면 구도로 찍기 좋은 위치"
}
필드 타입 필수 설명
title String Y PhotoSpot 이름
description String N PhotoSpot 설명
imageUrl String N JSON 요청에서 사용하는 이미지 URL

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "photoSpotId": 1,
    "title": "근정전 앞",
    "description": "정면 구도로 찍기 좋은 위치",
    "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/photo-spots/spot1.jpg"
  }
}

PhotoSpot 삭제

DELETE /api/places/{placeId}/photo-spots/{photoSpotId} 🔒

Path Variables

이름 타입 설명
placeId Long PhotoSpot이 속한 장소 ID
photoSpotId Long 삭제할 PhotoSpot ID

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": null
}

이미 사진이 등록된 PhotoSpot은 삭제할 수 없으며 400 응답을 반환합니다.

{
  "code": "E400",
  "message": "PhotoSpot has photos and cannot be deleted.",
  "data": null
}

Upload / S3

이미지 S3 업로드

POST /api/uploads/images 🔒

이미지 파일만 S3에 업로드하고 접근 가능한 URL을 반환합니다. 피드 게시물이나 PhotoSpot 레코드는 생성하지 않습니다.

multipart/form-data로 요청합니다. 최대 업로드 크기는 파일 10MB, 요청 전체 12MB입니다.

Request Parts

이름 타입 필수 설명
image File Y S3에 업로드할 이미지 파일

Response

{
  "code": "SUCCESS",
  "message": "성공",
  "data": {
    "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/uploads/images/example.jpg"
  }
}