From 621919d3002f68aa4fdbbca1428889efa355d803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kar=C3=A1sek?= Date: Wed, 27 Sep 2023 21:53:15 +0200 Subject: [PATCH] feat: pagination with templates (#150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds logic for generating listing functions capable of going through all the pages (think devices in a project, or events in a device). It adds templates for the new code, docs, and code tests. The templates are fetched from oag v7.0.0, and then modified for the sake of the paginated listers. It uses vendor extension property object in the form ```yaml x-paginated: x-paginated-property: Events ``` The spec patching part can be done in other oag generated SDKs. related to #135 fixes #131 --------- Signed-off-by: Tomáš Karásek Co-authored-by: Marques Johansson --- api/openapi.yaml | 14 + docs/DevicesApi.md | 2 + docs/EventsApi.md | 5 + docs/HardwareReservationsApi.md | 1 + docs/InterconnectionsApi.md | 1 + docs/MetalGatewaysApi.md | 1 + docs/OrganizationsApi.md | 2 + docs/ProjectsApi.md | 1 + docs/UsersApi.md | 1 + metal/v1/api_devices.go | 50 ++ metal/v1/api_events.go | 125 +++++ metal/v1/api_hardware_reservations.go | 25 + metal/v1/api_interconnections.go | 25 + metal/v1/api_metal_gateways.go | 25 + metal/v1/api_organizations.go | 50 ++ metal/v1/api_projects.go | 25 + metal/v1/api_users.go | 25 + metal/v1/test/api_devices_test.go | 8 + metal/v1/test/api_events_test.go | 20 + .../v1/test/api_hardware_reservations_test.go | 4 + metal/v1/test/api_interconnections_test.go | 4 + metal/v1/test/api_metal_gateways_test.go | 4 + metal/v1/test/api_organizations_test.go | 8 + metal/v1/test/api_projects_test.go | 4 + metal/v1/test/api_users_test.go | 4 + ...5-x-equinix-metal-paginated-property.patch | 147 ++++++ script/mark_paginated.py | 69 +++ .../connections/connection_id/events.yaml | 1 + .../oas3.patched/paths/devices/id/events.yaml | 1 + spec/oas3.patched/paths/events.yaml | 1 + spec/oas3.patched/paths/organizations.yaml | 1 + .../paths/organizations/id/devices.yaml | 1 + .../paths/organizations/id/events.yaml | 1 + .../paths/organizations/id/projects.yaml | 1 + spec/oas3.patched/paths/projects.yaml | 1 + .../paths/projects/id/devices.yaml | 1 + .../paths/projects/id/events.yaml | 1 + .../projects/id/hardware-reservations.yaml | 1 + .../projects/project_id/connections.yaml | 1 + .../projects/project_id/metal-gateways.yaml | 1 + spec/oas3.patched/paths/users.yaml | 1 + templates/api.mustache | 444 ++++++++++++++++++ templates/api_doc.mustache | 97 ++++ templates/api_test.mustache | 64 +++ 44 files changed, 1269 insertions(+) create mode 100644 patches/spec.fetched.json/20230925-x-equinix-metal-paginated-property.patch create mode 100755 script/mark_paginated.py create mode 100644 templates/api.mustache create mode 100644 templates/api_doc.mustache create mode 100644 templates/api_test.mustache diff --git a/api/openapi.yaml b/api/openapi.yaml index 1ab4a387..45781d7b 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1094,6 +1094,7 @@ paths: summary: Retrieve interconnection events tags: - Events + x-equinix-metal-paginated-property: Events /connections/{connection_id}/ports: get: description: List the ports associated to an interconnection. @@ -2018,6 +2019,7 @@ paths: summary: Retrieve device's events tags: - Events + x-equinix-metal-paginated-property: Events /devices/{id}/firmware-sets: get: description: "Returns the firmware set associated with the device. If a custom\ @@ -2678,6 +2680,7 @@ paths: summary: Retrieve current user's events tags: - Events + x-equinix-metal-paginated-property: Events /events/{id}: get: description: Returns a single event if the user has access @@ -4543,6 +4546,7 @@ paths: summary: Retrieve all organizations tags: - Organizations + x-equinix-metal-paginated-property: Organizations post: description: Creates an organization. operationId: createOrganization @@ -5044,6 +5048,7 @@ paths: summary: Retrieve all devices of an organization tags: - Devices + x-equinix-metal-paginated-property: Devices /organizations/{id}/events: get: description: Returns a list of events for a single organization @@ -5126,6 +5131,7 @@ paths: summary: Retrieve organization's events tags: - Events + x-equinix-metal-paginated-property: Events /organizations/{id}/facilities: get: deprecated: true @@ -5729,6 +5735,7 @@ paths: summary: Retrieve all projects of an organization tags: - Organizations + x-equinix-metal-paginated-property: Projects post: description: Creates a new project for the organization operationId: createOrganizationProject @@ -7042,6 +7049,7 @@ paths: summary: Retrieve all projects tags: - Projects + x-equinix-metal-paginated-property: Projects post: description: "Creates a new project for the user default organization. If the\ \ user don't have an organization, a new one will be created." @@ -7750,6 +7758,7 @@ paths: summary: Retrieve all devices of a project tags: - Devices + x-equinix-metal-paginated-property: Devices post: description: |- Creates a new device and provisions it in the specified location. @@ -7964,6 +7973,7 @@ paths: summary: Retrieve project's events tags: - Events + x-equinix-metal-paginated-property: Events /projects/{id}/facilities: get: deprecated: true @@ -8211,6 +8221,7 @@ paths: summary: Retrieve all hardware reservations for a given project tags: - HardwareReservations + x-equinix-metal-paginated-property: HardwareReservations /projects/{id}/ips: get: description: Provides a paginated list of IP reservations for a single project. @@ -9253,6 +9264,7 @@ paths: summary: List project connections tags: - Interconnections + x-equinix-metal-paginated-property: Interconnections post: description: Creates a new interconnection request operationId: createProjectInterconnection @@ -9636,6 +9648,7 @@ paths: summary: Returns all metal gateways for a project tags: - MetalGateways + x-equinix-metal-paginated-property: MetalGateways post: description: Create a metal gateway in a project operationId: createMetalGateway @@ -11204,6 +11217,7 @@ paths: summary: Retrieve all users tags: - Users + x-equinix-metal-paginated-property: Users post: description: Creates a user. operationId: createUser diff --git a/docs/DevicesApi.md b/docs/DevicesApi.md index 2ff39cce..e8b09d7d 100644 --- a/docs/DevicesApi.md +++ b/docs/DevicesApi.md @@ -901,6 +901,7 @@ Name | Type | Description | Notes Retrieve all devices of an organization +FindOrganizationDevices is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -995,6 +996,7 @@ Name | Type | Description | Notes Retrieve all devices of a project +FindProjectDevices is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/EventsApi.md b/docs/EventsApi.md index 88e02ea7..6df8d9f3 100644 --- a/docs/EventsApi.md +++ b/docs/EventsApi.md @@ -23,6 +23,7 @@ Method | HTTP request | Description Retrieve device's events +FindDeviceEvents is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -175,6 +176,7 @@ Name | Type | Description | Notes Retrieve current user's events +FindEvents is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -247,6 +249,7 @@ Name | Type | Description | Notes Retrieve interconnection events +FindInterconnectionEvents is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -406,6 +409,7 @@ Name | Type | Description | Notes Retrieve organization's events +FindOrganizationEvents is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -484,6 +488,7 @@ Name | Type | Description | Notes Retrieve project's events +FindProjectEvents is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/HardwareReservationsApi.md b/docs/HardwareReservationsApi.md index 85ebb1bb..1ab48587 100644 --- a/docs/HardwareReservationsApi.md +++ b/docs/HardwareReservationsApi.md @@ -168,6 +168,7 @@ Name | Type | Description | Notes Retrieve all hardware reservations for a given project +FindProjectHardwareReservations is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/InterconnectionsApi.md b/docs/InterconnectionsApi.md index ac18b287..3eb39e84 100644 --- a/docs/InterconnectionsApi.md +++ b/docs/InterconnectionsApi.md @@ -920,6 +920,7 @@ Name | Type | Description | Notes List project connections +ProjectListInterconnections is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/MetalGatewaysApi.md b/docs/MetalGatewaysApi.md index 1d1332fb..ce9f990c 100644 --- a/docs/MetalGatewaysApi.md +++ b/docs/MetalGatewaysApi.md @@ -324,6 +324,7 @@ Name | Type | Description | Notes Returns all metal gateways for a project +FindMetalGatewaysByProject is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/OrganizationsApi.md b/docs/OrganizationsApi.md index 332be0d6..2e1441bf 100644 --- a/docs/OrganizationsApi.md +++ b/docs/OrganizationsApi.md @@ -757,6 +757,7 @@ Name | Type | Description | Notes Retrieve all projects of an organization +FindOrganizationProjects is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example @@ -909,6 +910,7 @@ Name | Type | Description | Notes Retrieve all organizations +FindOrganizations is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/ProjectsApi.md b/docs/ProjectsApi.md index c106212b..c05c8043 100644 --- a/docs/ProjectsApi.md +++ b/docs/ProjectsApi.md @@ -678,6 +678,7 @@ Name | Type | Description | Notes Retrieve all projects +FindProjects is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/docs/UsersApi.md b/docs/UsersApi.md index 8e437bf1..3762523d 100644 --- a/docs/UsersApi.md +++ b/docs/UsersApi.md @@ -371,6 +371,7 @@ Name | Type | Description | Notes Retrieve all users +FindUsers is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. ### Example diff --git a/metal/v1/api_devices.go b/metal/v1/api_devices.go index aca95e18..5d075505 100644 --- a/metal/v1/api_devices.go +++ b/metal/v1/api_devices.go @@ -2210,6 +2210,31 @@ func (a *DevicesApiService) FindOrganizationDevicesExecute(r ApiFindOrganization return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return DeviceList +func (r ApiFindOrganizationDevicesRequest) ExecuteWithPagination() (*DeviceList, error) { + + var items DeviceList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Devices = append(items.Devices, page.Devices...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindProjectDevicesRequest struct { ctx context.Context ApiService *DevicesApiService @@ -2480,6 +2505,31 @@ func (a *DevicesApiService) FindProjectDevicesExecute(r ApiFindProjectDevicesReq return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return DeviceList +func (r ApiFindProjectDevicesRequest) ExecuteWithPagination() (*DeviceList, error) { + + var items DeviceList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Devices = append(items.Devices, page.Devices...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindTrafficRequest struct { ctx context.Context ApiService *DevicesApiService diff --git a/metal/v1/api_events.go b/metal/v1/api_events.go index e8b8cc77..0b26ded8 100644 --- a/metal/v1/api_events.go +++ b/metal/v1/api_events.go @@ -213,6 +213,31 @@ func (a *EventsApiService) FindDeviceEventsExecute(r ApiFindDeviceEventsRequest) return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return EventList +func (r ApiFindDeviceEventsRequest) ExecuteWithPagination() (*EventList, error) { + + var items EventList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Events = append(items.Events, page.Events...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindEventByIdRequest struct { ctx context.Context ApiService *EventsApiService @@ -547,6 +572,31 @@ func (a *EventsApiService) FindEventsExecute(r ApiFindEventsRequest) (*EventList return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return EventList +func (r ApiFindEventsRequest) ExecuteWithPagination() (*EventList, error) { + + var items EventList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Events = append(items.Events, page.Events...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindInterconnectionEventsRequest struct { ctx context.Context ApiService *EventsApiService @@ -737,6 +787,31 @@ func (a *EventsApiService) FindInterconnectionEventsExecute(r ApiFindInterconnec return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return EventList +func (r ApiFindInterconnectionEventsRequest) ExecuteWithPagination() (*EventList, error) { + + var items EventList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Events = append(items.Events, page.Events...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindInterconnectionPortEventsRequest struct { ctx context.Context ApiService *EventsApiService @@ -1121,6 +1196,31 @@ func (a *EventsApiService) FindOrganizationEventsExecute(r ApiFindOrganizationEv return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return EventList +func (r ApiFindOrganizationEventsRequest) ExecuteWithPagination() (*EventList, error) { + + var items EventList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Events = append(items.Events, page.Events...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindProjectEventsRequest struct { ctx context.Context ApiService *EventsApiService @@ -1311,6 +1411,31 @@ func (a *EventsApiService) FindProjectEventsExecute(r ApiFindProjectEventsReques return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return EventList +func (r ApiFindProjectEventsRequest) ExecuteWithPagination() (*EventList, error) { + + var items EventList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Events = append(items.Events, page.Events...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindVirtualCircuitEventsRequest struct { ctx context.Context ApiService *EventsApiService diff --git a/metal/v1/api_hardware_reservations.go b/metal/v1/api_hardware_reservations.go index e8958311..b405142e 100644 --- a/metal/v1/api_hardware_reservations.go +++ b/metal/v1/api_hardware_reservations.go @@ -592,6 +592,31 @@ func (a *HardwareReservationsApiService) FindProjectHardwareReservationsExecute( return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return HardwareReservationList +func (r ApiFindProjectHardwareReservationsRequest) ExecuteWithPagination() (*HardwareReservationList, error) { + + var items HardwareReservationList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.HardwareReservations = append(items.HardwareReservations, page.HardwareReservations...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiMoveHardwareReservationRequest struct { ctx context.Context ApiService *HardwareReservationsApiService diff --git a/metal/v1/api_interconnections.go b/metal/v1/api_interconnections.go index 68c023e0..ace4db77 100644 --- a/metal/v1/api_interconnections.go +++ b/metal/v1/api_interconnections.go @@ -2109,6 +2109,31 @@ func (a *InterconnectionsApiService) ProjectListInterconnectionsExecute(r ApiPro return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return InterconnectionList +func (r ApiProjectListInterconnectionsRequest) ExecuteWithPagination() (*InterconnectionList, error) { + + var items InterconnectionList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Interconnections = append(items.Interconnections, page.Interconnections...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiUpdateInterconnectionRequest struct { ctx context.Context ApiService *InterconnectionsApiService diff --git a/metal/v1/api_metal_gateways.go b/metal/v1/api_metal_gateways.go index 98dcb53e..18f9db8a 100644 --- a/metal/v1/api_metal_gateways.go +++ b/metal/v1/api_metal_gateways.go @@ -918,6 +918,31 @@ func (a *MetalGatewaysApiService) FindMetalGatewaysByProjectExecute(r ApiFindMet return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return MetalGatewayList +func (r ApiFindMetalGatewaysByProjectRequest) ExecuteWithPagination() (*MetalGatewayList, error) { + + var items MetalGatewayList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.MetalGateways = append(items.MetalGateways, page.MetalGateways...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiGetMetalGatewayElasticIpsRequest struct { ctx context.Context ApiService *MetalGatewaysApiService diff --git a/metal/v1/api_organizations.go b/metal/v1/api_organizations.go index 318a702f..396e8917 100644 --- a/metal/v1/api_organizations.go +++ b/metal/v1/api_organizations.go @@ -1850,6 +1850,31 @@ func (a *OrganizationsApiService) FindOrganizationProjectsExecute(r ApiFindOrgan return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return ProjectList +func (r ApiFindOrganizationProjectsRequest) ExecuteWithPagination() (*ProjectList, error) { + + var items ProjectList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Projects = append(items.Projects, page.Projects...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindOrganizationTransfersRequest struct { ctx context.Context ApiService *OrganizationsApiService @@ -2183,6 +2208,31 @@ func (a *OrganizationsApiService) FindOrganizationsExecute(r ApiFindOrganization return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return OrganizationList +func (r ApiFindOrganizationsRequest) ExecuteWithPagination() (*OrganizationList, error) { + + var items OrganizationList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Organizations = append(items.Organizations, page.Organizations...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiFindPlansByOrganizationRequest struct { ctx context.Context ApiService *OrganizationsApiService diff --git a/metal/v1/api_projects.go b/metal/v1/api_projects.go index dee3536d..c3911868 100644 --- a/metal/v1/api_projects.go +++ b/metal/v1/api_projects.go @@ -1688,6 +1688,31 @@ func (a *ProjectsApiService) FindProjectsExecute(r ApiFindProjectsRequest) (*Pro return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return ProjectList +func (r ApiFindProjectsRequest) ExecuteWithPagination() (*ProjectList, error) { + + var items ProjectList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Projects = append(items.Projects, page.Projects...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiUpdateProjectRequest struct { ctx context.Context ApiService *ProjectsApiService diff --git a/metal/v1/api_users.go b/metal/v1/api_users.go index c9428353..cbc0903b 100644 --- a/metal/v1/api_users.go +++ b/metal/v1/api_users.go @@ -982,6 +982,31 @@ func (a *UsersApiService) FindUsersExecute(r ApiFindUsersRequest) (*UserList, *h return localVarReturnValue, localVarHTTPResponse, nil } +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice +// +// @return UserList +func (r ApiFindUsersRequest) ExecuteWithPagination() (*UserList, error) { + + var items UserList + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.Users = append(items.Users, page.Users...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} + type ApiUpdateCurrentUserRequest struct { ctx context.Context ApiService *UsersApiService diff --git a/metal/v1/test/api_devices_test.go b/metal/v1/test/api_devices_test.go index e7339a65..dbf44afb 100644 --- a/metal/v1/test/api_devices_test.go +++ b/metal/v1/test/api_devices_test.go @@ -173,6 +173,10 @@ func Test_v1_DevicesApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.DevicesApi.FindOrganizationDevices(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test DevicesApiService FindProjectDevices", func(t *testing.T) { @@ -185,6 +189,10 @@ func Test_v1_DevicesApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.DevicesApi.FindProjectDevices(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test DevicesApiService FindTraffic", func(t *testing.T) { diff --git a/metal/v1/test/api_events_test.go b/metal/v1/test/api_events_test.go index f5a363e3..bb957174 100644 --- a/metal/v1/test/api_events_test.go +++ b/metal/v1/test/api_events_test.go @@ -32,6 +32,10 @@ func Test_v1_EventsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.EventsApi.FindDeviceEvents(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test EventsApiService FindEventById", func(t *testing.T) { @@ -54,6 +58,10 @@ func Test_v1_EventsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.EventsApi.FindEvents(context.Background()).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test EventsApiService FindInterconnectionEvents", func(t *testing.T) { @@ -66,6 +74,10 @@ func Test_v1_EventsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.EventsApi.FindInterconnectionEvents(context.Background(), connectionId).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test EventsApiService FindInterconnectionPortEvents", func(t *testing.T) { @@ -91,6 +103,10 @@ func Test_v1_EventsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.EventsApi.FindOrganizationEvents(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test EventsApiService FindProjectEvents", func(t *testing.T) { @@ -103,6 +119,10 @@ func Test_v1_EventsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.EventsApi.FindProjectEvents(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test EventsApiService FindVirtualCircuitEvents", func(t *testing.T) { diff --git a/metal/v1/test/api_hardware_reservations_test.go b/metal/v1/test/api_hardware_reservations_test.go index 1e98a63f..e28955ed 100644 --- a/metal/v1/test/api_hardware_reservations_test.go +++ b/metal/v1/test/api_hardware_reservations_test.go @@ -56,6 +56,10 @@ func Test_v1_HardwareReservationsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.HardwareReservationsApi.FindProjectHardwareReservations(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test HardwareReservationsApiService MoveHardwareReservation", func(t *testing.T) { diff --git a/metal/v1/test/api_interconnections_test.go b/metal/v1/test/api_interconnections_test.go index c08c9cb0..9ec95948 100644 --- a/metal/v1/test/api_interconnections_test.go +++ b/metal/v1/test/api_interconnections_test.go @@ -179,6 +179,10 @@ func Test_v1_InterconnectionsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.InterconnectionsApi.ProjectListInterconnections(context.Background(), projectId).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test InterconnectionsApiService UpdateInterconnection", func(t *testing.T) { diff --git a/metal/v1/test/api_metal_gateways_test.go b/metal/v1/test/api_metal_gateways_test.go index cc83bd40..ba16e2ba 100644 --- a/metal/v1/test/api_metal_gateways_test.go +++ b/metal/v1/test/api_metal_gateways_test.go @@ -80,6 +80,10 @@ func Test_v1_MetalGatewaysApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.MetalGatewaysApi.FindMetalGatewaysByProject(context.Background(), projectId).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test MetalGatewaysApiService GetMetalGatewayElasticIps", func(t *testing.T) { diff --git a/metal/v1/test/api_organizations_test.go b/metal/v1/test/api_organizations_test.go index bd777186..c6e8f171 100644 --- a/metal/v1/test/api_organizations_test.go +++ b/metal/v1/test/api_organizations_test.go @@ -148,6 +148,10 @@ func Test_v1_OrganizationsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.OrganizationsApi.FindOrganizationProjects(context.Background(), id).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test OrganizationsApiService FindOrganizationTransfers", func(t *testing.T) { @@ -170,6 +174,10 @@ func Test_v1_OrganizationsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.OrganizationsApi.FindOrganizations(context.Background()).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test OrganizationsApiService FindPlansByOrganization", func(t *testing.T) { diff --git a/metal/v1/test/api_projects_test.go b/metal/v1/test/api_projects_test.go index 22e7c1a0..cc491b6f 100644 --- a/metal/v1/test/api_projects_test.go +++ b/metal/v1/test/api_projects_test.go @@ -134,6 +134,10 @@ func Test_v1_ProjectsApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.ProjectsApi.FindProjects(context.Background()).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test ProjectsApiService UpdateProject", func(t *testing.T) { diff --git a/metal/v1/test/api_users_test.go b/metal/v1/test/api_users_test.go index b21269f1..97f6f6eb 100644 --- a/metal/v1/test/api_users_test.go +++ b/metal/v1/test/api_users_test.go @@ -83,6 +83,10 @@ func Test_v1_UsersApiService(t *testing.T) { require.Nil(t, err) require.NotNil(t, resp) assert.Equal(t, 200, httpRes.StatusCode) + + resp, err = apiClient.UsersApi.FindUsers(context.Background()).ExecuteWithPagination() + require.Nil(t, err) + require.NotNil(t, resp) }) t.Run("Test UsersApiService UpdateCurrentUser", func(t *testing.T) { diff --git a/patches/spec.fetched.json/20230925-x-equinix-metal-paginated-property.patch b/patches/spec.fetched.json/20230925-x-equinix-metal-paginated-property.patch new file mode 100644 index 00000000..632ea4cb --- /dev/null +++ b/patches/spec.fetched.json/20230925-x-equinix-metal-paginated-property.patch @@ -0,0 +1,147 @@ +diff --git a/spec/oas3.patched/paths/connections/connection_id/events.yaml b/spec/oas3.patched/paths/connections/connection_id/events.yaml +index 8d2121b..e797a39 100644 +--- a/spec/oas3.patched/paths/connections/connection_id/events.yaml ++++ b/spec/oas3.patched/paths/connections/connection_id/events.yaml +@@ -41,3 +41,4 @@ get: + summary: Retrieve interconnection events + tags: + - Events ++ x-equinix-metal-paginated-property: Events +diff --git a/spec/oas3.patched/paths/devices/id/events.yaml b/spec/oas3.patched/paths/devices/id/events.yaml +index 62a179c..470b51e 100644 +--- a/spec/oas3.patched/paths/devices/id/events.yaml ++++ b/spec/oas3.patched/paths/devices/id/events.yaml +@@ -41,3 +41,4 @@ get: + summary: Retrieve device's events + tags: + - Events ++ x-equinix-metal-paginated-property: Events +diff --git a/spec/oas3.patched/paths/events.yaml b/spec/oas3.patched/paths/events.yaml +index 6e5042d..7efcc87 100644 +--- a/spec/oas3.patched/paths/events.yaml ++++ b/spec/oas3.patched/paths/events.yaml +@@ -22,3 +22,4 @@ get: + summary: Retrieve current user's events + tags: + - Events ++ x-equinix-metal-paginated-property: Events +diff --git a/spec/oas3.patched/paths/organizations.yaml b/spec/oas3.patched/paths/organizations.yaml +index 0a21aaf..0a43328 100644 +--- a/spec/oas3.patched/paths/organizations.yaml ++++ b/spec/oas3.patched/paths/organizations.yaml +@@ -41,6 +41,7 @@ get: + summary: Retrieve all organizations + tags: + - Organizations ++ x-equinix-metal-paginated-property: Organizations + post: + description: Creates an organization. + operationId: createOrganization +diff --git a/spec/oas3.patched/paths/organizations/id/devices.yaml b/spec/oas3.patched/paths/organizations/id/devices.yaml +index 9309843..709f1c1 100644 +--- a/spec/oas3.patched/paths/organizations/id/devices.yaml ++++ b/spec/oas3.patched/paths/organizations/id/devices.yaml +@@ -83,3 +86,4 @@ get: + summary: Retrieve all devices of an organization + tags: + - Devices ++ x-equinix-metal-paginated-property: Devices +diff --git a/spec/oas3.patched/paths/organizations/id/events.yaml b/spec/oas3.patched/paths/organizations/id/events.yaml +index cd713da..e184181 100644 +--- a/spec/oas3.patched/paths/organizations/id/events.yaml ++++ b/spec/oas3.patched/paths/organizations/id/events.yaml +@@ -41,3 +41,4 @@ get: + summary: Retrieve organization's events + tags: + - Events ++ x-equinix-metal-paginated-property: Events +diff --git a/spec/oas3.patched/paths/organizations/id/projects.yaml b/spec/oas3.patched/paths/organizations/id/projects.yaml +index 004a17e..3ccaf57 100644 +--- a/spec/oas3.patched/paths/organizations/id/projects.yaml ++++ b/spec/oas3.patched/paths/organizations/id/projects.yaml +@@ -30,6 +30,7 @@ get: + summary: Retrieve all projects of an organization + tags: + - Organizations ++ x-equinix-metal-paginated-property: Projects + post: + description: Creates a new project for the organization + operationId: createOrganizationProject +diff --git a/spec/oas3.patched/paths/projects.yaml b/spec/oas3.patched/paths/projects.yaml +index e9c147a..19312f2 100644 +--- a/spec/oas3.patched/paths/projects.yaml ++++ b/spec/oas3.patched/paths/projects.yaml +@@ -24,6 +24,7 @@ get: + summary: Retrieve all projects + tags: + - Projects ++ x-equinix-metal-paginated-property: Projects + post: + description: Creates a new project for the user default organization. If the user + don't have an organization, a new one will be created. +diff --git a/spec/oas3.patched/paths/projects/id/devices.yaml b/spec/oas3.patched/paths/projects/id/devices.yaml +index c939c98..836099e 100644 +--- a/spec/oas3.patched/paths/projects/id/devices.yaml ++++ b/spec/oas3.patched/paths/projects/id/devices.yaml +@@ -83,6 +86,7 @@ get: + summary: Retrieve all devices of a project + tags: + - Devices ++ x-equinix-metal-paginated-property: Devices + post: + description: |- + Creates a new device and provisions it in the specified location. +diff --git a/spec/oas3.patched/paths/projects/id/events.yaml b/spec/oas3.patched/paths/projects/id/events.yaml +index 233f1f9..9c0119e 100644 +--- a/spec/oas3.patched/paths/projects/id/events.yaml ++++ b/spec/oas3.patched/paths/projects/id/events.yaml +@@ -41,3 +41,4 @@ get: + summary: Retrieve project's events + tags: + - Events ++ x-equinix-metal-paginated-property: Events +diff --git a/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml b/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml +index 5d95c14..37d7935 100644 +--- a/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml ++++ b/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml +@@ -62,3 +63,4 @@ get: + summary: Retrieve all hardware reservations for a given project + tags: + - HardwareReservations ++ x-equinix-metal-paginated-property: HardwareReservations +diff --git a/spec/oas3.patched/paths/projects/project_id/connections.yaml b/spec/oas3.patched/paths/projects/project_id/connections.yaml +index f00ac06..b9dda2b 100644 +--- a/spec/oas3.patched/paths/projects/project_id/connections.yaml ++++ b/spec/oas3.patched/paths/projects/project_id/connections.yaml +@@ -35,6 +35,7 @@ get: + summary: List project connections + tags: + - Interconnections ++ x-equinix-metal-paginated-property: Interconnections + post: + description: Creates a new interconnection request + operationId: createProjectInterconnection +diff --git a/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml b/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml +index 3ab78d3..cd306e7 100644 +--- a/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml ++++ b/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml +@@ -35,6 +35,7 @@ get: + summary: Returns all metal gateways for a project + tags: + - MetalGateways ++ x-equinix-metal-paginated-property: MetalGateways + post: + description: Create a metal gateway in a project + operationId: createMetalGateway +diff --git a/spec/oas3.patched/paths/users.yaml b/spec/oas3.patched/paths/users.yaml +index ce1b579..b9e6977 100644 +--- a/spec/oas3.patched/paths/users.yaml ++++ b/spec/oas3.patched/paths/users.yaml +@@ -23,6 +23,7 @@ get: + summary: Retrieve all users + tags: + - Users ++ x-equinix-metal-paginated-property: Users + post: + description: Creates a user. + operationId: createUser diff --git a/script/mark_paginated.py b/script/mark_paginated.py new file mode 100755 index 00000000..67c9c27d --- /dev/null +++ b/script/mark_paginated.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +# This script isn't run from Makefile. It's here to help generate patch for the +# x-paginated object. The x-paginated object marks that all-pages-listing +# method should be generated for given operation, think listing of devices +# in a project with more than 20 devices. + +# example run: +# for o in `find spec/oas3.patched/paths -name '*.yaml'`; do script/mark_paginated.py $o; done + +import sys +import os +import os.path +import ruamel.yaml + +yaml = ruamel.yaml.YAML() +yaml.preserve_quotes = True + +ymlfile = sys.argv[1] + +def getYaml(fn): + with open(fn) as f: + return yaml.load(f.read()) + +paginated = False +paginatedProperty = None + +operation = getYaml(ymlfile) + +def toGolangPropertyName(s): + return "".join([w.capitalize() for w in s.split("_")]) + +refkey = "$ref" +if "get" in operation: + getop = operation['get'] + if "parameters" in getop: + getopparams = getop['parameters'] + for p in getopparams: + if refkey in p: + if "/components/parameters/Page.yaml" in p[refkey]: + schemaPathRelative = getop['responses']['200']['content']['application/json']['schema']['$ref'] + schemaPath = schemaPathRelative.split("../")[-1] + twoTopDirs = ymlfile.split("/")[:2] + specDir = os.path.dirname(ymlfile) + schemaFile = os.path.join(twoTopDirs[0], twoTopDirs[1], schemaPath) + responseSchema = getYaml(schemaFile) + responseProps = set(responseSchema['properties'].keys()) + oid = getop['operationId'] + if 'meta' in responseProps: + responseProps.remove("meta") + else: + print("%s => %s doesn't have 'meta', and therefore no PageNum etc" % (oid, schemaFile)) + break + if len(responseProps) > 1: + print("%s => %s has 'page' but ambiguous response type with args %s" % + (oid, schemaFile, responseProps)) + break + print("marking %s as paginated" % oid) + paginated = True + paginatedProperty = toGolangPropertyName(responseProps.pop()) + break + + +if paginated: + operation['get']['x-equinix-metal-paginated-property'] = paginatedProperty + with open(ymlfile,"w") as f: + yaml.dump(operation, f) + + diff --git a/spec/oas3.patched/paths/connections/connection_id/events.yaml b/spec/oas3.patched/paths/connections/connection_id/events.yaml index 8d2121bc..e797a392 100644 --- a/spec/oas3.patched/paths/connections/connection_id/events.yaml +++ b/spec/oas3.patched/paths/connections/connection_id/events.yaml @@ -41,3 +41,4 @@ get: summary: Retrieve interconnection events tags: - Events + x-equinix-metal-paginated-property: Events diff --git a/spec/oas3.patched/paths/devices/id/events.yaml b/spec/oas3.patched/paths/devices/id/events.yaml index 62a179c5..470b51ea 100644 --- a/spec/oas3.patched/paths/devices/id/events.yaml +++ b/spec/oas3.patched/paths/devices/id/events.yaml @@ -41,3 +41,4 @@ get: summary: Retrieve device's events tags: - Events + x-equinix-metal-paginated-property: Events diff --git a/spec/oas3.patched/paths/events.yaml b/spec/oas3.patched/paths/events.yaml index 6e5042d7..7efcc877 100644 --- a/spec/oas3.patched/paths/events.yaml +++ b/spec/oas3.patched/paths/events.yaml @@ -22,3 +22,4 @@ get: summary: Retrieve current user's events tags: - Events + x-equinix-metal-paginated-property: Events diff --git a/spec/oas3.patched/paths/organizations.yaml b/spec/oas3.patched/paths/organizations.yaml index 0a21aaf9..0a43328f 100644 --- a/spec/oas3.patched/paths/organizations.yaml +++ b/spec/oas3.patched/paths/organizations.yaml @@ -41,6 +41,7 @@ get: summary: Retrieve all organizations tags: - Organizations + x-equinix-metal-paginated-property: Organizations post: description: Creates an organization. operationId: createOrganization diff --git a/spec/oas3.patched/paths/organizations/id/devices.yaml b/spec/oas3.patched/paths/organizations/id/devices.yaml index 93098435..e04d5822 100644 --- a/spec/oas3.patched/paths/organizations/id/devices.yaml +++ b/spec/oas3.patched/paths/organizations/id/devices.yaml @@ -83,3 +83,4 @@ get: summary: Retrieve all devices of an organization tags: - Devices + x-equinix-metal-paginated-property: Devices diff --git a/spec/oas3.patched/paths/organizations/id/events.yaml b/spec/oas3.patched/paths/organizations/id/events.yaml index cd713da2..e184181c 100644 --- a/spec/oas3.patched/paths/organizations/id/events.yaml +++ b/spec/oas3.patched/paths/organizations/id/events.yaml @@ -41,3 +41,4 @@ get: summary: Retrieve organization's events tags: - Events + x-equinix-metal-paginated-property: Events diff --git a/spec/oas3.patched/paths/organizations/id/projects.yaml b/spec/oas3.patched/paths/organizations/id/projects.yaml index 004a17e2..3ccaf571 100644 --- a/spec/oas3.patched/paths/organizations/id/projects.yaml +++ b/spec/oas3.patched/paths/organizations/id/projects.yaml @@ -30,6 +30,7 @@ get: summary: Retrieve all projects of an organization tags: - Organizations + x-equinix-metal-paginated-property: Projects post: description: Creates a new project for the organization operationId: createOrganizationProject diff --git a/spec/oas3.patched/paths/projects.yaml b/spec/oas3.patched/paths/projects.yaml index e9c147a9..19312f2f 100644 --- a/spec/oas3.patched/paths/projects.yaml +++ b/spec/oas3.patched/paths/projects.yaml @@ -24,6 +24,7 @@ get: summary: Retrieve all projects tags: - Projects + x-equinix-metal-paginated-property: Projects post: description: Creates a new project for the user default organization. If the user don't have an organization, a new one will be created. diff --git a/spec/oas3.patched/paths/projects/id/devices.yaml b/spec/oas3.patched/paths/projects/id/devices.yaml index c939c980..290006f7 100644 --- a/spec/oas3.patched/paths/projects/id/devices.yaml +++ b/spec/oas3.patched/paths/projects/id/devices.yaml @@ -83,6 +83,7 @@ get: summary: Retrieve all devices of a project tags: - Devices + x-equinix-metal-paginated-property: Devices post: description: |- Creates a new device and provisions it in the specified location. diff --git a/spec/oas3.patched/paths/projects/id/events.yaml b/spec/oas3.patched/paths/projects/id/events.yaml index 233f1f91..9c0119e2 100644 --- a/spec/oas3.patched/paths/projects/id/events.yaml +++ b/spec/oas3.patched/paths/projects/id/events.yaml @@ -41,3 +41,4 @@ get: summary: Retrieve project's events tags: - Events + x-equinix-metal-paginated-property: Events diff --git a/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml b/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml index 5d95c144..beddc6fc 100644 --- a/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml +++ b/spec/oas3.patched/paths/projects/id/hardware-reservations.yaml @@ -62,3 +62,4 @@ get: summary: Retrieve all hardware reservations for a given project tags: - HardwareReservations + x-equinix-metal-paginated-property: HardwareReservations diff --git a/spec/oas3.patched/paths/projects/project_id/connections.yaml b/spec/oas3.patched/paths/projects/project_id/connections.yaml index f00ac06c..b9dda2bb 100644 --- a/spec/oas3.patched/paths/projects/project_id/connections.yaml +++ b/spec/oas3.patched/paths/projects/project_id/connections.yaml @@ -35,6 +35,7 @@ get: summary: List project connections tags: - Interconnections + x-equinix-metal-paginated-property: Interconnections post: description: Creates a new interconnection request operationId: createProjectInterconnection diff --git a/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml b/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml index 3ab78d3a..cd306e74 100644 --- a/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml +++ b/spec/oas3.patched/paths/projects/project_id/metal-gateways.yaml @@ -35,6 +35,7 @@ get: summary: Returns all metal gateways for a project tags: - MetalGateways + x-equinix-metal-paginated-property: MetalGateways post: description: Create a metal gateway in a project operationId: createMetalGateway diff --git a/spec/oas3.patched/paths/users.yaml b/spec/oas3.patched/paths/users.yaml index ce1b579a..6add348a 100644 --- a/spec/oas3.patched/paths/users.yaml +++ b/spec/oas3.patched/paths/users.yaml @@ -23,6 +23,7 @@ get: summary: Retrieve all users tags: - Users + x-equinix-metal-paginated-property: Users post: description: Creates a user. operationId: createUser diff --git a/templates/api.mustache b/templates/api.mustache new file mode 100644 index 00000000..7e8348c0 --- /dev/null +++ b/templates/api.mustache @@ -0,0 +1,444 @@ +{{>partial_header}} +package {{packageName}} + +{{#operations}} +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" +{{#imports}} "{{import}}" +{{/imports}} +) + +{{#generateInterfaces}} + +type {{classname}} interface { + {{#operation}} + + /* + {{operationId}} {{{summary}}}{{^summary}}Method for {{operationId}}{{/summary}} + {{#notes}} + + {{{unescapedNotes}}} + {{/notes}} + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().{{#pathParams}} + @param {{paramName}}{{#description}} {{{.}}}{{/description}}{{/pathParams}} + @return {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request + {{#isDeprecated}} + + Deprecated + {{/isDeprecated}} + */ + {{{nickname}}}(ctx context.Context{{#pathParams}}, {{paramName}} {{{dataType}}}{{/pathParams}}) {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request + + // {{nickname}}Execute executes the request{{#returnType}} + // @return {{{.}}}{{/returnType}} + {{#isDeprecated}} + // Deprecated + {{/isDeprecated}} + {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) + {{/operation}} +} +{{/generateInterfaces}} + +// {{classname}}Service {{classname}} service +type {{classname}}Service service +{{#operation}} + +type {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request struct { + ctx context.Context{{#generateInterfaces}} + ApiService {{classname}} +{{/generateInterfaces}}{{^generateInterfaces}} + ApiService *{{classname}}Service +{{/generateInterfaces}} +{{#allParams}} + {{paramName}} {{^isPathParam}}{{^isFile}}*{{/isFile}}{{/isPathParam}}{{{dataType}}} +{{/allParams}} +} + +{{#allParams}} +{{^isPathParam}} +{{#description}} +// {{.}} +{{/description}} +{{#isDeprecated}} +// Deprecated +{{/isDeprecated}} +func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) {{vendorExtensions.x-export-param-name}}({{paramName}} {{{dataType}}}) {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request { + r.{{paramName}} = {{^isFile}}&{{/isFile}}{{paramName}} + return r +} + +{{/isPathParam}} +{{/allParams}} +func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) Execute() ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) { + return r.ApiService.{{nickname}}Execute(r) +} + +/* +{{operationId}} {{{summary}}}{{^summary}}Method for {{operationId}}{{/summary}} +{{#notes}} + +{{{unescapedNotes}}} +{{/notes}} + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().{{#pathParams}} + @param {{paramName}}{{#description}} {{{.}}}{{/description}}{{/pathParams}} + @return {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request +{{#isDeprecated}} + +Deprecated +{{/isDeprecated}} +*/ +func (a *{{{classname}}}Service) {{{nickname}}}(ctx context.Context{{#pathParams}}, {{paramName}} {{{dataType}}}{{/pathParams}}) {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request { + return {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request{ + ApiService: a, + ctx: ctx, + {{#pathParams}} + {{paramName}}: {{paramName}}, + {{/pathParams}} + } +} + +// Execute executes the request{{#returnType}} +// @return {{{.}}}{{/returnType}} +{{#isDeprecated}} +// Deprecated +{{/isDeprecated}} +func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) { + var ( + localVarHTTPMethod = http.Method{{httpMethod}} + localVarPostBody interface{} + formFiles []formFile + {{#returnType}} + localVarReturnValue {{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}} + {{/returnType}} + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "{{{classname}}}Service.{{{nickname}}}") + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "{{{path}}}"{{#pathParams}} + localVarPath = strings.Replace(localVarPath, "{"+"{{baseName}}"+"}", url.PathEscape(parameterValueToString(r.{{paramName}}, "{{paramName}}")), -1){{/pathParams}} + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + {{#allParams}} + {{#required}} + {{^isPathParam}} + if r.{{paramName}} == nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} is required and must be specified") + } + {{/isPathParam}} + {{#minItems}} + if len({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) < {{minItems}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minItems}} elements") + } + {{/minItems}} + {{#maxItems}} + if len({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) > {{maxItems}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxItems}} elements") + } + {{/maxItems}} + {{#minLength}} + if strlen({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) < {{minLength}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minLength}} elements") + } + {{/minLength}} + {{#maxLength}} + if strlen({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) > {{maxLength}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxLength}} elements") + } + {{/maxLength}} + {{#minimum}} + {{#isString}} + {{paramName}}Txt, err := atoi({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) + if {{paramName}}Txt < {{minimum}} { + {{/isString}} + {{^isString}} + if {{^isPathParam}}*{{/isPathParam}}r.{{paramName}} < {{minimum}} { + {{/isString}} + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must be greater than {{minimum}}") + } + {{/minimum}} + {{#maximum}} + {{#isString}} + {{paramName}}Txt, err := atoi({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) + if {{paramName}}Txt > {{maximum}} { + {{/isString}} + {{^isString}} + if {{^isPathParam}}*{{/isPathParam}}r.{{paramName}} > {{maximum}} { + {{/isString}} + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must be less than {{maximum}}") + } + {{/maximum}} + {{/required}} + {{/allParams}} + + {{#queryParams}} + {{#required}} + {{#isCollectionFormatMulti}} + { + t := *r.{{paramName}} + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", s.Index(i).Interface(), "{{collectionFormat}}") + } + } else { + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", t, "{{collectionFormat}}") + } + } + {{/isCollectionFormatMulti}} + {{^isCollectionFormatMulti}} + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") + {{/isCollectionFormatMulti}} + {{/required}} + {{^required}} + if r.{{paramName}} != nil { + {{#isCollectionFormatMulti}} + t := *r.{{paramName}} + if reflect.TypeOf(t).Kind() == reflect.Slice { + s := reflect.ValueOf(t) + for i := 0; i < s.Len(); i++ { + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", s.Index(i).Interface(), "{{collectionFormat}}") + } + } else { + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", t, "{{collectionFormat}}") + } + {{/isCollectionFormatMulti}} + {{^isCollectionFormatMulti}} + parameterAddToHeaderOrQuery(localVarQueryParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") + {{/isCollectionFormatMulti}} + } + {{/required}} + {{/queryParams}} + // to determine the Content-Type header +{{=<% %>=}} + localVarHTTPContentTypes := []string{<%#consumes%>"<%&mediaType%>"<%^-last%>, <%/-last%><%/consumes%>} +<%={{ }}=%> + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header +{{=<% %>=}} + localVarHTTPHeaderAccepts := []string{<%#produces%>"<%&mediaType%>"<%^-last%>, <%/-last%><%/produces%>} +<%={{ }}=%> + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } +{{#headerParams}} + {{#required}} + parameterAddToHeaderOrQuery(localVarHeaderParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") + {{/required}} + {{^required}} + if r.{{paramName}} != nil { + parameterAddToHeaderOrQuery(localVarHeaderParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") + } + {{/required}} +{{/headerParams}} +{{#formParams}} +{{#isFile}} + var {{paramName}}LocalVarFormFileName string + var {{paramName}}LocalVarFileName string + var {{paramName}}LocalVarFileBytes []byte + + {{paramName}}LocalVarFormFileName = "{{baseName}}" + + + {{paramName}}LocalVarFile := r.{{paramName}} + + if {{paramName}}LocalVarFile != nil { + fbs, _ := io.ReadAll({{paramName}}LocalVarFile) + + {{paramName}}LocalVarFileBytes = fbs + {{paramName}}LocalVarFileName = {{paramName}}LocalVarFile.Name() + {{paramName}}LocalVarFile.Close() + formFiles = append(formFiles, formFile{fileBytes: {{paramName}}LocalVarFileBytes, fileName: {{paramName}}LocalVarFileName, formFileName: {{paramName}}LocalVarFormFileName}) + } +{{/isFile}} +{{^isFile}} +{{#required}} + parameterAddToHeaderOrQuery(localVarFormParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") +{{/required}} +{{^required}} +{{#isModel}} + if r.{{paramName}} != nil { + paramJson, err := parameterToJson(*r.{{paramName}}) + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, err + } + localVarFormParams.Add("{{baseName}}", paramJson) + } +{{/isModel}} +{{^isModel}} + if r.{{paramName}} != nil { + parameterAddToHeaderOrQuery(localVarFormParams, "{{baseName}}", r.{{paramName}}, "{{collectionFormat}}") + } +{{/isModel}} +{{/required}} +{{/isFile}} +{{/formParams}} +{{#bodyParams}} + // body params + localVarPostBody = r.{{paramName}} +{{/bodyParams}} +{{#authMethods}} +{{#isApiKey}} +{{^isKeyInCookie}} + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + {{#vendorExtensions.x-auth-id-alias}} + if apiKey, ok := auth["{{.}}"]; ok { + var key string + if prefix, ok := auth["{{name}}"]; ok && prefix.Prefix != "" { + key = prefix.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + {{/vendorExtensions.x-auth-id-alias}} + {{^vendorExtensions.x-auth-id-alias}} + if apiKey, ok := auth["{{name}}"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + {{/vendorExtensions.x-auth-id-alias}} + {{#isKeyInHeader}} + localVarHeaderParams["{{keyParamName}}"] = key + {{/isKeyInHeader}} + {{#isKeyInQuery}} + localVarQueryParams.Add("{{keyParamName}}", key) + {{/isKeyInQuery}} + } + } + } +{{/isKeyInCookie}} +{{/isApiKey}} +{{/authMethods}} + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + {{#responses}} + {{#dataType}} + {{^is1xx}} + {{^is2xx}} + {{#range}} + {{#is3xx}} + if localVarHTTPResponse.StatusCode >= 300 && localVarHTTPResponse.StatusCode < 400 { + {{/is3xx}} + {{#is4xx}} + if localVarHTTPResponse.StatusCode >= 400 && localVarHTTPResponse.StatusCode < 500 { + {{/is4xx}} + {{#is5xx}} + if localVarHTTPResponse.StatusCode >= 500 { + {{/is5xx}} + {{/range}} + {{^range}} + {{^wildcard}} + if localVarHTTPResponse.StatusCode == {{{code}}} { + {{/wildcard}} + {{/range}} + var v {{{dataType}}} + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + {{^-last}} + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, newErr + {{/-last}} + {{^wildcard}} + } + {{/wildcard}} + {{/is2xx}} + {{/is1xx}} + {{/dataType}} + {{/responses}} + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, newErr + } + + {{#returnType}} + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, newErr + } + + {{/returnType}} + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHTTPResponse, nil +} + +{{#vendorExtensions}} +{{#x-equinix-metal-paginated-property}} +// ExecuteWithPagination executes the request to fetch and return all pages of results as a single slice{{#returnType}} +// @return {{{.}}}{{/returnType}} +{{#isDeprecated}} +// Deprecated +{{/isDeprecated}} +func (r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ExecuteWithPagination() (*{{returnType}}, error) { + + var items {{returnType}} + + pageNumber := int32(1) + + for { + page, _, err := r.Page(pageNumber).Execute() + if err != nil { + return nil, err + } + + items.{{.}} = append(items.{{.}}, page.{{.}}...) + if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() { + break + } + pageNumber = page.Meta.GetCurrentPage() + 1 + } + + return &items, nil +} +{{/x-equinix-metal-paginated-property}} +{{/vendorExtensions}} + +{{/operation}} +{{/operations}} diff --git a/templates/api_doc.mustache b/templates/api_doc.mustache new file mode 100644 index 00000000..9b2811c1 --- /dev/null +++ b/templates/api_doc.mustache @@ -0,0 +1,97 @@ +# {{invokerPackage}}\{{classname}}{{#description}} + +{{.}}{{/description}} + +All URIs are relative to *{{basePath}}* + +Method | HTTP request | Description +------------- | ------------- | ------------- +{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{summary}} +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} + +## {{{operationId}}} + +> {{#returnType}}{{{.}}} {{/returnType}}{{{operationId}}}(ctx{{#pathParams}}, {{paramName}}{{/pathParams}}){{#allParams}}{{^isPathParam}}.{{vendorExtensions.x-export-param-name}}({{paramName}}){{/isPathParam}}{{/allParams}}.Execute() + +{{{summary}}}{{#notes}} + +{{{unespacedNotes}}}{{/notes}} +{{#vendorExtensions}} +{{#x-equinix-metal-paginated-property}} +{{{operationId}}} is a paginated API operation. You can specify page number and per page parameters with `Execute`, or to fetch and return all pages of results as a single slice you can call `ExecuteWithPagination()`. `ExecuteWithPagination()`, while convenient, can significantly increase the overhead of API calls in terms of time, network utilization, and memory. Excludes can make the call more efficient by removing any unneeded nested fields that are included by default. If any of the requests fail, the list of results will be nil and the error returned will represent the failed request. +{{/x-equinix-metal-paginated-property}} +{{/vendorExtensions}} + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" +{{#vendorExtensions.x-go-import}} +{{{vendorExtensions.x-go-import}}} +{{/vendorExtensions.x-go-import}} + {{goImportAlias}} "{{gitHost}}/{{gitUserId}}/{{gitRepoId}}{{#isGoSubmodule}}/{{packageName}}{{/isGoSubmodule}}" +) + +func main() { + {{#allParams}} + {{paramName}} := {{{vendorExtensions.x-go-example}}} // {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} + {{/allParams}} + + configuration := {{goImportAlias}}.NewConfiguration() + apiClient := {{goImportAlias}}.NewAPIClient(configuration) + {{#returnType}}resp, {{/returnType}}r, err := apiClient.{{classname}}.{{operationId}}(context.Background(){{#pathParams}}, {{paramName}}{{/pathParams}}){{#allParams}}{{^isPathParam}}.{{vendorExtensions.x-export-param-name}}({{paramName}}){{/isPathParam}}{{/allParams}}.Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `{{classname}}.{{operationId}}``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + {{#returnType}} + // response from `{{operationId}}`: {{{.}}} + fmt.Fprintf(os.Stdout, "Response from `{{classname}}.{{operationId}}`: %v\n", resp) + {{/returnType}} +} +``` + +### Path Parameters + +{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#pathParams}}{{#-last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc.{{/-last}}{{/pathParams}}{{#pathParams}} +**{{paramName}}** | {{^isPrimitiveType}}{{^isFile}}[{{/isFile}}{{/isPrimitiveType}}**{{dataType}}**{{^isPrimitiveType}}{{^isFile}}]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}} | {{description}} | {{#defaultValue}}[default to {{.}}]{{/defaultValue}}{{/pathParams}} + +### Other Parameters + +Other parameters are passed through a pointer to a api{{{nickname}}}Request struct via the builder pattern +{{#allParams}}{{#-last}} + +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}{{#allParams}} +{{^isPathParam}} **{{paramName}}** | {{#isContainer}}{{#isArray}}{{#items}}{{^isPrimitiveType}}{{^isFile}}[{{/isFile}}{{/isPrimitiveType}}**[]{{dataType}}**{{^isPrimitiveType}}{{^isFile}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isFile}}{{/isPrimitiveType}}{{/items}}{{/isArray}}{{#isMap}}{{#items}}{{^isPrimitiveType}}{{^isFile}}[{{/isFile}}{{/isPrimitiveType}}**map[string]{{dataType}}**{{^isPrimitiveType}}{{^isFile}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isFile}}{{/isPrimitiveType}}{{/items}}{{/isMap}}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}{{^isFile}}[{{/isFile}}{{/isPrimitiveType}}**{{dataType}}**{{^isPrimitiveType}}{{^isFile}}]({{^baseType}}{{dataType}}{{/baseType}}{{baseType}}.md){{/isFile}}{{/isPrimitiveType}}{{/isContainer}} | {{description}} | {{#defaultValue}}[default to {{.}}]{{/defaultValue}}{{/isPathParam}}{{/allParams}} + +### Return type + +{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}} (empty response body){{/returnType}} + +### Authorization + +{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}} + +### HTTP request headers + +- **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} +- **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}} + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + +{{/operation}} +{{/operations}} diff --git a/templates/api_test.mustache b/templates/api_test.mustache new file mode 100644 index 00000000..57c9a45b --- /dev/null +++ b/templates/api_test.mustache @@ -0,0 +1,64 @@ +/* +{{#appName}} +{{{.}}} +{{/appName}} + +Testing {{classname}}Service + +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); + +package {{packageName}} + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" + {{goImportAlias}} "{{gitHost}}/{{gitUserId}}/{{gitRepoId}}{{#isGoSubmodule}}/{{packageName}}{{/isGoSubmodule}}" +) + +func Test_{{packageName}}_{{classname}}Service(t *testing.T) { + + configuration := {{goImportAlias}}.NewConfiguration() + apiClient := {{goImportAlias}}.NewAPIClient(configuration) + +{{#operations}} +{{#operation}} + t.Run("Test {{classname}}Service {{{nickname}}}", func(t *testing.T) { + + {{^pathParams}} + t.Skip("skip test") // remove to run test + {{/pathParams}} + {{#pathParams}} + {{#-first}} + t.Skip("skip test") // remove to run test + + {{/-first}} + var {{paramName}} {{{dataType}}} + {{/pathParams}} + + {{#returnType}}resp, {{/returnType}}httpRes, err := apiClient.{{classname}}.{{operationId}}(context.Background(){{#pathParams}}, {{paramName}}{{/pathParams}}).Execute() + + require.Nil(t, err) + {{#returnType}} + require.NotNil(t, resp) + {{/returnType}} + assert.Equal(t, 200, httpRes.StatusCode) +{{#vendorExtensions}} +{{#x-equinix-metal-paginated-property}} + + {{#returnType}}resp, {{/returnType}}err = apiClient.{{classname}}.{{operationId}}(context.Background(){{#pathParams}}, {{paramName}}{{/pathParams}}).ExecuteWithPagination() + require.Nil(t, err) + {{#returnType}} + require.NotNil(t, resp) + {{/returnType}} +{{/x-equinix-metal-paginated-property}} +{{/vendorExtensions}} + + }) + +{{/operation}} +{{/operations}} +}