1. 개요

인구감소 소도시 여행 코스 서비스 TripPick의 백엔드 API 문서입니다.

이 문서의 요청/응답 예시는 테스트 실행 중 실제로 오간 것을 그대로 담습니다. 코드가 바뀌면 문서도 같이 바뀌고, 문서와 코드가 어긋나면 테스트가 실패합니다.

1.1. 기본 정보

항목

개발계 서버

https://trippick.kro.kr — 아래 요청 예시의 기준입니다

로컬 서버

http://localhost:8080

요청/응답 형식

application/json (UTF-8)

인증

카카오 로그인으로 받은 토큰을 Authorization: Bearer {accessToken} 헤더에 넣습니다. 인증 참고

1.2. 오류 응답 형식

모든 오류는 상태 코드와 무관하게 아래 한 가지 형태로 옵니다.

{
  "code": "REGION_AMBIGUOUS",
  "message": "'고성군'는 여러 시도에 있습니다. province를 함께 지정해 주세요.",
  "details": ["강원특별자치도 고성군", "경상남도 고성군"]
}

분기는 message`가 아니라 `code`로 하세요. `400 하나에 원인이 여러 가지라 상태 코드만으로는 구분되지 않습니다. code`는 바뀌지 않는 계약이고, `message 문구는 다듬어질 수 있습니다.

`details`는 보조 정보입니다. 대부분 비어 있고, 지역명이 모호할 때처럼 고를 수 있는 후보가 있으면 채워집니다.

상태 코드 code 의미

400

REGION_NAME_REQUIRED

`generate-by-name`에 `regionName`을 보내지 않음

400

REGION_INPUT_REQUIRED

generate`에 `regionId`와 `terrains(산/바다)가 모두 비어 있음. 지역을 정할 근거가 없음

400

REGION_NOT_FOUND_FOR_TERRAIN

선택한 지형으로 분류된 소도시가 없음. 분류 시드(V4) 문제이므로 정상 요청에서는 나오지 않아야 함

400

REGION_NOT_FOUND

지원하지 않는 지역. 없는 `regionId`거나, 소도시 목록에 없는 이름이거나 `province`와 맞지 않음

400

REGION_AMBIGUOUS

같은 이름의 시군구가 여러 시도에 있음. `details`의 후보를 보여주고 `province`를 받아 다시 요청

400

COURSE_INVALID_REQUEST

지원하지 않는 테마·지형이거나 여행 일수가 범위(1~3)를 벗어남

400

AUTH_INVALID_REQUEST

로그인 요청 값이 잘못됨. 인가코드(code)가 비어 있는 경우

400

INVALID_REQUEST_BODY

본문이 없거나 JSON이 깨짐

400

BAD_REQUEST

그 밖의 잘못된 요청

401

AUTH_REQUIRED

토큰이 없거나, 만료됐거나, 신뢰할 수 없음. 카카오 로그인부터 다시

401

KAKAO_AUTH_FAILED

인가코드가 무효·만료됐거나 이미 사용됨. 카카오 로그인부터 다시

404

ENDPOINT_NOT_FOUND

없는 경로

405

METHOD_NOT_ALLOWED

지원하지 않는 HTTP 메서드

415

UNSUPPORTED_MEDIA_TYPE

지원하지 않는 Content-Type

500

INTERNAL_ERROR

서버 오류

502

TOUR_API_UNAVAILABLE

TourAPI 장애로 관광 정보를 가져오지 못함. 재시도 안내가 적절함

502

KAKAO_UNAVAILABLE

카카오 서버 장애·타임아웃으로 로그인을 마치지 못함. 재시도 안내가 적절함

2. 인증

카카오 로그인으로 우리 서비스 토큰을 받고, 이후 요청에 그 토큰을 실어 보냅니다.

2.1. 로그인 흐름

프론트는 카카오 인가코드까지만 받고, 토큰 교환부터는 백엔드가 처리합니다. 카카오 REST API 키와 시크릿이 프론트에 노출되지 않도록 하기 위해서입니다.

  1. 프론트: 카카오 로그인 화면으로 이동, 사용자가 로그인하고 동의

  2. 카카오: redirect_uri?code=…​ 를 붙여 프론트로 돌려보냄

  3. 프론트: 그 code카카오 로그인 API로 전달

  4. 백엔드: 카카오와 토큰을 교환하고 사용자 정보를 조회해 로그인 또는 회원가입

  5. 백엔드: 우리 서비스 access token 발급

redirect_uri 는 프론트가 인가코드를 받을 때 쓴 값과 서버 설정값이 정확히 같아야 합니다. 한 글자라도 다르면 카카오가 토큰 교환을 거부해 401 KAKAO_AUTH_FAILED 가 옵니다.

인가코드는 일회용입니다. 같은 code 로 두 번 요청하면 두 번째는 401 KAKAO_AUTH_FAILED 입니다. 새로고침이나 재시도로 같은 코드를 다시 보내지 않도록 주의하세요.

닉네임은 카카오 선택 동의 항목이라 사용자가 거부하면 내려오지 않습니다. 이 경우 백엔드가 사용자 + 임의의 숫자 6자리로 기본 닉네임을 만들어 가입시킵니다. 닉네임은 가입할 때만 저장되므로, 이미 가입한 사용자가 나중에 동의해도 기존 닉네임이 유지됩니다.

2.2. 카카오 로그인

인가코드를 우리 서비스 토큰으로 바꿉니다. 가입 여부는 백엔드가 판단하므로 로그인과 회원가입을 프론트에서 구분할 필요가 없습니다. 처음 오는 사용자면 자동으로 가입됩니다.

2.2.1. 요청

POST /api/v1/auth/kakao/login HTTP/1.1
Content-Type: application/json
Content-Length: 57
Host: trippick.kro.kr

{
  "code" : "rqg8rCME_1nE__HG65-ARfKBAnuhIhmOITUfDBrp"
}
Path Type Description

code

String

카카오 인가코드. 카카오 로그인 후 redirect_uri로 돌아올 때 쿼리스트링으로 받은 code를 그대로 넣는다. 일회용이라 재사용하면 401이 온다. 토큰 교환에 쓰는 redirect_uri는 서버 설정값이므로 인가코드를 받을 때 쓴 값과 정확히 같아야 한다

curl 예시
$ curl 'https://trippick.kro.kr/api/v1/auth/kakao/login' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{
  "code" : "rqg8rCME_1nE__HG65-ARfKBAnuhIhmOITUfDBrp"
}'

2.2.2. 응답

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 253

{
  "accessToken" : "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTdmYjhkZi04MDE2LTQxM2UtYmNiNC0yZjJhODgzNGRjYzYiLCJpYXQiOjE3ODU2ODQwMDAsImV4cCI6MTc4NTY5MTIwMH0.Zm9yLWRvY3VtZW50YXRpb24tb25seS1zaWduYXR1cmUtc2FtcGxl",
  "tokenType" : "Bearer",
  "expiresIn" : 7200
}
Path Type Description

accessToken

String

우리 서비스 access token. 이후 요청의 Authorization 헤더에 실어 보낸다

tokenType

String

항상 Bearer. Authorization 헤더에 붙일 접두사다. Authorization: Bearer {accessToken}

expiresIn

Number

만료까지 남은 시간(초). 현재 7200(2시간). 리프레시 토큰이 없으므로 만료되면 카카오 로그인부터 다시 해야 한다

2.3. 토큰 사용

발급받은 accessToken 을 이후 요청의 Authorization 헤더에 넣습니다.

GET /api/v1/some-protected-api HTTP/1.1
Host: trippick.kro.kr
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTdmYjhkZi04...

리프레시 토큰이 없습니다. 토큰이 만료되면(발급 후 2시간) 카카오 로그인부터 다시 해야 합니다. 응답의 expiresIn 을 보고 만료 전에 재로그인을 유도하세요.

토큰이 없거나, 만료됐거나, 서명이 맞지 않으면 모두 401 AUTH_REQUIRED 로 응답합니다. 원인을 구분해 알려주지 않습니다 — 공격자에게 힌트가 되기 때문입니다.

{
  "code": "AUTH_REQUIRED",
  "message": "로그인이 필요합니다.",
  "details": []
}

2.3.1. 인증이 필요 없는 경로

아래는 토큰 없이 호출할 수 있습니다. 그 밖의 모든 경로는 토큰이 필요합니다.

경로 비고

POST /api/v1/auth/**

로그인. 토큰을 받기 전 단계라 열려 있음

GET /api/v1/regions/**

소도시 목록

/api/v1/courses/**

코스 생성. 아래 안내 참고

/actuator/health

헬스체크

코스 API는 한시적으로만 공개입니다.

로그인이 방금 추가되어 프론트가 아직 토큰을 붙이지 않았기 때문에, 지금 잠그면 코스 기능이 곧바로 멈춥니다. 그래서 연동 기간 동안만 열어 둔 상태입니다.

로그인 연동이 끝나면 코스 API도 토큰 필수로 전환합니다. 코스를 호출하는 코드에도 Authorization 헤더를 함께 넣어 두시면 전환 시점에 따로 손댈 일이 없습니다.

2.4. 로그인 실패

인가코드에 문제가 있으면 401, 카카오 쪽 장애면 502 로 구분해 응답합니다. 프론트 대응이 정반대이므로 반드시 나눠서 처리하세요401 은 재로그인, 502 는 잠시 후 재시도입니다.

2.4.1. 인가코드가 무효한 경우

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 141

{
  "code" : "KAKAO_AUTH_FAILED",
  "message" : "카카오 인증에 실패했습니다. 다시 로그인해 주세요.",
  "details" : [ ]
}
Path Type Description

code

String

오류 식별자. 분기는 메시지가 아니라 이 값으로 한다. 목록은 오류 응답 형식 참고

message

String

사용자에게 보여줄 설명. 문구는 바뀔 수 있다

details

Array

보조 정보. 이 오류에서는 비어 있다

2.4.2. 카카오 장애

카카오 서버 오류, 타임아웃, 예상치 못한 응답 형식이 모두 여기에 해당합니다. 사용자 잘못이 아니므로 재로그인을 유도하지 마세요.

HTTP/1.1 502 Bad Gateway
Content-Type: application/json
Content-Length: 156

{
  "code" : "KAKAO_UNAVAILABLE",
  "message" : "카카오 서버가 응답하지 않습니다. 잠시 후 다시 시도해 주세요.",
  "details" : [ ]
}

3. 지역

3.1. 소도시 목록 조회

코스를 만들 수 있는 소도시 목록입니다. 지역 선택 화면을 채울 때 사용합니다. 여기서 받은 `name`과 `province`를 그대로 코스 생성 요청에 넣으면 됩니다.

3.1.1. 요청

GET /api/v1/regions/small-cities HTTP/1.1
Host: trippick.kro.kr

3.1.2. 응답

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 387

[ {
  "id" : "8b1f0d6e-3c7a-4a1e-9a2b-6f0c5d4e3a21",
  "name" : "평창군",
  "province" : "강원특별자치도",
  "population" : 39897,
  "smallCity" : true,
  "populationDeclineArea" : true
}, {
  "id" : "2c9a7b41-5d3e-4c8f-b0a6-1e2d3c4b5a60",
  "name" : "단양군",
  "province" : "충청북도",
  "population" : 26628,
  "smallCity" : true,
  "populationDeclineArea" : true
} ]
Path Type Description

[].id

String

지역 식별자

[].name

String

시군구명. 코스 생성 요청의 regionName에 그대로 넣으면 된다

[].province

String

시도명. 같은 이름의 시군구가 있을 때 코스 생성 요청의 province에 넣는다

[].population

Number

주민등록인구

[].smallCity

Boolean

소도시 여부. 이 목록은 항상 true

[].populationDeclineArea

Boolean

인구감소지역 여부

4. 코스

4.1. 코스 생성

지역·테마·지형·기간을 받아 Day별 일정을 만들어 돌려줍니다. 호출할 때마다 한국관광공사 TourAPI를 실시간으로 조회하므로 응답에 1~2초가 걸립니다.

알아둘 점
  • `themes`는 고른 순서가 가중치입니다. `["미식", "힐링"]`과 `["힐링", "미식"]`은 다른 코스가 나옵니다.

  • 테마를 고르지 않아도 코스는 나옵니다. 테마는 후보의 *순위*를 정할 뿐, 명소·식사·숙소는 항상 확보합니다.

  • `themes`와 `terrains`는 작동 방식이 다릅니다. 테마는 순위를 바꾸고(예: '미식’은 카페보다 한식당을 위로), 지형은 관광지 후보를 걸러냅니다('바다’면 해수욕장·해안절경 등만 남김).

  • 지형에 맞는 곳이 부족하면 다른 장소로 채우고 `warnings`로 이유를 알립니다. 아예 없으면 지형 조건을 무시하고 평범한 코스를 만듭니다 — 내륙 소도시에서 '바다’를 골라도 빈 코스가 나오지 않습니다.

  • 테마가 하루 구성을 바꿉니다. 힐링은 간격이 넓어 체류시간이 길고(5자리), 액티비티는 명소가 더 많고(7자리), 미식은 카페 자리가 추가됩니다(6자리). 로컬·미지정은 기본 5자리입니다.

  • 가볼 만한 곳이 넉넉하지 않은 소도시에서는 자리를 줄여서 내보내고 `warnings`로 알립니다.

  • 마지막 날에는 숙소가 들어가지 않습니다(귀가).

  • 자리 분기는 seatId`로 하세요. `slot`은 화면에 보여줄 이름이라 문구가 바뀔 수 있습니다. `STAY(숙소)·CAFE(카페)처럼 특정 자리를 골라내야 하면 `seatId`를 쓰세요. 오류 응답의 `code`와 같은 원칙입니다.

  • 숙소는 여행 내내 같은 곳입니다. 2박이면 1일차와 2일차 숙소 항목의 `contentId`가 같습니다. 숙소를 뺀 나머지 장소는 코스에 두 번 나오지 않습니다.

  • 코스는 그 소도시 안에서의 일정만 담습니다. 출발지에서 가는 길, 마지막 날 돌아오는 길은 포함되지 않습니다. 그날 첫 항목의 `travelMinutesFromPrevious`가 `null`인 것도 같은 이유입니다(직전 장소가 없음).

  • 좌표가 없는 장소는 코스에 넣지 않습니다.

  • 시간과 이동 시간은 실측이 아니라 고정 예측치입니다. 동선 최적화는 후속 작업입니다.

  • 코스가 만들어져도 `warnings`가 채워질 수 있습니다. 오류가 아니라 참고 사항이니 화면에 노출할지 판단해 주세요.

  • 지역을 지정하는 방법이 셋입니다. 이 API는 그중 둘을 받습니다.

    regionId

    소도시 목록 API 응답의 id. 목록·자동완성에서 고른 경우 이걸 보내세요

    `terrains`만

    산/바다 버튼만 누른 경우. 서버가 해당 지형의 소도시 중 하나를 고릅니다

    사용자가 지역명을 직접 타이핑하는 화면이면 지역명으로 코스 생성을 쓰세요.

    regionId`를 보내면 `terrains`는 후보 필터로만 쓰입니다. 비우면 지역 선정에도 쓰이고, 고른 뒤에도 같은 필터를 겁니다. 매핑은 `regions.is_mountain/`is_sea`이며 TourAPI 자연관광지 분포로 산출했습니다.

  • 버튼으로 고른 지역은 매번 달라질 수 있습니다. 후보 중 무작위로 하나를 뽑기 때문에 같은 요청이라도 결과가 다릅니다. 어떤 지역이 뽑혔는지는 응답의 `region`을 보세요.

4.1.1. 요청

POST /api/v1/courses/generate HTTP/1.1
Content-Type: application/json
Content-Length: 134
Host: trippick.kro.kr

{
  "regionId" : "3f2a1c40-0000-0000-0000-000000000015",
  "themes" : [ "힐링", "미식" ],
  "terrains" : [ "산" ],
  "days" : 2
}
Path Type Description

regionId

String

지역 식별자. 소도시 목록 API 응답의 id를 그대로 넣는다. 생략하면 terrains(산/바다)에 매핑된 소도시 중에서 서버가 하나를 고른다. regionId와 terrains가 모두 비면 REGION_INPUT_REQUIRED

themes

Array

여행 테마. 미식 | 힐링 | 액티비티 | 로컬 (영문 GOURMET | HEALING | ACTIVITY | LOCAL도 받는다). 고른 순서가 가중치다 — 먼저 고를수록 반영이 커진다

terrains

Array

지형. 산 | 바다 (영문 MOUNTAIN | SEA도 받는다). 역할이 둘이다. ① 테마와 달리 관광지 후보를 걸러낸다 — 부족하면 다른 장소로 채우고 warnings로 알린다. ② regionId가 비었을 때 지역 선정에도 쓰인다 — 그 지형의 소도시 중 하나를 고른다

days

Number

여행 일수. 1~3. 생략하면 1

curl 예시
$ curl 'https://trippick.kro.kr/api/v1/courses/generate' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{
  "regionId" : "3f2a1c40-0000-0000-0000-000000000015",
  "themes" : [ "힐링", "미식" ],
  "terrains" : [ "산" ],
  "days" : 2
}'

4.1.2. 응답

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1958

{
  "region" : {
    "name" : "평창군",
    "province" : "강원특별자치도",
    "areaCode" : "32",
    "sigunguCode" : "15",
    "smallCity" : true,
    "populationDeclineArea" : true
  },
  "themes" : [ "힐링", "미식" ],
  "terrains" : [ "산" ],
  "days" : 2,
  "plan" : [ {
    "day" : 1,
    "items" : [ {
      "order" : 1,
      "seatId" : "MORNING_SPOT",
      "slot" : "오전 일정",
      "startTime" : "09:00",
      "travelMinutesFromPrevious" : null,
      "contentId" : "125591",
      "title" : "오대산국립공원",
      "contentTypeId" : 12,
      "contentType" : "TOURIST_SPOT",
      "address" : "강원특별자치도 평창군 진부면 오대산로 2",
      "lat" : 37.7029269542,
      "lng" : 128.6021975495,
      "imageUrl" : "http://tong.visitkorea.or.kr/cms/resource/82/3549482_image2_1.jpg",
      "tel" : null
    }, {
      "order" : 2,
      "seatId" : "LUNCH",
      "slot" : "점심",
      "startTime" : "12:00",
      "travelMinutesFromPrevious" : 22,
      "contentId" : "2721447",
      "title" : "청산회관",
      "contentTypeId" : 39,
      "contentType" : "RESTAURANT",
      "address" : "강원특별자치도 평창군 진부면 진부중앙로 51",
      "lat" : 37.644,
      "lng" : 128.554,
      "imageUrl" : "http://tong.visitkorea.or.kr/cms/resource/82/3549482_image2_1.jpg",
      "tel" : null
    } ]
  }, {
    "day" : 2,
    "items" : [ {
      "order" : 1,
      "seatId" : "MORNING_SPOT",
      "slot" : "오전 일정",
      "startTime" : "09:00",
      "travelMinutesFromPrevious" : null,
      "contentId" : "2645678",
      "title" : "장전계곡",
      "contentTypeId" : 12,
      "contentType" : "TOURIST_SPOT",
      "address" : "강원특별자치도 평창군 진부면 장전리",
      "lat" : 37.69,
      "lng" : 128.53,
      "imageUrl" : "http://tong.visitkorea.or.kr/cms/resource/82/3549482_image2_1.jpg",
      "tel" : null
    } ]
  } ],
  "warnings" : [ ]
}
Path Type Description

region.name

String

시군구명

region.province

String

시도명

region.areaCode

String

TourAPI 시도코드

region.sigunguCode

String

TourAPI 시군구코드

region.smallCity

Boolean

소도시 여부

region.populationDeclineArea

Boolean

인구감소지역 여부

themes

Array

해석된 테마 목록

terrains

Array

해석된 지형 목록

days

Number

여행 일수

plan[].day

Number

며칠째인지. 1부터

plan[].items[].order

Number

그날 안에서의 순서. 1부터

plan[].items[].seatId

String

자리 식별자. 화면 분기는 표시 문자열이 아니라 이 값으로 한다. MORNING_SPOT | MORNING_SPOT_2 | LUNCH | CAFE | AFTERNOON_SPOT | AFTERNOON_SPOT_2 | DINNER | STAY

plan[].items[].slot

String

일정 자리 이름. 고른 테마에 따라 구성이 달라진다(예: 액티비티는 '오전 일정 2’가 추가, 미식은 '카페’가 추가). 숙소는 여행 내내 같은 곳이라 날마다 반복된다

plan[].items[].startTime

String

시작 시각(HH:mm). 고정 예측치

plan[].items[].travelMinutesFromPrevious

Number

직전 장소에서의 이동 시간(분). 직선거리 기반 예측치이며 그날 첫 항목은 null

plan[].items[].contentId

String

TourAPI 콘텐츠 ID

plan[].items[].title

String

장소명

plan[].items[].contentTypeId

Number

TourAPI 콘텐츠 타입 ID. 12 관광지 / 14 문화시설 / 28 레포츠 / 32 숙박 / 39 음식점

plan[].items[].contentType

String

콘텐츠 타입 이름

plan[].items[].address

String

주소

plan[].items[].lat

Number

위도. 좌표 없는 장소는 코스에 넣지 않는다

plan[].items[].lng

Number

경도

plan[].items[].imageUrl

String

대표 이미지 URL

plan[].items[].tel

String

전화번호. 없으면 null

warnings

Array

코스는 만들어졌지만 알아야 할 사항. 후보 부족으로 인근 지역까지 넓혀 조회했거나 채우지 못한 자리가 있을 때 채워진다

4.2. 지역명으로 코스 생성

사용자가 직접 타이핑한 지역명을 받는 경로입니다.

현재는 이름이 정확히 일치해야 합니다. 평창·`강원도 평창군`은 찾지 못하고 `평창군`이어야 합니다. 자동완성 UI가 있다면 코스 생성에 `regionId`를 보내는 쪽이 안전합니다. 부분 일치·오타 허용은 후속 과제입니다.

같은 이름의 시군구가 여러 시도에 있으면(예: 고성군) REGION_AMBIGUOUS`로 후보를 돌려줍니다. `province`를 함께 받아 다시 요청하세요. `regionId 경로에는 이 문제가 없습니다.

이 경로에서는 terrains`가 후보 필터로만 쓰입니다 — 지역은 이름으로 이미 정해졌습니다. `themes·`days`의 의미와 응답 형태는 코스 생성과 같습니다.

4.2.1. 요청

POST /api/v1/courses/generate-by-name HTTP/1.1
Content-Type: application/json
Content-Length: 149
Host: trippick.kro.kr

{
  "regionName" : "평창군",
  "province" : "강원특별자치도",
  "themes" : [ "힐링", "미식" ],
  "terrains" : [ "산" ],
  "days" : 2
}
Path Type Description

regionName

String

사용자가 입력한 시군구명. 현재는 정확히 일치해야 한다 — '평창’은 찾지 못하고 '평창군’이어야 한다

province

String

시도명. 같은 이름의 시군구가 여러 시도에 있을 때 필요하다(예: 고성군). 유일하면 생략 가능

themes

Array

generate와 동일

terrains

Array

generate와 동일하나 후보 필터로만 쓰인다 — 지역은 regionName으로 이미 정해졌다

days

Number

generate와 동일

4.3. 지역코드로 코스 생성

지역명 대신 TourAPI 지역코드를 직접 주는 경로입니다. regions 테이블을 거치지 않습니다.

일반적인 화면 흐름에서는 코스 생성을 쓰세요. 이 경로는 지역 해석 없이 TourAPI 조회·조립만 확인하고 싶을 때, 또는 지역코드를 이미 알고 있을 때 씁니다. 개발·디버깅용이라 `@Profile("!prod")`로 막혀 있어 운영에서는 열리지 않습니다.

regions`를 거치지 않으므로 소도시 여부를 확인하지 않습니다. 소도시가 아닌 코드로도 코스가 만들어지고, 응답의 `region.name·`region.smallCity`는 항상 `null`입니다.

themes·terrains·`days`의 의미와 응답 형태는 코스 생성과 완전히 같습니다.

4.3.1. 요청

POST /api/v1/courses/generate-by-code HTTP/1.1
Content-Type: application/json
Content-Length: 114
Host: trippick.kro.kr

{
  "areaCode" : "32",
  "sigunguCode" : "15",
  "themes" : [ "힐링" ],
  "terrains" : [ "산" ],
  "days" : 1
}
Path Type Description

areaCode

String

TourAPI 시도코드. 예: 32(강원)

sigunguCode

String

TourAPI 시군구코드. 생략하면 시도 전체에서 찾는다

themes

Array

코스 생성과 동일

terrains

Array

코스 생성과 동일

days

Number

코스 생성과 동일

4.3.2. 응답

지역 관련 필드만 다릅니다. 나머지는 코스 생성의 응답을 참고하세요.

Path Type Description

region.name

String

regions 테이블을 거치지 않으므로 항상 null

region.areaCode

String

요청에 준 값 그대로

region.smallCity

Boolean

소도시 여부를 확인하지 않으므로 항상 null

4.4. 지역명이 모호한 경우

같은 이름의 시군구가 여러 시도에 있으면(예: 고성군 — 강원특별자치도·경상남도) `400`과 함께 후보를 돌려줍니다. 사용자에게 후보를 보여주고 고르게 한 뒤 `province`를 채워 다시 요청하세요.

HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 215

{
  "code" : "REGION_AMBIGUOUS",
  "message" : "'고성군'는 여러 시도에 있습니다. province를 함께 지정해 주세요.",
  "details" : [ "강원특별자치도 고성군", "경상남도 고성군" ]
}
Path Type Description

code

String

오류 식별자. 분기는 메시지가 아니라 이 값으로 한다. 목록은 오류 응답 형식 참고

message

String

사용자에게 보여줄 설명. 문구는 바뀔 수 있다

details

Array

보조 정보. 지역명이 모호하면 고를 수 있는 후보가 들어온다