Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add swagger #45

Merged
merged 33 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0f36a8a
Add swagger dependency
BucketOnHead Oct 17, 2023
2ae4531
Add GET /users docs
BucketOnHead Oct 17, 2023
05148ba
Add POST /users docs
BucketOnHead Oct 17, 2023
1d0e4af
Add GET /users/{userId} docs
BucketOnHead Oct 17, 2023
8682107
Fix typos
BucketOnHead Oct 18, 2023
25961ad
Add DELETE /users/{userId} docs
BucketOnHead Oct 18, 2023
e961163
Add PATCH /users/{userId} docs
BucketOnHead Oct 18, 2023
8c63b7d
Fix typos
BucketOnHead Oct 18, 2023
54c9229
Delete unused import
BucketOnHead Oct 18, 2023
9e0ad74
Update user docs
BucketOnHead Oct 18, 2023
5698206
Refactor methods in CRUD order
BucketOnHead Oct 18, 2023
71c2af8
Fix typo
BucketOnHead Oct 18, 2023
427590f
Refactor OpenApiConsts
BucketOnHead Oct 18, 2023
4f9172f
Refactor UserCreationDto style
BucketOnHead Oct 18, 2023
a63074e
Add GET /requests docs
BucketOnHead Oct 18, 2023
bb40b19
Add GET /requests/{itemRequestId} docs
BucketOnHead Oct 18, 2023
697bd1d
Add GET /requests/all docs
BucketOnHead Oct 18, 2023
a3a15d8
Add GET /requests 404 response docs
BucketOnHead Oct 18, 2023
7c75eab
Use static import
BucketOnHead Oct 18, 2023
6fb4051
Add GET /items docs
BucketOnHead Oct 18, 2023
4e37073
Add POST /items docs
BucketOnHead Oct 18, 2023
eb06c9e
Add POST /items/{itemId}/comment docs
BucketOnHead Oct 19, 2023
6dc4ad6
Add GET /items/{itemId} docs
BucketOnHead Oct 19, 2023
a3a133c
Add GET /items/search docs
BucketOnHead Oct 19, 2023
e98a909
Add GET /bookings docs
BucketOnHead Oct 19, 2023
5fe6aaa
Add POST /bookings docs
BucketOnHead Oct 19, 2023
73a5f5e
Add GET /bookings/{bookingId} docs
BucketOnHead Oct 19, 2023
8867726
Add PATCH /bookings/{bookingId} docs
BucketOnHead Oct 19, 2023
e59c8f4
Add GET /bookings/owner docs
BucketOnHead Oct 19, 2023
8e3d070
Add GET /bookings/owner docs
BucketOnHead Oct 19, 2023
544ec9e
Merge remote-tracking branch 'origin/add-swagger' into add-swagger
BucketOnHead Oct 19, 2023
fa41b11
Add open api file.yaml
BucketOnHead Oct 19, 2023
94662f9
Update README.md
BucketOnHead Oct 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ItemDetailsDto getItemById(Long itemId, Long userId) {
.block();
}

public List<ItemDetailsDto> getItemsByOwnerId(Long userId, Integer from, Integer size) {
public List<ItemDetailsDto> getItemsByUserId(Long userId, Integer from, Integer size) {
return client.get()
.uri(builder -> builder.path("/items")
.queryParam("from", from)
Expand All @@ -57,7 +57,7 @@ public List<ItemDetailsDto> getItemsByOwnerId(Long userId, Integer from, Integer
.block();
}

public List<ItemDto> searchItemsByNameOrDescription(String text, Integer from, Integer size) {
public List<ItemDto> getItemsByText(String text, Integer from, Integer size) {
return client.get()
.uri(builder -> builder.path("/items/search")
.queryParam("text", text)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ItemRequestDto getItemRequestById(Long itemRequestId, Long userId) {
.block();
}

public List<ItemRequestDto> getItemRequestsByRequesterId(Long userId, Integer from, Integer size) {
public List<ItemRequestDto> getItemRequests(Long userId, Integer from, Integer size) {
return client.get()
.uri(builder -> builder.path("/requests/all")
.queryParam("from", from)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,24 @@ public UserDto addUser(UserCreationDto userDto) {
.block();
}

public UserDto updateUser(UserCreationDto userDto, Long userId) {
return client.patch()
public UserDto getUserById(Long userId) {
return client.get()
.uri("/users/{id}", userId)
.bodyValue(userDto)
.retrieve()
.bodyToMono(UserDto.class)
.block();
}

public UserDto getUserById(Long userId) {
return client.get()
public UserDto updateUser(UserCreationDto userDto, Long userId) {
return client.patch()
.uri("/users/{id}", userId)
.bodyValue(userDto)
.retrieve()
.bodyToMono(UserDto.class)
.block();
}


public List<UserDto> getAllUsers(Integer from, Integer size) {
public List<UserDto> getUsers(Integer from, Integer size) {
return client.get()
.uri(builder -> builder.path("/users")
.queryParam("from", from)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package ru.practicum.shareit.server.constants;

import lombok.experimental.UtilityClass;

/**
* name = description
* <p>
* EG (exempli gratia) = example
*/
@UtilityClass
public class OpenApiConsts {

@UtilityClass
public static class Param {
public static final String FROM = "Количество элементов, которые нужно пропустить для формирования текущего набора";
public static final String SIZE = "Количество элементов в наборе";
public static final String USER_ID = "Идентификатор пользователя";
public static final String ITEM_REQUEST_ID = "Идентификатор запроса вещи";
public static final String ITEM_ID = "Идентификатор вещи";
public static final String FROM_EG = "10";
public static final String SIZE_EG = "20";
public static final String USER_ID_EG = User.ID_EG;
public static final String ITEM_REQUEST_ID_EG = ItemRequest.ID_EG;
public static final String ITEM_ID_EG = Item.ID_EG;
}

@UtilityClass
public static class User {
public static final String ID = "Идентификатор";
public static final String NAME = "Имя";
public static final String EMAIL = "Адрес электронной почты";
public static final String ID_EG = "1";
public static final String NAME_EG = "Вася Уточкин";
public static final String EMAIL_EG = "vasya.utochkin@example.org";
}

@UtilityClass
public static class Item {
public static final String ID = "Идентификатор";
public static final String NAME = "Название";
public static final String DESCRIPTION = "Описание";
public static final String IS_AVAILABLE = "Доступность";
public static final String REQUEST_ID = "Идентификатор запроса";
public static final String ID_EG = "4";
public static final String NAME_EG = "Щётка для обуви";
public static final String DESCRIPTION_EG = "Стандартная щётка для обуви";
public static final String IS_AVAILABLE_EG = "true";
public static final String REQUEST_ID_EG = ItemRequest.ID_EG;
}

@UtilityClass
public static class ItemRequest {
public static final String ID = "Идентификатор";
public static final String DESCRIPTION = "Описание";
public static final String CREATED = "Дата и время создания";
public static final String ITEMS = "Вещи, добавленные по запросу";
public static final String ID_EG = "1";
public static final String DESCRIPTION_EG = "Хотел бы воспользоваться щёткой для обуви";
}

@UtilityClass
public static class Booking {
public static final String ID = "Идентификатор";
public static final String ID_EG = "5";
}

@UtilityClass
public static class Comment {
public static final String ID = "Идентификатор";
public static final String TEXT = "Текст комментария";
public static final String AUTHOR_NAME = "Имя автора";
public static final String CREATED = "Дата и время создания";
public static final String ID_EG = "7";
public static final String TEXT_EG = "Все прошло хорошо, рекомендую!";
public static final String AUTHOR_NAME_EG = User.NAME_EG;
}

@UtilityClass
public static class ApiError {
public static final String STATUS = "статус HTTP-ответа";
public static final String REASON = "Общее описание ошибки";
public static final String MESSAGE = "Сообщение об ошибке";
public static final String TIMESTAMP = "Дата и время когда произошла ошибка";
public static final String ERRORS = "Сопутствующие ошибки или иная информация(вложенные ошибки, стектрейсы и пр.)";
public static final String STATUS_EG = "BAD_REQUEST";
public static final String REASON_EG = "Request cannot be understood by the server due to incorrect syntax";
public static final String MESSAGE_EG = "Unknown state: ABC";
public static final String ERRORS_EG = "[" +
"\"parameter 'size' must be greater than 0, but it was '0'\"," +
"\"parameter 'from' must be greater than or equal to 0, but it was '-1'\"" +
"]";
}

@UtilityClass
public static class Response {

public static final String GET_PAGINATION_BAD_REQUEST = "{" +
"\"status\":\"BAD_REQUEST\"," +
"\"reason\":\"Bad Request\"," +
"\"message\":\"Parameter(s) failed validation\"," +
"\"errors\":[" +
"\"parameter 'size' must be greater than 0, but it was '0'\"," +
"\"parameter 'from' must be greater than or equal to 0, but it was '-1'\"" +
"]," +
"\"timestamp\":\"2023-10-17T16:59:11.237789\"" +
"}";

public static final String POST_USER_BAD_REQUEST = "{" +
"\"status\":\"BAD_REQUEST\"," +
"\"reason\":\"Bad Request\"," +
"\"message\":\"Field(s) failed validation\"," +
"\"errors\":[" +
"\"field 'email' must have the format of an email address, but it was 'vasyaexample.com'\"" +
"]," +
"\"timestamp\":\"2023-10-17T19:12:12.08784\"" +
"}";

public static final String POST_USER_CONFLICT = "{" +
"\"status\":\"CONFLICT\"," +
"\"reason\":\"Request conflicts with another request or with server configuration\"," +
"\"message\":\"User email must be unique\"," +
"\"timestamp\":\"2023-10-17T19:27:41.322698\"" +
"}";

public static final String USER_NOT_FOUND = "{" +
"\"status\":\"NOT_FOUND\"," +
"\"reason\":\"Requested resource does not exist\"," +
"\"message\":\"User with id: 1 not found\"," +
"\"timestamp\":\"2023-10-17T21:25:18.098461\"" +
"}";

public static final String ITEM_REQUEST_BAD_REQUEST = "{" +
"\"status\":\"BAD_REQUEST\"," +
"\"reason\":\"Bad Request\"," +
"\"message\":\"Field(s) failed validation\"," +
"\"errors\":[" +
"\"field 'description' should not be empty, but it was 'null'\"" +
"]," +
"\"timestamp\":\"2023-10-18T14:42:50.201833\"" +
"}";

public static final String POST_ITEM_REQUEST_OK = "{" +
"\"id\":1," +
"\"description\":\"Хотел бы воспользоваться щёткой для обуви\"," +
"\"created\":\"2023-10-18T14:49:08.869138\"," +
"\"items\":null" +
"}";

public static final String ITEM_REQUEST_NOT_FOUND = "{" +
"\"status\":\"NOT_FOUND\"," +
"\"reason\":\"Requested resource does not exist\"," +
"\"message\":\"Item request with id: 99 not found\"," +
"\"timestamp\":\"2023-10-18T15:20:42.426754\"" +
"}";

public static final String COMMENT_BAD_REQUEST = "{" +
"\"status\":\"BAD_REQUEST\"," +
"\"reason\":\"Request cannot be understood by the server due to incorrect syntax\"," +
"\"message\":\"Unable to leave comment for item with id: 1: no approved booking for user with id: 4 or booking is not yet finished\"," +
"\"timestamp\":\"2023-10-19T09:57:46.77556\"" +
"}";

public static final String ITEM_NOT_FOUND = "{" +
"\"status\":\"NOT_FOUND\"," +
"\"reason\":\"Requested resource does not exist\"," +
"\"message\":\"Item not found with id: 99\"," +
"\"timestamp\":\"2023-10-19T10:11:42.797793\"" +
"}";

public static final String ITEM_FORBIDDEN = "{" +
"\"status\":\"FORBIDDEN\"," +
"\"reason\":\"Access denied\"," +
"\"message\":\"User with id: 8 is not owner of item with id: 1\"," +
"\"timestamp\":\"2023-10-19T11:12:52.394164\"" +
"}";
}
}
6 changes: 6 additions & 0 deletions core/dto/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>ru.practicum</groupId>
<artifactId>shareit-server-constants</artifactId>
<version>${shareit-server-constants.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,43 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import lombok.extern.jackson.Jacksonized;
import ru.practicum.shareit.server.constants.OpenApiConsts;

import java.time.LocalDateTime;
import java.util.List;

@Schema(description = "Сведения об ошибке")
@Jacksonized
@Builder
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@Getter
public class ApiError {

@Schema(description = OpenApiConsts.ApiError.STATUS, example = OpenApiConsts.ApiError.STATUS_EG)
String status;

@Schema(description = OpenApiConsts.ApiError.REASON, example = OpenApiConsts.ApiError.REASON_EG)
String reason;

@Schema(description = OpenApiConsts.ApiError.MESSAGE, example = OpenApiConsts.ApiError.MESSAGE_EG)
String message;

@ArraySchema(arraySchema = @Schema(
description = OpenApiConsts.ApiError.ERRORS,
example = OpenApiConsts.ApiError.ERRORS_EG,
nullable = true
))
@JsonInclude(Include.NON_NULL)
List<String> errors;

@Schema(description = OpenApiConsts.ApiError.TIMESTAMP)
@Builder.Default
LocalDateTime timestamp = LocalDateTime.now();
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
package ru.practicum.shareit.server.dto.item.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.FieldDefaults;
import ru.practicum.shareit.server.constants.OpenApiConsts;
import ru.practicum.shareit.server.dto.validation.Groups;
import ru.practicum.shareit.server.dto.validation.annotation.NullableNotBlank;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Schema(description = "Информация о вещи")
@FieldDefaults(level = AccessLevel.PRIVATE)
@Setter
@Getter
@ToString
@NoArgsConstructor
public class ItemCreationDto {

@Schema(description = OpenApiConsts.Item.NAME, example = OpenApiConsts.Item.NAME_EG)
@NotBlank(groups = Groups.OnCreate.class)
@NullableNotBlank(groups = Groups.OnUpdate.class)
String name;

@Schema(description = OpenApiConsts.Item.DESCRIPTION, example = OpenApiConsts.Item.DESCRIPTION_EG)
@NotBlank(groups = Groups.OnCreate.class)
@NullableNotBlank(groups = Groups.OnUpdate.class)
String description;

@Schema(description = OpenApiConsts.Item.IS_AVAILABLE, example = OpenApiConsts.Item.IS_AVAILABLE_EG)
@NotNull(groups = Groups.OnCreate.class)
Boolean available;

@Schema(description = OpenApiConsts.Item.REQUEST_ID, example = OpenApiConsts.Item.REQUEST_ID_EG)
Long requestId;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package ru.practicum.shareit.server.dto.item.request.comment;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.FieldDefaults;
import ru.practicum.shareit.server.constants.OpenApiConsts;
import ru.practicum.shareit.server.dto.validation.Groups;

import javax.validation.constraints.NotEmpty;

@Schema(description = "Данные комментария (отзыва)")
@FieldDefaults(level = AccessLevel.PRIVATE)
@Setter
@Getter
@ToString
@NoArgsConstructor
public class CommentCreationDto {

@Schema(description = OpenApiConsts.Comment.TEXT, example = OpenApiConsts.Comment.TEXT_EG)
@NotEmpty(groups = Groups.OnCreate.class)
String text;
}
Loading
Loading