ebowman / api-first-hand

API-First bootstrapping tool for building RESTful web services from a Swagger/OpenAPI spec
MIT License
142 stars 22 forks source link

Errors when generating a new play projet using my Swagger specification #46

Closed SellamiRami closed 7 years ago

SellamiRami commented 7 years ago

Dear all,

This is my first time that I implement a REST API using Scala and Play framework. I created the specification fo the API using swagger editor.

Then, I create a new project that I name myAPI using the command:

`$ activator new myAPI api-first-hand

Fetching the latest list of templates...

OK, application "myAPI" is being created using the "api-first-hand" template.

To run "myAPI" from the command line, "cd myAPI" then: /Users/rs/myAPI/activator run

To run the test for "myAPI" from the command line, "cd myAPI" then: /Users/rs/myAPI/activator test

To run the Activator UI for "myAPI" from the command line, "cd myAPI" then: /Users/rs/myAPI/activator ui`

Afterward, I copy paste the yaml file of the specification in /conf/ and I edit the routes file as follow:

`#Routes

This file defines all application routes (Higher priority routes first)

~~~~

GET /spec/:name controllers.Swagger.swaggerSpec(name: String)

GET /list_specs controllers.Swagger.listSpecs

GET / controllers.Assets.versioned(path="/public/swagger", file: Asset = "index.html")

GET /index.html controllers.Assets.versioned(path="/public/swagger", file: Asset = "index.html")

GET /o2c.html controllers.Assets.versioned(path="/public/swagger", file: Asset = "o2c.html")

GET /favicon.ico controllers.Assets.versioned(path="/public/swagger/images", file: Asset = "favicon.ico")

GET /api/*file controllers.Assets.versioned(path="/public/swagger", file: Asset)

-> /number_validation numbers.validation.yaml.Routes

-> /string_validation string_formats.validation.yaml.Routes

-> /cross_spec cross_spec_references.yaml.Routes

-> /form_data form_data.yaml.Routes

-> /types type_deduplication.yaml.Routes

-> /uber uber.api.yaml.Routes

-> /petstore simple.petstore.api.yaml.Routes

-> /security security.api.yaml.Routes

-> /example example.yaml.Routes

-> /opendataapi APISpecification.yaml.Routes`

I position my sefl in the root directory /myAPI and run the sbt command:

$ sbt [info] Loading project definition from /Users/rs/myAPI/project [info] Updating {file:/Users/rs/myAPI/project/}myapi-build... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Set current project to myAPI (in build file:/Users/rs/myAPI/)

I run the following command and I get these errors when I try to access http://localhost:9000/:

`$ run [info] Updating {file:/Users/rs/myAPI/}root... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [warn] Scala version was updated by one of library dependencies: [warn] org.scala-lang:scala-library:(2.11.7, 2.11.0, 2.11.6) -> 2.11.8 [warn] To force scalaVersion, add the following: [warn] ivyScala := ivyScala.value map { _.copy(overrideScalaVersion = true) } [warn] There may be incompatibilities among your library dependencies. [warn] Here are some of the libraries that were evicted: [warn] com.fasterxml.jackson.module:jackson-module-scala_2.11:2.6.1 -> 2.7.4 [warn] Run 'evicted' to see detailed eviction warnings

--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/rs/activator-dist-1.3.12/repository/org.slf4j/slf4j-simple/1.7.12/jars/slf4j-simple.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/rs/.ivy2/cache/ch.qos.logback/logback-classic/jars/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory] [trace] Stack trace suppressed: run last compile:swaggerParseSpec for the full output. [error] (compile:swaggerParseSpec) com.fasterxml.jackson.core.JsonParseException: Instantiation of [simple type, class de.zalando.swagger.strictModel$Schema] value failed (java.lang.IllegalArgumentException): requirement failed: Support for object definitions without properties is not implemented yet [error] at [Source: N/A; line: -1, column: -1] (through reference chain: de.zalando.swagger.Schema["properties"]->com.fasterxml.jackson.module.scala.deser.MapBuilderWrapper["metadata"]) through reference chain: paths → /line → get → responses → 200 → schema [trace] Stack trace suppressed: run last compile:swaggerParseSpec for the full output. [error] (compile:swaggerParseSpec) com.fasterxml.jackson.core.JsonParseException: Instantiation of [simple type, class de.zalando.swagger.strictModel$Schema] value failed (java.lang.IllegalArgumentException): requirement failed: Support for object definitions without properties is not implemented yet [error] at [Source: N/A; line: -1, column: -1] (through reference chain: de.zalando.swagger.Schema["properties"]->com.fasterxml.jackson.module.scala.deser.MapBuilderWrapper["metadata"]) through reference chain: paths → /line → get → responses → 200 → schema [error] application -

! @72c4p8dcp - Internal server error, for (GET) [/] ->

play.sbt.PlayExceptions$UnexpectedException: Unexpected exception[JsonParseException: Instantiation of [simple type, class de.zalando.swagger.strictModel$Schema] value failed (java.lang.IllegalArgumentException): requirement failed: Support for object definitions without properties is not implemented yet at [Source: N/A; line: -1, column: -1] (through reference chain: de.zalando.swagger.Schema["properties"]->com.fasterxml.jackson.module.scala.deser.MapBuilderWrapper["metadata"]) through reference chain: paths → /line → get → responses → 200 → schema] at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:51) at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:44) at scala.Option.map(Option.scala:145) at play.sbt.run.PlayReload$.taskFailureHandler(PlayReload.scala:44) at play.sbt.run.PlayReload$.compileFailure(PlayReload.scala:40) at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) at scala.util.Either$LeftProjection.map(Either.scala:377) at play.sbt.run.PlayReload$.compile(PlayReload.scala:17) at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$2.apply(PlayRun.scala:61) Caused by: com.fasterxml.jackson.core.JsonParseException: Instantiation of [simple type, class de.zalando.swagger.strictModel$Schema] value failed (java.lang.IllegalArgumentException): requirement failed: Support for object definitions without properties is not implemented yet at [Source: N/A; line: -1, column: -1] (through reference chain: de.zalando.swagger.Schema["properties"]->com.fasterxml.jackson.module.scala.deser.MapBuilderWrapper["metadata"]) through reference chain: paths → /line → get → responses → 200 → schema at de.zalando.swagger.StrictSwaggerParser$$anonfun$1.apply(StrictParser.scala:76) at de.zalando.swagger.StrictSwaggerParser$$anonfun$1.apply(StrictParser.scala:71) at scala.util.control.Exception$Catch$$anon$2.apply(Exception.scala:136) at scala.util.control.Exception$Catch$$anon$2.apply(Exception.scala:134) at scala.util.control.Exception$Catch.apply(Exception.scala:105) at de.zalando.swagger.StrictSwaggerParser.parse(StrictParser.scala:77) at de.zalando.swagger.SwaggerParser$.readSwaggerModel(SwaggerParser.scala:12) at de.zalando.play.swagger.sbt.ApiFirstSwaggerParser$$anonfun$swaggerParserSettings$4$$anonfun$apply$1.apply(ApiFirstSwaggerParser.scala:55) at de.zalando.play.swagger.sbt.ApiFirstSwaggerParser$$anonfun$swaggerParserSettings$4$$anonfun$apply$1.apply(ApiFirstSwaggerParser.scala:55) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)

`

SellamiRami commented 7 years ago

I am wondering if these errors are related to the other issue that I opened #44 or not.

SellamiRami commented 7 years ago

Dear all,

Could you please answer me?

slavaschmidt commented 7 years ago

Hey @SellamiRami, the error message in your case is as you can see

(java.lang.IllegalArgumentException): requirement failed: Support for object definitions without properties is not implemented yet which is related to following path in your spec: paths → /line → get → responses → 200 → schema

There is a known issue with allOf which can cause this error message, but probably it's not your case. So could you please check if the specification you provide contains some object definition for the 200 response code of the GET /line api call without any properties defined? In this case you will need to change the specification in the way that every object definition specifies at least one field.

SellamiRami commented 7 years ago

Dear @slavaschmidt,

Thank you for your response. However, I defined properties for the 200 response code using the syntax $ref: '#/definitions/ResponseLine'.

Here is my swagger specification:

swagger: '2.0' info: contact: name: 'CETIC' url: https://www.cetic.be/Contact version: '0.1' title: MOBITS API description: 'Open Data API Specification' basePath: /opendataapi schemes: -https

This is your document metadata

Describe your paths here

consumes: -text/plain -text/csv -application/json -application/xml produces: -application/json -application/xml -text/html paths: /line: get: description: Lists all the lines operationId: listAllLines produces: -application/json -application/xml -text/html responses: '200': description: list all lines response schema: $ref: '#/definitions/ResponseLine' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /line/{lineId}: get: description: Returns a line based on a single ID operationId: findLineById produces: -application/json -application/xml -text/html parameters: -name: lineId in: path description: ID of a line required: true type: string responses: '200': description: Requested line schema: $ref: '#/definitions/ResponseLine' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /line/{lineId}/stop: get: description: Lists all the stops of a given line operationId: listAllStops produces: -application/json -application/xml -text/html parameters: -name: lineId in: path description: ID of a line required: true type: string responses: '200': description: List all stops of a given line response schema: $ref: '#/definitions/ResponseStop' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /line/{lineId}/stop/{stopId}: get: description: Returns a stop based on a single ID of a given line operationId: findStopById produces: -application/json -application/xml -text/html parameters: -name: lineId in: path description: ID of a line required: true type: string -name: stopId in: path description: ID of a stop required: true type: string responses: '200': description: Requested stop of a given line schema: $ref: '#/definitions/ResponseStop' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /stop/{stopId}/occupency: get: description: Returns the occupency of a given stop in terms of percentage. operationId: findOccupencyStop produces: -application/json -application/xml -text/html parameters: -name: stopId in: path description: ID of a stop required: true type: string responses: '200': description: Returns the occupncy of a given stop schema: $ref: '#/definitions/ResponsePassengerStop' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /stop/{stopId}/weather: get: description: Returns the weather forecast at a given stop during the day. operationId: findWeatherInStop produces: -application/json -application/xml -text/html parameters: -name: stopId in: path description: ID of a stop required: true type: string -name: when in: query description: The passenger may choose the wether forecast of the current day or during the week required: true type: string responses: '200': description: Weather forecast at a given stop during the day. schema: $ref: '#/definitions/ResponseWhetherStop' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /stop/{stopId}/interestpoint: post: description: Returns the interest points to the passenger based on a stop name, distance and categories (e.g. restaurant, cinema, etc.). operationId: findInterestPoint consumes: -application/json produces: -application/json -application/xml -text/html parameters: -name: stopId in: path description: ID of a stop required: true type: string -name: queryInterestPoint in: body required: true schema: $ref: '#/definitions/RequestInterestPoint' responses: '200': description: Returns the interest points at a given stop schema: $ref: '#/definitions/ResponseInterestPoint' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /line/{lineId}/stop/{stopId}/schedule: get: description: Returns the schedule of given stop and line during the year (i.e. school and holidays periods, summer and autumn season, etc.) operationId: findSchedule produces: -application/json -application/xml -text/html parameters: -name: lineId in: path description: ID of a line required: true type: string -name: stopId in: path description: ID of a stop required: true type: string responses: '200': description: Returns the schedule of given stop and line schema: $ref: '#/definitions/ResponseSchedule' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /line/{lineId}/stop/{stopId}/timetable: get: description: Returns the time table of a given path. The passenger enters the stop name, the line name, the date, the start time and the end time. Unlike the findSchedule operation, this one return the schedule for a prefixed and short period. operationId: findTimeTable produces: -application/json -application/xml -text/html parameters: -name: lineId in: path description: ID of a line required: true type: string -name: stopId in: path description: ID of a stop required: true type: string -name: date in: query description: Date required: true type: integer format: int64 -name: from in: query description: Start time required: true type: integer format: int64 -name: to in: query description: End time required: true type: integer format: int64 responses: '200': description: Returns the time table schema: $ref: '#/definitions/ResponseTimeTable' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /vehicle/{vehicleId}/: get: description: Returns information about a vehicle. operationId: findVehicleById produces: -application/json -application/xml -text/html parameters:

  • name: vehicleId in: path description: ID of a vehicle required: true type: string responses: '200': description: Returns information about a vehicle schema: $ref: '#/definitions/ResponseVehicle' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /vehicle/{vehicleId}/occupancy: get: description: Returns the occupancy of a given vehicle in terms of percentage. operationId: findOccupancyVehicle produces: -application/json -application/xml -text/html parameters: -name: vehicleId in: path description: ID of a vehicle required: true type: string responses: '200': description: Returns the occupancy of a given vehicle schema: $ref: '#/definitions/ResponsePassengerVehicle' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /passenger/distance: get: description: Returns the stops near the passenger within a radius of a given distance based on his/her position. operationId: finddistance produces: -application/json -application/xml -text/html parameters: -name: lat in: query description: The latitude of the passenger required: true type: string -name: lon in: query description: The longitude of the passenger required: true type: string -name: distance in: query description: The maximum distance between the passenger and the stops. required: true type: string -name: vehicleType in: query description: Vehicle types. If there is multiple types, they must be seperated by a ",". required: true type: string responses: '200': description: Returns the occupancy of a given vehicle schema: $ref: '#/definitions/ResponsePassengerDistance' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' /itinerary: get: description: Returns an itinerary operationId: finditinerary produces: -application/json -application/xml -text/html parameters: -name: from in: query description: The departure point. required: true type: string -name: to in: query description: The arrival point. required: true type: string -name: date in: query description: The departure date required: true type: string -name: departureTime in: query description: The departure time required: true type: string -name: arrivalTime in: query description: The arrival time required: true type: string -name: vehicleType in: query description: Vehicle types. If there is multiple types, they must be seperated by a ",". required: true type: string responses: '200': description: Returns the occupancy of a given vehicle schema: $ref: '#/definitions/ResponseItinerary' '400': description: Invalid request schema: $ref: '#/definitions/Error' '402': description: Valid request but quota exceeded schema: $ref: '#/definitions/Error' '404': description: Invalid API endpoint schema: $ref: '#/definitions/Error' '410': description: Not available requested resource and will not be available again schema: $ref: '#/definitions/Error' '503': description: Internal server error schema: $ref: '#/definitions/Error' definitions: RequestInterestPoint: properties: query: type: object properties: distance: type: string interestPoint: type: array items: type: string ResponseLine: properties: data: type: object properties: Lines: type: array items: type: object properties: idLine: type: string name: type: string description: type: string agencyId: type: string vehicleType: type: string metadata: type: object ResponseStop: properties: data: type: object properties: stops: type: array items: type: object properties: idStop: type: string latitude: type: string longittude: type: string name: type: string metadata: type: object ResponseTimeTable: properties: data: type: object properties: inputData: type: object properties: line: type: string stop: type: string date: type: string startTime: type: string endTime: type: string arrivalTime: type: array items: type: string metadata: type: object ResponseSchedule: properties: data: type: object properties: inputData: type: object properties: line: type: string stop: type: string schedule: type: array items: type: string metadata: type: object ResponsePassengerStop: properties: data: type: object properties: stop: type: string passengerNumber: type: integer metadata: type: object ResponseInterestPoint: properties: data: type: object metadata: type: object ResponsePassengerVehicle: properties: data: type: object properties: vehicle: type: string passengerNumber: type: integer metadata: type: object ResponseWhetherStop: properties: data: type: object metadata: type: object ResponseVehicle: properties: data: type: object properties: stops: type: array items: type: object properties: idVehicle: type: string isAgency: type: string number: type: string comment: type: string metadata: type: object ResponsePassengerDistance: properties: data: type: object properties: input: type: object properties: latPassenger: type: string lonPassenger: type: string distance: type: string stops: type: array items: type: object properties: vehicle: type: string idStop: type: string name: type: string latitude: type: string longitude: type: string distance: type: string metadata: type: object ResponseItinerary: properties: data: type: object metadata: type: object Error: properties: error: type: object properties: status: type: string description: type: string
slavaschmidt commented 7 years ago

Hi @SellamiRami

could you please attach a properly formatted specification? This one definitely won't work if I feed it to the plugin. Thanks!

SellamiRami commented 7 years ago

API Specification.txt Hi @slavaschmidt,

Please find enclosed the yaml file of the API specification.

Thank you in advance.

slavaschmidt commented 7 years ago

Hey @SellamiRami ,

please take a look at your ResponseLine definition. It's property metadata is of type object and has no properties defined.

SellamiRami commented 7 years ago

Dear @slavaschmidt,

Thank you very much for your assistance. It perfectly works.

Have a nice day.