diff --git a/client/src/domain/index.ts b/client/src/domain/index.ts index 43dee426..c8aef455 100644 --- a/client/src/domain/index.ts +++ b/client/src/domain/index.ts @@ -1,7 +1,7 @@ import { Jwt } from "./model/jwt"; import { Role } from "./model/role"; import { InstrumentId } from "./model/instrument-id"; -import type { Country, Countries } from "./model/country"; +import type { Countries } from "./model/country"; import type { InstrumentName } from "./model/instrument-name"; import type { ManufacturerName, @@ -14,7 +14,6 @@ export { Jwt, Role, InstrumentId, - Country, Countries, InstrumentName, ManufacturerName, diff --git a/client/src/generated/.openapi-generator/FILES b/client/src/generated/.openapi-generator/FILES index 830832cc..5b49a97d 100644 --- a/client/src/generated/.openapi-generator/FILES +++ b/client/src/generated/.openapi-generator/FILES @@ -4,6 +4,7 @@ api.ts api/add-favorite-api.ts api/basic-login-api.ts api/delete-instrument-by-id-api.ts +api/get-countries-api.ts api/get-instrument-basic-materials-api.ts api/get-instrument-by-id-api.ts api/get-instrument-types-api.ts @@ -20,6 +21,8 @@ git_push.sh index.ts model/add-favorite-request-body.ts model/client-error.ts +model/country.ts +model/get-countries-response.ts model/get-instrument-basic-materials-response.ts model/get-instrument-by-criteria-page-response.ts model/get-instrument-criteria-request-body.ts diff --git a/client/src/generated/api.ts b/client/src/generated/api.ts index f570a89a..64ccc888 100644 --- a/client/src/generated/api.ts +++ b/client/src/generated/api.ts @@ -15,6 +15,7 @@ export * from "./api/add-favorite-api"; export * from "./api/basic-login-api"; export * from "./api/delete-instrument-by-id-api"; +export * from "./api/get-countries-api"; export * from "./api/get-instrument-basic-materials-api"; export * from "./api/get-instrument-by-id-api"; export * from "./api/get-instrument-types-api"; diff --git a/client/src/generated/model/index.ts b/client/src/generated/model/index.ts index 9fea743d..ca0abc96 100644 --- a/client/src/generated/model/index.ts +++ b/client/src/generated/model/index.ts @@ -1,5 +1,7 @@ export * from "./add-favorite-request-body"; export * from "./client-error"; +export * from "./country"; +export * from "./get-countries-response"; export * from "./get-instrument-basic-materials-response"; export * from "./get-instrument-by-criteria-page-response"; export * from "./get-instrument-criteria-request-body"; diff --git a/client/src/pages/create-instrument/api/loader.ts b/client/src/pages/create-instrument/api/loader.ts index df459100..c934acf2 100644 --- a/client/src/pages/create-instrument/api/loader.ts +++ b/client/src/pages/create-instrument/api/loader.ts @@ -1,21 +1,26 @@ import { LoaderFunction } from "react-router-dom"; import { SERVER_URL } from "shared/config"; -import { API_COUNTRIES, API_MANUFACTURERS } from "shared/config/backend"; +import { API_MANUFACTURERS } from "shared/config/backend"; import axios from "axios"; -import { Countries } from "domain/model/country"; import { ManufacturerNames } from "domain/model/manufacturer-name"; import { GetInstrumentTypesApi } from "generated/api/get-instrument-types-api"; -import type { InstrumentBasicMaterial, InstrumentType } from "generated/model"; +import type { + Country, + InstrumentBasicMaterial, + InstrumentType, +} from "generated/model"; import { GetInstrumentBasicMaterialsApi } from "generated/api/get-instrument-basic-materials-api"; +import { GetCountriesApi } from "generated/api/get-countries-api"; const getInstrumentTypes = new GetInstrumentTypesApi(); const getInstrumentBasicMaterials = new GetInstrumentBasicMaterialsApi(); +const getCountries = new GetCountriesApi(); export interface CreateInstrumentLoader { instrumentTypes: InstrumentType[]; manufacturerNames: ManufacturerNames; materials: InstrumentBasicMaterial[]; - countries: Countries; + countries: Country[]; } export const loader: LoaderFunction = @@ -26,15 +31,7 @@ export const loader: LoaderFunction = const instrumentBasicMaterialsRequest = await getInstrumentBasicMaterials.getInstrumentBasicMaterials(); - let countries: string[] = []; - await axios - .get(`${SERVER_URL}${API_COUNTRIES}`) - .then((data) => { - countries = data.data; - }) - .catch(() => { - throw new Error("Fail to retrieve countries"); - }); + const countriesRequest = await getCountries.getCountries(); let manufacturers: ManufacturerNames = []; await axios @@ -50,6 +47,6 @@ export const loader: LoaderFunction = instrumentTypes: instrumentTypesRequest.data.content, manufacturerNames: manufacturers, materials: instrumentBasicMaterialsRequest.data.content, - countries: countries, + countries: countriesRequest.data.content, }; }; diff --git a/client/src/pages/edit-instrument/api/loader.ts b/client/src/pages/edit-instrument/api/loader.ts index 47717340..4999464c 100644 --- a/client/src/pages/edit-instrument/api/loader.ts +++ b/client/src/pages/edit-instrument/api/loader.ts @@ -1,28 +1,30 @@ import { ManufacturerNames } from "domain/model/manufacturer-name"; -import { Countries } from "domain/model/country"; import { LoaderFunction } from "react-router-dom"; import axios from "axios"; import { SERVER_URL } from "shared/config"; -import { API_COUNTRIES, API_MANUFACTURERS } from "shared/config/backend"; +import { API_MANUFACTURERS } from "shared/config/backend"; import { GetInstrumentByIdApi } from "generated/api/get-instrument-by-id-api"; import { + Country, InstrumentBasicMaterial, InstrumentDetail, type InstrumentType, } from "generated/model"; import { GetInstrumentTypesApi } from "generated/api/get-instrument-types-api"; import { GetInstrumentBasicMaterialsApi } from "generated/api/get-instrument-basic-materials-api"; +import { GetCountriesApi } from "generated/api/get-countries-api"; const getInstrumentById = new GetInstrumentByIdApi(); const getInstrumentTypes = new GetInstrumentTypesApi(); const getInstrumentBasicMaterials = new GetInstrumentBasicMaterialsApi(); +const getCountries = new GetCountriesApi(); export interface EditInstrumentLoader { instrumentForEdit: InstrumentDetail; instrumentTypes: InstrumentType[]; manufacturerNames: ManufacturerNames; materials: InstrumentBasicMaterial[]; - countries: Countries; + countries: Country[]; } export const loader: LoaderFunction = async ({ @@ -37,15 +39,7 @@ export const loader: LoaderFunction = async ({ const instrumentBasicMaterialsRequest = await getInstrumentBasicMaterials.getInstrumentBasicMaterials(); - let countries: string[] = []; - await axios - .get(`${SERVER_URL}${API_COUNTRIES}`) - .then((data) => { - countries = data.data; - }) - .catch(() => { - throw new Error("Fail to retrieve countries"); - }); + const countriesRequest = await getCountries.getCountries(); let manufacturers: ManufacturerNames = []; await axios @@ -62,6 +56,6 @@ export const loader: LoaderFunction = async ({ instrumentTypes: instrumentTypesRequest.data.content, manufacturerNames: manufacturers, materials: instrumentBasicMaterialsRequest.data.content, - countries: countries, + countries: countriesRequest.data.content, }; }; diff --git a/client/src/shared/config/backend.ts b/client/src/shared/config/backend.ts index a8ddcebb..6ad5d1eb 100644 --- a/client/src/shared/config/backend.ts +++ b/client/src/shared/config/backend.ts @@ -1,6 +1,5 @@ export const SERVER_URL = "http://localhost:8080"; export const API = "/api"; -export const API_COUNTRIES = `${API}/countries`; export const API_CREATE_INSTRUMENT = `${API}/instrument/create`; export const API_MANUFACTURERS = `${API}/manufacturers`; diff --git a/client/src/shared/model/parseInstrumentDetails.ts b/client/src/shared/model/parseInstrumentDetails.ts index 95dfb01d..b68bfe8d 100644 --- a/client/src/shared/model/parseInstrumentDetails.ts +++ b/client/src/shared/model/parseInstrumentDetails.ts @@ -2,10 +2,9 @@ import { InstrumentName } from "domain/model/instrument-name"; import { ManufacturerName } from "domain/model/manufacturer-name"; import { ManufactureDate } from "domain/model/manufacture-date"; import { ReleaseDate } from "domain/model/release-date"; -import { Country } from "domain/model/country"; import { InstrumentId } from "domain/model/instrument-id"; import { InstrumentType } from "generated/model/instrument-type"; -import { InstrumentBasicMaterial } from "generated/model"; +import { Country, InstrumentBasicMaterial } from "generated/model"; export const parseInstrumentDetails = (data: FormData) => { const errors = []; @@ -67,11 +66,14 @@ export const parseInstrumentDetails = (data: FormData) => { errors.push("Release date must be after manufacture date"); } - const country = data.get("country"); + const country = { + country: data.get("country"), + } as Country; + if ( - country === null || - typeof country !== "string" || - manufactureDate === "" + country.country === null || + typeof country.country !== "string" || + country.country === "" ) { errors.push("Type country"); } diff --git a/client/src/widgets/catalogue-filter/ui/CountryFilter.tsx b/client/src/widgets/catalogue-filter/ui/CountryFilter.tsx index ed184eae..4077f08c 100644 --- a/client/src/widgets/catalogue-filter/ui/CountryFilter.tsx +++ b/client/src/widgets/catalogue-filter/ui/CountryFilter.tsx @@ -1,26 +1,23 @@ import React, { useEffect, useState } from "react"; import { ManufacturerNames } from "domain/model/manufacturer-name"; -import axios from "axios"; -import { SERVER_URL } from "shared/config"; -import { API_COUNTRIES } from "shared/config/backend"; -import { Countries } from "domain/model/country"; +import { GetCountriesApi } from "generated/api/get-countries-api"; +import { Country } from "generated/model"; interface Props { onValueChange: (names: ManufacturerNames) => void; } +const getCountries = new GetCountriesApi(); + export const CountryFilter = ({ onValueChange }: Props) => { - const [countries, setCountries] = useState([]); + const [countries, setCountries] = useState([]); useEffect(() => { - axios - .get(`${SERVER_URL}${API_COUNTRIES}`) - .then((r) => { - setCountries(r.data); - }) - .catch((e) => { - throw new Error(`Failed to extract countries: '${e}'`); - }); + const fetchCountries = async () => { + const response = await getCountries.getCountries(); + setCountries(response.data.content); + }; + fetchCountries(); }, []); function onChange() { @@ -39,15 +36,15 @@ export const CountryFilter = ({ onValueChange }: Props) => {
Country: {countries.map((country) => ( -
+
- +
))}
diff --git a/openapi/openapi.yml b/openapi/openapi.yml index eb049164..8ae4ed07 100644 --- a/openapi/openapi.yml +++ b/openapi/openapi.yml @@ -18,6 +18,9 @@ servers: basePath: default: api tags: + - name: getCountries + description: Get Countries + x-displayName: getCountries - name: addFavorite description: Add Favorite x-displayName: addFavorite @@ -55,6 +58,32 @@ tags: description: User Registration x-displayName: userRegistration paths: + /countries: + get: + description: Get Countries + summary: Get Countries + operationId: getCountries + tags: + - getCountries + responses: + '200': + description: Country + content: + application/json: + schema: + $ref: '#/components/schemas/GetCountriesResponse' + '400': + description: Client Error + content: + application/json: + schema: + $ref: '#/components/schemas/ClientError' + default: + description: Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ServerError' /favorite/add: post: description: Add Favorite @@ -468,6 +497,22 @@ components: description: A description of the error. example: message: Internal Server Error. Please try again later. + Country: + type: object + required: + - country + properties: + country: + type: string + GetCountriesResponse: + type: object + required: + - content + properties: + content: + type: array + items: + $ref: '#/components/schemas/Country' AddFavoriteRequestBody: type: object required: @@ -659,6 +704,9 @@ components: password: type: string x-tagGroups: + - name: Get Countries + tags: + - getCountries - name: Add Favorite tags: - addFavorite diff --git a/openapi/specs/country/GetCountriesEndpoint.yml b/openapi/specs/country/GetCountriesEndpoint.yml new file mode 100644 index 00000000..a79f2b50 --- /dev/null +++ b/openapi/specs/country/GetCountriesEndpoint.yml @@ -0,0 +1,71 @@ +openapi: "3.0.0" # openApiGenerate gradle task do not support officially 3.1.0 openapi version + +info: + description: Get Countries + version: 1.0.0 + title: Get Countries + contact: + name: Kirill B + email: baskirill.an@gmail.com +servers: + - url: http://localhost:{port}/{basePath} + description: Local server (uses local data) + variables: + port: + default: "8080" + enum: + - "8080" + - "8000" + basePath: + default: "api" + +tags: + - name: getCountries + description: Get Countries + +paths: + /countries: + get: + description: Get Countries + summary: Get Countries + operationId: getCountries + tags: + - getCountries + responses: + "200": + description: Country + content: + application/json: + schema: + $ref: "#/components/schemas/GetCountriesResponse" + "400": + description: Client Error + content: + application/json: + schema: + $ref: "./../common/ClientError.yml#/components/schemas/ClientError" + default: + description: Server Error + content: + application/json: + schema: + $ref: "./../common/ServerError.yml#/components/schemas/ServerError" + +components: + schemas: + Country: + type: object + required: [country] + properties: + country: + type: string + + GetCountriesResponse: + type: object + required: [content] + properties: + content: + type: array + items: + $ref: "#/components/schemas/Country" + diff --git a/server/app/src/main/kotlin/mu/muse/rest/country/GetCountriesEndpoint.kt b/server/app/src/main/kotlin/mu/muse/rest/country/GetCountriesEndpoint.kt index edb6de01..3d1eedd0 100644 --- a/server/app/src/main/kotlin/mu/muse/rest/country/GetCountriesEndpoint.kt +++ b/server/app/src/main/kotlin/mu/muse/rest/country/GetCountriesEndpoint.kt @@ -1,18 +1,27 @@ package mu.muse.rest.country import mu.muse.domain.instrument.Country -import mu.muse.rest.API_COUNTRIES +import mu.muse.rest.api.GetCountriesApi +import mu.muse.rest.dto.GetCountriesResponse import mu.muse.usecase.GetCountries -import org.springframework.web.bind.annotation.GetMapping +import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RestController @RestController class GetCountriesEndpoint( private val getCountries: GetCountries, -) { +): GetCountriesApi { - @GetMapping(API_COUNTRIES) - fun getCountries(): List { - return getCountries.execute() + override fun getCountries(): ResponseEntity { + val countries = getCountries.execute() + return countries.toResponse() } } + +fun List.toResponse(): ResponseEntity { + return ResponseEntity.ok( + GetCountriesResponse( + content = this.map { mu.muse.rest.dto.Country(it.name) }, + ), + ) +}