From 3db6b526f4f79de1fc6463e1303285e8bb491c73 Mon Sep 17 00:00:00 2001 From: Mehmet Fatih Ercik Date: Tue, 20 Feb 2024 08:37:44 +0100 Subject: [PATCH] Generate API files as interfaces for go-gin server (#17784) * add feature to generate only interface files * generate sample * add workflow file foe go gin service * add workflow file foe go gin service * add workflow file foe go gin service * update samples --- .github/workflows/samples-go-gin.yaml | 31 + ...rver-go-gin-api-server-interface-only.yaml | 8 + docs/generators/go-gin-server.md | 1 + .../codegen/languages/GoGinServerCodegen.java | 19 + .../go-gin-server/interface-api.mustache | 22 + .../goginserver/GoGinServerCodegenTest.java | 52 +- .../.openapi-generator-ignore | 23 + .../.openapi-generator/FILES | 15 + .../.openapi-generator/VERSION | 1 + .../Dockerfile | 16 + .../api/openapi.yaml | 811 ++++++++++++++++++ .../go-gin-api-server-interface-only/go.mod | 32 + .../go/README.md | 39 + .../go/api_pet.go | 52 ++ .../go/api_store.go | 35 + .../go/api_user.go | 51 ++ .../go/model_api_response.go | 20 + .../go/model_category.go | 18 + .../go/model_order.go | 31 + .../go/model_pet.go | 28 + .../go/model_tag.go | 18 + .../go/model_user.go | 31 + .../go/routers.go | 196 +++++ .../go-gin-api-server-interface-only/main.go | 29 + 24 files changed, 1559 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/samples-go-gin.yaml create mode 100644 bin/configs/go-gin-server-go-gin-api-server-interface-only.yaml create mode 100644 modules/openapi-generator/src/main/resources/go-gin-server/interface-api.mustache create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator-ignore create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/FILES create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/VERSION create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/Dockerfile create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/api/openapi.yaml create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go.mod create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/README.md create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/api_pet.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/api_store.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/api_user.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_api_response.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_category.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_order.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_pet.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_tag.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/model_user.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/go/routers.go create mode 100644 samples/server/petstore/go-gin-api-server-interface-only/main.go diff --git a/.github/workflows/samples-go-gin.yaml b/.github/workflows/samples-go-gin.yaml new file mode 100644 index 000000000000..ba2da3f55cdc --- /dev/null +++ b/.github/workflows/samples-go-gin.yaml @@ -0,0 +1,31 @@ +name: Samples Go + +on: + push: + paths: + - 'samples/server/petstore/go-gin-api-server/**' + - 'samples/server/petstore/go-gin-api-server-interface-only/**' + pull_request: + paths: + - 'samples/server/petstore/go-gin-api-server/**' + - 'samples/server/petstore/go-gin-api-server-interface-only/**' + +jobs: + build: + name: Build Go + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sample: + - samples/server/petstore/go-gin-api-server/ + - samples/server/petstore/go-gin-api-server-interface-only/ + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "stable" + - run: go version + - name: Run test + working-directory: ${{ matrix.sample }} + run: go test -mod=mod -v diff --git a/bin/configs/go-gin-server-go-gin-api-server-interface-only.yaml b/bin/configs/go-gin-server-go-gin-api-server-interface-only.yaml new file mode 100644 index 000000000000..4bb396fcdced --- /dev/null +++ b/bin/configs/go-gin-server-go-gin-api-server-interface-only.yaml @@ -0,0 +1,8 @@ +generatorName: go-gin-server +outputDir: samples/server/petstore/go-gin-api-server-interface-only +inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml +templateDir: modules/openapi-generator/src/main/resources/go-gin-server +additionalProperties: + hideGenerationTimestamp: "true" + packageName: petstoreserver + interfaceOnly: true diff --git a/docs/generators/go-gin-server.md b/docs/generators/go-gin-server.md index 6cc2e828ec63..60e8653c13c0 100644 --- a/docs/generators/go-gin-server.md +++ b/docs/generators/go-gin-server.md @@ -21,6 +21,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |apiPath|Name of the folder that contains the Go source code| |go| |enumClassPrefix|Prefix enum with class name| |false| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true| +|interfaceOnly|Whether to generate only API interface stubs without the implementation files.| |false| |packageName|Go package name (convention: lowercase).| |openapi| |packageVersion|Go package version.| |1.0.0| |serverPort|The network port the generated server binds to| |8080| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoGinServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoGinServerCodegen.java index af46f6f7405c..34d7a80cbebd 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoGinServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoGinServerCodegen.java @@ -38,6 +38,10 @@ public class GoGinServerCodegen extends AbstractGoCodegen { private final Logger LOGGER = LoggerFactory.getLogger(GoGinServerCodegen.class); + public static final String INTERFACE_ONLY = "interfaceOnly"; + + protected boolean interfaceOnly = false; + protected String apiVersion = "1.0.0"; protected int serverPort = 8080; protected String projectName = "openapi-server"; @@ -114,6 +118,8 @@ public GoGinServerCodegen() { cliOptions.add(new CliOption("apiPath", "Name of the folder that contains the Go source code") .defaultValue(apiPath)); + cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, + "Whether to generate only API interface stubs without the implementation files.", interfaceOnly)); CliOption optServerPort = new CliOption("serverPort", "The network port the generated server binds to"); optServerPort.setType("int"); @@ -148,6 +154,10 @@ public void processOpts() { additionalProperties.put(CodegenConstants.PACKAGE_NAME, this.packageName); } + if (additionalProperties.containsKey(INTERFACE_ONLY)) { + this.setInterfaceOnly(Boolean.parseBoolean(additionalProperties.get(INTERFACE_ONLY).toString())); + } + /* * Additional Properties. These values can be passed to the templates and * are available in models, apis, and supporting files @@ -180,6 +190,11 @@ public void processOpts() { modelPackage = packageName; apiPackage = packageName; + if (interfaceOnly) { + apiTemplateFiles.clear(); + apiTemplateFiles.put("interface-api.mustache", ".go"); + } + /* * Supporting Files. You can write single files for the generator with the * entire object tree available. If the input file has a suffix of `.mustache @@ -194,6 +209,10 @@ public void processOpts() { supportingFiles.add(new SupportingFile("go.mod.mustache", "go.mod")); } + public void setInterfaceOnly(boolean interfaceOnly) { + this.interfaceOnly = interfaceOnly; + } + @Override public String apiPackage() { return apiPath; diff --git a/modules/openapi-generator/src/main/resources/go-gin-server/interface-api.mustache b/modules/openapi-generator/src/main/resources/go-gin-server/interface-api.mustache new file mode 100644 index 000000000000..0f52d3954d47 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/go-gin-server/interface-api.mustache @@ -0,0 +1,22 @@ +{{>partial_header}} +package {{packageName}} + +{{#operations}} +import ( + "github.com/gin-gonic/gin" +) + +type {{classname}} interface { + + + {{#operation}} + // {{nickname}} {{httpMethod}} {{{basePathWithoutHost}}}{{{path}}}{{#summary}} + // {{{.}}} {{/summary}} + {{#isDeprecated}} + // Deprecated + {{/isDeprecated}} + {{nickname}}(c *gin.Context) + + {{/operation}} + {{/operations}} +} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/goginserver/GoGinServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/goginserver/GoGinServerCodegenTest.java index 4d70aa6591dc..6fa9b0ee2a3d 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/goginserver/GoGinServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/goginserver/GoGinServerCodegenTest.java @@ -17,20 +17,16 @@ package org.openapitools.codegen.goginserver; -import org.openapitools.codegen.*; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.TestUtils; import org.openapitools.codegen.config.CodegenConfigurator; -import org.openapitools.codegen.languages.GoClientCodegen; -import org.testng.Assert; import org.testng.annotations.Test; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class GoGinServerCodegenTest { @@ -40,13 +36,8 @@ public void verifyGoMod() throws IOException { File output = Files.createTempDirectory("test").toFile(); output.deleteOnExit(); - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("go-gin-server") - .setGitUserId("my-user") - .setGitRepoId("my-repo") - .setPackageName("my-package") - .setInputSpec("src/test/resources/3_0/petstore.yaml") - .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + final CodegenConfigurator configurator = createDefaultCodegenConfigurator(output) + .setInputSpec("src/test/resources/3_0/petstore.yaml"); DefaultGenerator generator = new DefaultGenerator(); List files = generator.opts(configurator.toClientOptInput()).generate(); @@ -64,13 +55,8 @@ public void webhooks() throws IOException { File output = Files.createTempDirectory("test").toFile(); output.deleteOnExit(); - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName("go-gin-server") - .setGitUserId("my-user") - .setGitRepoId("my-repo") - .setPackageName("my-package") - .setInputSpec("src/test/resources/3_1/webhooks.yaml") - .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + final CodegenConfigurator configurator = createDefaultCodegenConfigurator(output) + .setInputSpec("src/test/resources/3_1/webhooks.yaml"); DefaultGenerator generator = new DefaultGenerator(); List files = generator.opts(configurator.toClientOptInput()).generate(); @@ -82,4 +68,30 @@ public void webhooks() throws IOException { " c.JSON(200, gin.H{\"status\": \"OK\"})"); } + @Test + public void verifyInterfaceOnly() throws IOException { + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = createDefaultCodegenConfigurator(output) + .setInputSpec("src/test/resources/3_0/petstore.yaml") + .addAdditionalProperty("interfaceOnly", true); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + TestUtils.assertFileContains(Paths.get(output + "/go/api_pet.go"), + "type PetAPI interface"); + } + + private static CodegenConfigurator createDefaultCodegenConfigurator(File output) { + return new CodegenConfigurator() + .setGeneratorName("go-gin-server") + .setGitUserId("my-user") + .setGitRepoId("my-repo") + .setPackageName("my-package") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + } + } diff --git a/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator-ignore b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator-ignore new file mode 100644 index 000000000000..7484ee590a38 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/FILES b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/FILES new file mode 100644 index 000000000000..52dc8b1a0dab --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/FILES @@ -0,0 +1,15 @@ +Dockerfile +api/openapi.yaml +go.mod +go/README.md +go/api_pet.go +go/api_store.go +go/api_user.go +go/model_api_response.go +go/model_category.go +go/model_order.go +go/model_pet.go +go/model_tag.go +go/model_user.go +go/routers.go +main.go diff --git a/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/VERSION b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/VERSION new file mode 100644 index 000000000000..c9e125ba1880 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.4.0-SNAPSHOT diff --git a/samples/server/petstore/go-gin-api-server-interface-only/Dockerfile b/samples/server/petstore/go-gin-api-server-interface-only/Dockerfile new file mode 100644 index 000000000000..8e83f2948dfa --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:1.19 AS build +WORKDIR /go/src +COPY go ./go +COPY main.go . +COPY go.sum . +COPY go.mod . + +ENV CGO_ENABLED=0 + +RUN go build -o petstoreserver . + +FROM scratch AS runtime +ENV GIN_MODE=release +COPY --from=build /go/src/petstoreserver ./ +EXPOSE 8080/tcp +ENTRYPOINT ["./petstoreserver"] diff --git a/samples/server/petstore/go-gin-api-server-interface-only/api/openapi.yaml b/samples/server/petstore/go-gin-api-server-interface-only/api/openapi.yaml new file mode 100644 index 000000000000..9a95adaefff2 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/api/openapi.yaml @@ -0,0 +1,811 @@ +openapi: 3.0.0 +info: + description: "This is a sample server Petstore server. For this sample, you can\ + \ use the api key `special-key` to test the authorization filters." + license: + name: Apache-2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + title: OpenAPI Petstore + version: 1.0.0 +externalDocs: + description: Find out more about Swagger + url: http://swagger.io +servers: +- url: http://petstore.swagger.io/v2 +tags: +- description: Everything about your Pets + name: pet +- description: Access to Petstore orders + name: store +- description: Operations about user + name: user +paths: + /pet: + post: + description: "" + operationId: addPet + requestBody: + $ref: '#/components/requestBodies/Pet' + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + description: successful operation + "405": + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + summary: Add a new pet to the store + tags: + - pet + put: + description: "" + externalDocs: + description: API documentation for the updatePet operation + url: http://petstore.swagger.io/v2/doc/updatePet + operationId: updatePet + requestBody: + $ref: '#/components/requestBodies/Pet' + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + description: successful operation + "400": + description: Invalid ID supplied + "404": + description: Pet not found + "405": + description: Validation exception + security: + - petstore_auth: + - write:pets + - read:pets + summary: Update an existing pet + tags: + - pet + /pet/findByStatus: + get: + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - deprecated: true + description: Status values that need to be considered for filter + explode: false + in: query + name: status + required: true + schema: + items: + default: available + enum: + - available + - pending + - sold + type: string + type: array + style: form + responses: + "200": + content: + application/xml: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + application/json: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + description: successful operation + "400": + description: Invalid status value + security: + - petstore_auth: + - read:pets + summary: Finds Pets by status + tags: + - pet + /pet/findByTags: + get: + deprecated: true + description: "Multiple tags can be provided with comma separated strings. Use\ + \ tag1, tag2, tag3 for testing." + operationId: findPetsByTags + parameters: + - description: Tags to filter by + explode: false + in: query + name: tags + required: true + schema: + items: + type: string + type: array + style: form + responses: + "200": + content: + application/xml: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + application/json: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + description: successful operation + "400": + description: Invalid tag value + security: + - petstore_auth: + - read:pets + summary: Finds Pets by tags + tags: + - pet + /pet/{petId}: + delete: + description: "" + operationId: deletePet + parameters: + - explode: false + in: header + name: api_key + required: false + schema: + type: string + style: simple + - description: Pet id to delete + explode: false + in: path + name: petId + required: true + schema: + format: int64 + type: integer + style: simple + responses: + "400": + description: Invalid pet value + security: + - petstore_auth: + - write:pets + - read:pets + summary: Deletes a pet + tags: + - pet + get: + description: Returns a single pet + operationId: getPetById + parameters: + - description: ID of pet to return + explode: false + in: path + name: petId + required: true + schema: + format: int64 + type: integer + style: simple + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + description: successful operation + "400": + description: Invalid ID supplied + "404": + description: Pet not found + security: + - api_key: [] + summary: Find pet by ID + tags: + - pet + post: + description: "" + operationId: updatePetWithForm + parameters: + - description: ID of pet that needs to be updated + explode: false + in: path + name: petId + required: true + schema: + format: int64 + type: integer + style: simple + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/updatePetWithForm_request' + responses: + "405": + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + summary: Updates a pet in the store with form data + tags: + - pet + /pet/{petId}/uploadImage: + post: + description: "" + operationId: uploadFile + parameters: + - description: ID of pet to update + explode: false + in: path + name: petId + required: true + schema: + format: int64 + type: integer + style: simple + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/uploadFile_request' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + description: successful operation + security: + - petstore_auth: + - write:pets + - read:pets + summary: uploads an image + tags: + - pet + /store/inventory: + get: + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + "200": + content: + application/json: + schema: + additionalProperties: + format: int32 + type: integer + type: object + description: successful operation + security: + - api_key: [] + summary: Returns pet inventories by status + tags: + - store + /store/order: + post: + description: "" + operationId: placeOrder + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + description: order placed for purchasing the pet + required: true + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + description: successful operation + "400": + description: Invalid Order + summary: Place an order for a pet + tags: + - store + /store/order/{orderId}: + delete: + description: For valid response try integer IDs with value < 1000. Anything + above 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - description: ID of the order that needs to be deleted + explode: false + in: path + name: orderId + required: true + schema: + type: string + style: simple + responses: + "400": + description: Invalid ID supplied + "404": + description: Order not found + summary: Delete purchase order by ID + tags: + - store + get: + description: For valid response try integer IDs with value <= 5 or > 10. Other + values will generate exceptions + operationId: getOrderById + parameters: + - description: ID of pet that needs to be fetched + explode: false + in: path + name: orderId + required: true + schema: + format: int64 + maximum: 5 + minimum: 1 + type: integer + style: simple + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + description: successful operation + "400": + description: Invalid ID supplied + "404": + description: Order not found + summary: Find purchase order by ID + tags: + - store + /user: + post: + description: This can only be done by the logged in user. + operationId: createUser + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Created user object + required: true + responses: + default: + description: successful operation + security: + - api_key: [] + summary: Create user + tags: + - user + /user/createWithArray: + post: + description: "" + operationId: createUsersWithArrayInput + requestBody: + $ref: '#/components/requestBodies/UserArray' + responses: + default: + description: successful operation + security: + - api_key: [] + summary: Creates list of users with given input array + tags: + - user + /user/createWithList: + post: + description: "" + operationId: createUsersWithListInput + requestBody: + $ref: '#/components/requestBodies/UserArray' + responses: + default: + description: successful operation + security: + - api_key: [] + summary: Creates list of users with given input array + tags: + - user + /user/login: + get: + description: "" + operationId: loginUser + parameters: + - description: The user name for login + explode: true + in: query + name: username + required: true + schema: + pattern: "^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$" + type: string + style: form + - description: The password for login in clear text + explode: true + in: query + name: password + required: true + schema: + type: string + style: form + responses: + "200": + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + description: successful operation + headers: + Set-Cookie: + description: Cookie authentication key for use with the `api_key` apiKey + authentication. + explode: false + schema: + example: AUTH_KEY=abcde12345; Path=/; HttpOnly + type: string + style: simple + X-Rate-Limit: + description: calls per hour allowed by the user + explode: false + schema: + format: int32 + type: integer + style: simple + X-Expires-After: + description: date in UTC when token expires + explode: false + schema: + format: date-time + type: string + style: simple + "400": + description: Invalid username/password supplied + summary: Logs user into the system + tags: + - user + /user/logout: + get: + description: "" + operationId: logoutUser + responses: + default: + description: successful operation + security: + - api_key: [] + summary: Logs out current logged in user session + tags: + - user + /user/{username}: + delete: + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - description: The name that needs to be deleted + explode: false + in: path + name: username + required: true + schema: + type: string + style: simple + responses: + "400": + description: Invalid username supplied + "404": + description: User not found + security: + - api_key: [] + summary: Delete user + tags: + - user + get: + description: "" + operationId: getUserByName + parameters: + - description: The name that needs to be fetched. Use user1 for testing. + explode: false + in: path + name: username + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + description: successful operation + "400": + description: Invalid username supplied + "404": + description: User not found + summary: Get user by user name + tags: + - user + put: + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - description: name that need to be deleted + explode: false + in: path + name: username + required: true + schema: + type: string + style: simple + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Updated user object + required: true + responses: + "400": + description: Invalid user supplied + "404": + description: User not found + security: + - api_key: [] + summary: Updated user + tags: + - user +components: + requestBodies: + UserArray: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/User' + type: array + description: List of user object + required: true + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + schemas: + Order: + description: An order for a pets from the pet store + example: + petId: 6 + quantity: 1 + id: 0 + shipDate: 2000-01-23T04:56:07.000+00:00 + complete: false + status: placed + properties: + id: + format: int64 + type: integer + petId: + format: int64 + type: integer + quantity: + format: int32 + type: integer + shipDate: + format: date-time + type: string + status: + description: Order Status + enum: + - placed + - approved + - delivered + type: string + complete: + default: false + type: boolean + title: Pet Order + type: object + xml: + name: Order + Category: + description: A category for a pet + example: + name: name + id: 6 + properties: + id: + format: int64 + type: integer + name: + pattern: "^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$" + type: string + title: Pet category + type: object + xml: + name: Category + User: + description: A User who is purchasing from the pet store + example: + firstName: firstName + lastName: lastName + password: password + userStatus: 6 + phone: phone + id: 0 + email: email + username: username + properties: + id: + format: int64 + type: integer + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + description: User Status + format: int32 + type: integer + title: a User + type: object + xml: + name: User + Tag: + description: A tag for a pet + example: + name: name + id: 1 + properties: + id: + format: int64 + type: integer + name: + type: string + title: Pet Tag + type: object + xml: + name: Tag + Pet: + description: A pet for sale in the pet store + example: + photoUrls: + - photoUrls + - photoUrls + name: doggie + id: 0 + category: + name: name + id: 6 + tags: + - name: name + id: 1 + - name: name + id: 1 + status: available + properties: + id: + format: int64 + type: integer + category: + $ref: '#/components/schemas/Category' + name: + example: doggie + type: string + photoUrls: + items: + type: string + type: array + xml: + name: photoUrl + wrapped: true + tags: + items: + $ref: '#/components/schemas/Tag' + type: array + xml: + name: tag + wrapped: true + status: + deprecated: true + description: pet status in the store + enum: + - available + - pending + - sold + type: string + required: + - name + - photoUrls + title: a Pet + type: object + xml: + name: Pet + ApiResponse: + description: Describes the result of uploading an image resource + example: + code: 0 + type: type + message: message + properties: + code: + format: int32 + type: integer + type: + type: string + message: + type: string + title: An uploaded response + type: object + updatePetWithForm_request: + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + type: object + uploadFile_request: + properties: + additionalMetadata: + description: Additional data to pass to server + type: string + file: + description: file to upload + format: binary + type: string + type: object + securitySchemes: + petstore_auth: + flows: + implicit: + authorizationUrl: http://petstore.swagger.io/api/oauth/dialog + scopes: + write:pets: modify pets in your account + read:pets: read your pets + type: oauth2 + api_key: + in: header + name: api_key + type: apiKey diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go.mod b/samples/server/petstore/go-gin-api-server-interface-only/go.mod new file mode 100644 index 000000000000..054f904bb08d --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go.mod @@ -0,0 +1,32 @@ +module github.com/GIT_USER_ID/GIT_REPO_ID + +go 1.19 + +require github.com/gin-gonic/gin v1.9.1 + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/README.md b/samples/server/petstore/go-gin-api-server-interface-only/go/README.md new file mode 100644 index 000000000000..4f16ed4562fa --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/README.md @@ -0,0 +1,39 @@ +# Go API Server for petstoreserver + +This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + +## Overview +This server was generated by the [openapi-generator] +(https://openapi-generator.tech) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://openapi-generator.tech) + +- API version: 1.0.0 + +### Running the server + +To run the server, follow these simple steps: + +``` +go run main.go +``` + +To run the server in a docker container +``` +docker build --network=host -t petstoreserver . +``` + +Once the image is built, just run +``` +docker run --rm -it petstoreserver +``` + +### Known Issue + +Endpoints sharing a common path may result in issues. For example, `/v2/pet/findByTags` and `/v2/pet/:petId` will result in an issue with the Gin framework. For more information about this known limitation, please refer to [gin-gonic/gin#388](https://github.com/gin-gonic/gin/issues/388) for more information. + +A workaround is to manually update the path and handler. Please refer to [gin-gonic/gin/issues/205#issuecomment-296155497](https://github.com/gin-gonic/gin/issues/205#issuecomment-296155497) for more information. diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/api_pet.go b/samples/server/petstore/go-gin-api-server-interface-only/go/api_pet.go new file mode 100644 index 000000000000..5b54ca1e0380 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/api_pet.go @@ -0,0 +1,52 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +import ( + "github.com/gin-gonic/gin" +) + +type PetAPI interface { + + + // AddPet Post /v2/pet + // Add a new pet to the store + AddPet(c *gin.Context) + + // DeletePet Delete /v2/pet/:petId + // Deletes a pet + DeletePet(c *gin.Context) + + // FindPetsByStatus Get /v2/pet/findByStatus + // Finds Pets by status + FindPetsByStatus(c *gin.Context) + + // FindPetsByTags Get /v2/pet/findByTags + // Finds Pets by tags + // Deprecated + FindPetsByTags(c *gin.Context) + + // GetPetById Get /v2/pet/:petId + // Find pet by ID + GetPetById(c *gin.Context) + + // UpdatePet Put /v2/pet + // Update an existing pet + UpdatePet(c *gin.Context) + + // UpdatePetWithForm Post /v2/pet/:petId + // Updates a pet in the store with form data + UpdatePetWithForm(c *gin.Context) + + // UploadFile Post /v2/pet/:petId/uploadImage + // uploads an image + UploadFile(c *gin.Context) + +} \ No newline at end of file diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/api_store.go b/samples/server/petstore/go-gin-api-server-interface-only/go/api_store.go new file mode 100644 index 000000000000..b0ea83a4bc9b --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/api_store.go @@ -0,0 +1,35 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +import ( + "github.com/gin-gonic/gin" +) + +type StoreAPI interface { + + + // DeleteOrder Delete /v2/store/order/:orderId + // Delete purchase order by ID + DeleteOrder(c *gin.Context) + + // GetInventory Get /v2/store/inventory + // Returns pet inventories by status + GetInventory(c *gin.Context) + + // GetOrderById Get /v2/store/order/:orderId + // Find purchase order by ID + GetOrderById(c *gin.Context) + + // PlaceOrder Post /v2/store/order + // Place an order for a pet + PlaceOrder(c *gin.Context) + +} \ No newline at end of file diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/api_user.go b/samples/server/petstore/go-gin-api-server-interface-only/go/api_user.go new file mode 100644 index 000000000000..9c274994745b --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/api_user.go @@ -0,0 +1,51 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +import ( + "github.com/gin-gonic/gin" +) + +type UserAPI interface { + + + // CreateUser Post /v2/user + // Create user + CreateUser(c *gin.Context) + + // CreateUsersWithArrayInput Post /v2/user/createWithArray + // Creates list of users with given input array + CreateUsersWithArrayInput(c *gin.Context) + + // CreateUsersWithListInput Post /v2/user/createWithList + // Creates list of users with given input array + CreateUsersWithListInput(c *gin.Context) + + // DeleteUser Delete /v2/user/:username + // Delete user + DeleteUser(c *gin.Context) + + // GetUserByName Get /v2/user/:username + // Get user by user name + GetUserByName(c *gin.Context) + + // LoginUser Get /v2/user/login + // Logs user into the system + LoginUser(c *gin.Context) + + // LogoutUser Get /v2/user/logout + // Logs out current logged in user session + LogoutUser(c *gin.Context) + + // UpdateUser Put /v2/user/:username + // Updated user + UpdateUser(c *gin.Context) + +} \ No newline at end of file diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_api_response.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_api_response.go new file mode 100644 index 000000000000..2379e169080d --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_api_response.go @@ -0,0 +1,20 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +// ApiResponse - Describes the result of uploading an image resource +type ApiResponse struct { + + Code int32 `json:"code,omitempty"` + + Type string `json:"type,omitempty"` + + Message string `json:"message,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_category.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_category.go new file mode 100644 index 000000000000..5e6f9d247fa4 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_category.go @@ -0,0 +1,18 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +// Category - A category for a pet +type Category struct { + + Id int64 `json:"id,omitempty"` + + Name string `json:"name,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_order.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_order.go new file mode 100644 index 000000000000..a9d8dbb79579 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_order.go @@ -0,0 +1,31 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +import ( + "time" +) + +// Order - An order for a pets from the pet store +type Order struct { + + Id int64 `json:"id,omitempty"` + + PetId int64 `json:"petId,omitempty"` + + Quantity int32 `json:"quantity,omitempty"` + + ShipDate time.Time `json:"shipDate,omitempty"` + + // Order Status + Status string `json:"status,omitempty"` + + Complete bool `json:"complete,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_pet.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_pet.go new file mode 100644 index 000000000000..3fb69fafe385 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_pet.go @@ -0,0 +1,28 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +// Pet - A pet for sale in the pet store +type Pet struct { + + Id int64 `json:"id,omitempty"` + + Category Category `json:"category,omitempty"` + + Name string `json:"name"` + + PhotoUrls []string `json:"photoUrls"` + + Tags []Tag `json:"tags,omitempty"` + + // pet status in the store + // Deprecated + Status string `json:"status,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_tag.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_tag.go new file mode 100644 index 000000000000..2fb07fb32c46 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_tag.go @@ -0,0 +1,18 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +// Tag - A tag for a pet +type Tag struct { + + Id int64 `json:"id,omitempty"` + + Name string `json:"name,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/model_user.go b/samples/server/petstore/go-gin-api-server-interface-only/go/model_user.go new file mode 100644 index 000000000000..8f40d0ac04cb --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/model_user.go @@ -0,0 +1,31 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +// User - A User who is purchasing from the pet store +type User struct { + + Id int64 `json:"id,omitempty"` + + Username string `json:"username,omitempty"` + + FirstName string `json:"firstName,omitempty"` + + LastName string `json:"lastName,omitempty"` + + Email string `json:"email,omitempty"` + + Password string `json:"password,omitempty"` + + Phone string `json:"phone,omitempty"` + + // User Status + UserStatus int32 `json:"userStatus,omitempty"` +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/go/routers.go b/samples/server/petstore/go-gin-api-server-interface-only/go/routers.go new file mode 100644 index 000000000000..93a820207343 --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/go/routers.go @@ -0,0 +1,196 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// Route is the information for every URI. +type Route struct { + // Name is the name of this Route. + Name string + // Method is the string for the HTTP method. ex) GET, POST etc.. + Method string + // Pattern is the pattern of the URI. + Pattern string + // HandlerFunc is the handler function of this route. + HandlerFunc gin.HandlerFunc +} + +// NewRouter returns a new router. +func NewRouter(handleFunctions ApiHandleFunctions) *gin.Engine { + return NewRouterWithGinEngine(gin.Default(), handleFunctions) +} + +// NewRouter add routes to existing gin engine. +func NewRouterWithGinEngine(router *gin.Engine, handleFunctions ApiHandleFunctions) *gin.Engine { + for _, route := range getRoutes(handleFunctions) { + if route.HandlerFunc == nil { + route.HandlerFunc = DefaultHandleFunc + } + switch route.Method { + case http.MethodGet: + router.GET(route.Pattern, route.HandlerFunc) + case http.MethodPost: + router.POST(route.Pattern, route.HandlerFunc) + case http.MethodPut: + router.PUT(route.Pattern, route.HandlerFunc) + case http.MethodPatch: + router.PATCH(route.Pattern, route.HandlerFunc) + case http.MethodDelete: + router.DELETE(route.Pattern, route.HandlerFunc) + } + } + + return router +} + +// Default handler for not yet implemented routes +func DefaultHandleFunc(c *gin.Context) { + c.String(http.StatusNotImplemented, "501 not implemented") +} + +type ApiHandleFunctions struct { + + // Routes for the PetAPI part of the API + PetAPI PetAPI + // Routes for the StoreAPI part of the API + StoreAPI StoreAPI + // Routes for the UserAPI part of the API + UserAPI UserAPI +} + +func getRoutes(handleFunctions ApiHandleFunctions) []Route { + return []Route{ + { + "AddPet", + http.MethodPost, + "/v2/pet", + handleFunctions.PetAPI.AddPet, + }, + { + "DeletePet", + http.MethodDelete, + "/v2/pet/:petId", + handleFunctions.PetAPI.DeletePet, + }, + { + "FindPetsByStatus", + http.MethodGet, + "/v2/pet/findByStatus", + handleFunctions.PetAPI.FindPetsByStatus, + }, + { + "FindPetsByTags", + http.MethodGet, + "/v2/pet/findByTags", + handleFunctions.PetAPI.FindPetsByTags, + }, + { + "GetPetById", + http.MethodGet, + "/v2/pet/:petId", + handleFunctions.PetAPI.GetPetById, + }, + { + "UpdatePet", + http.MethodPut, + "/v2/pet", + handleFunctions.PetAPI.UpdatePet, + }, + { + "UpdatePetWithForm", + http.MethodPost, + "/v2/pet/:petId", + handleFunctions.PetAPI.UpdatePetWithForm, + }, + { + "UploadFile", + http.MethodPost, + "/v2/pet/:petId/uploadImage", + handleFunctions.PetAPI.UploadFile, + }, + { + "DeleteOrder", + http.MethodDelete, + "/v2/store/order/:orderId", + handleFunctions.StoreAPI.DeleteOrder, + }, + { + "GetInventory", + http.MethodGet, + "/v2/store/inventory", + handleFunctions.StoreAPI.GetInventory, + }, + { + "GetOrderById", + http.MethodGet, + "/v2/store/order/:orderId", + handleFunctions.StoreAPI.GetOrderById, + }, + { + "PlaceOrder", + http.MethodPost, + "/v2/store/order", + handleFunctions.StoreAPI.PlaceOrder, + }, + { + "CreateUser", + http.MethodPost, + "/v2/user", + handleFunctions.UserAPI.CreateUser, + }, + { + "CreateUsersWithArrayInput", + http.MethodPost, + "/v2/user/createWithArray", + handleFunctions.UserAPI.CreateUsersWithArrayInput, + }, + { + "CreateUsersWithListInput", + http.MethodPost, + "/v2/user/createWithList", + handleFunctions.UserAPI.CreateUsersWithListInput, + }, + { + "DeleteUser", + http.MethodDelete, + "/v2/user/:username", + handleFunctions.UserAPI.DeleteUser, + }, + { + "GetUserByName", + http.MethodGet, + "/v2/user/:username", + handleFunctions.UserAPI.GetUserByName, + }, + { + "LoginUser", + http.MethodGet, + "/v2/user/login", + handleFunctions.UserAPI.LoginUser, + }, + { + "LogoutUser", + http.MethodGet, + "/v2/user/logout", + handleFunctions.UserAPI.LogoutUser, + }, + { + "UpdateUser", + http.MethodPut, + "/v2/user/:username", + handleFunctions.UserAPI.UpdateUser, + }, + } +} diff --git a/samples/server/petstore/go-gin-api-server-interface-only/main.go b/samples/server/petstore/go-gin-api-server-interface-only/main.go new file mode 100644 index 000000000000..05aee5b9255b --- /dev/null +++ b/samples/server/petstore/go-gin-api-server-interface-only/main.go @@ -0,0 +1,29 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package main + +import ( + "log" + + // WARNING! + // Pass --git-repo-id and --git-user-id properties when generating the code + // + sw "github.com/GIT_USER_ID/GIT_REPO_ID/go" +) + +func main() { + routes := sw.ApiHandleFunctions{} + + log.Printf("Server started") + + router := sw.NewRouter(routes) + + log.Fatal(router.Run(":8080")) +}