I have defined a 'number' field in my Open API documentation. In the request if I provide a string with only spaces the field gets processed as null while any other string gives bad request response.
I want to have bad request response for all the cases where a proper number isn't provided including when an empty string or spaces are there.
Open API snippet:
UpdateListRequest:
type: object
properties:
numberField:
type: integer
format: int32
minimum: 1
maximum: 4
required:
- action
Note: the number field is not a required field.
This is a gradle 6.0 project and source is at java version 1.8
My dependencies are -
dependencies {
compile group: 'io.swagger.core.v3', name: 'swagger-core', version: '2.0.9'
swaggerUI group: 'org.webjars', name: 'swagger-ui', version: '3.23.8'
swaggerCodegen 'io.swagger.codegen.v3:swagger-codegen-cli:3.0.11'
}
Related
Swagger-parser version: 2.1.1
Example swagger spec:
The test case is quite large, so I put it in a github gist. Don't be surprised by the names of the paths and schemes - I masked the critical data.
Description:
When using the ResolveFully option, I get requests with unresolved links. For example, take the request POST /v1/BusinePEH0JF. In swagger-ui it renders correctly - in the request body in the manager field, the Emplo4XN6X schema is resolved:
enter image description here
But swagger-parser gives this result:
enter image description here
Here the link is not resolved. This is most likely due to the fact that the parent schema BusinesYD77B4X in this request is stored as such in resolvedModels due to the fact that it is also used in other requests, such as POST /v1/ApprovalSetU0C9RY71SHD/manager-to-employees. Here, the manager field is empty, because this scheme has already been used above in the approver field.
enter image description here
Reproduction of the error:
val parseOptions = new ParseOptions()
parseOptions.setResolve(true)
parseOptions.setResolveFully(true)
val openAPI = new OpenAPIV3Parser().read(swaggerSpec, null, parseOptions)
Expected result:
Like on the first screen in swagger-ui
Thanks!
I have an API which is accepting query param as Object. I am using this to add multiple filters to filter the result.
When I hit the request from swagger, I am getting null for my filter object in the controller.
userFilter is the POJO class. It is used as a query param and in the controller, it is coming as null.
On swagger, it is showing as below
userFilter object is not getting constructed and getting NullPointerException in controller class when trying to access any field from userFilter.
I got the solution from swagger.io.
As per the explanation, content is used in complex serialization scenarios that are not covered by style and explode. For example, if we need to send a JSON string in the query string like so:
filter={"type":"t-shirt","color":"blue"}
In this case, we need to wrap the parameter schema into content/<media-type> as shown below.
We need to add content = {#Content(schema = #Schema(type = "object"))} to the #Parameter.
#Parameter(description = "Filters", required = true, content = {#Content(schema = #Schema(type = "object"))})
In JSON format it will look like below.
parameters:
- in: query
name: filter
# Wrap 'schema' into 'content.<media-type>'
content:
application/json: # <---- media type indicates how to serialize / deserialize the parameter content
schema:
type: object
properties:
type:
type: string
color:
type: string
So I'm no swagger expert, but all systems using swagger require you to have the swagger specification in JSON or YAML defining all endpoints (and such) of your API.
My question is: Are there know ways to generate these specification files based on the actual source code?
I'm asking, because it seems very hard to keep endpoint code & documentation in sync when you start adding properties or returning slightly different results.
So when I have this code (using http4s & RhoService):
object HelloWorld {
val service = new RhoService {
GET / "hello" / 'name |>> { name: String =>
Ok(Json.obj("message" -> Json.fromString(s"Hello, ${name}")))
}
}
}
It would be great if it could produce (in some way:)
/hello/{name}:
get:
tags:
- "HelloWorld"
summary: ""
description: ""
operationId: "getHellobyName"
produces:
- "application/json"
parameters:
- name: "name"
in: "path"
description: ""
required: true
type: "string"
responses:
200:
description: "successful operation"
schema:
$ref: "#/definitions/Hello"
security:
- api_key: []
Disclaimer: I'm the author of tapir.
rho is one possibility. Another approach is to completely separate the description of the API endpoint from the business logic.
Having a description of an endpoint, which is a regular Scala value, it can be then interpreted as either a server (given the "business logic" function), or documentation.
Two Scala libraries that can provide both http4s and OpenAPI interpreters are tapir and typeapi.
It is not documented well, but apparently http4s' RhoService adds middleware to generate a swagger.json based on your routes:
Fetch it by calling 'http://localhost:8080/swagger.json'
Git source: https://github.com/http4s/rho/blob/0c5aed48aeeea18b1d66d88b58cd3deea733f070/swagger/src/main/scala/org/http4s/rho/swagger/SwaggerSupport.scala#L30
Disclaimer: I’m the author of endpoints4s.
Similar to tapir (mentioned in another answer) endpoints4s is a library that can produce http4s servers and OpenAPI documentation for HTTP endpoints.
You would write your example like the following:
// --- This is the description of your HTTP service
import endpoints4s.algebra
case class Hello(message: String)
trait HelloWorldEndpoints
extends algebra.Endpoints
with algebra.JsonEntitiesFromSchemas {
implicit val helloJsonSchema: JsonSchema[Hello] =
field[String]("message")
.xmap(message => Hello(message))(hello => hello.message)
val hello: Endpoint[String, Hello] =
endpoint(
get(path / "hello" / segment[String]("name")),
ok(jsonResponse[Hello])
)
}
// --- This is an OpenApi documentation of the endpoints defined
// --- in HelloWorldEndpoints
import endpoints4s.openapi
import endpoints4s.openapi.model.{ Info, OpenApi }
object HelloWorldDocumentation
extends HelloWorldEndpoints
with openapi.Endpoints
with openapi.JsonEntitiesFromSchemas {
val api: OpenApi =
openApi(Info(title = "Hello API", version = "1.0"))(
hello
)
}
// --- This is an http4s server that implements the endpoints defined
// --- in HelloWorldEndpoints
import endpoints4s.http4s
import cats.effect.IO
import org.http4s.HttpRoutes
object HelloWorld
extends http4s.server.Endpoints[IO]
with http4s.server.JsonEntitiesFromSchemas
with HelloWorldEndpoints {
val service: HttpRoutes[IO] = HttpRoutes.of(
routesFromEndpoints(
hello.implementedBy(name => Hello(s"Hello, ${name}"))
)
)
}
// --- And this is an http4s service that publishes the OpenApi documentation
object OpenApiServer
extends http4s.server.Endpoints[IO]
with http4s.server.JsonEntitiesFromEncodersAndDecoders {
val openApiService: HttpRoutes[IO] = HttpRoutes.of(
routesFromEndpoints(
endpoint(
get(path / "open-api.json"),
ok(jsonResponse[OpenApi])
).implementedBy(_ => HelloWorldDocumentation.api)
)
)
}
I am looking for a way to add a fixed parameter to every request the client sends to the server.
For example: param1=false. The default value for the server is param1=true, but I want the generated client to send false with every request. Is this somehow possible?
I have tried:
default: false - which is documented to not work for this case
defaultValue: false - which seems to only work for the UI
enum: -false - which also seems to only work for the UI
Edit
When I generate Java Code with
- name: param1
in: query
type: boolean
required: true
enum: [true]
The generated code looks like this:
private com.squareup.okhttp.Call routeGetCall(Boolean param1){
Object localVarPostBody = null;
// verify the required parameter 'param1' is set
if (param1 == null) {
throw new ApiException("Missing the required parameter 'param1' when calling routeGet(Async)");
}
... more code ...
Param1 is never forced to be true. I can even set it false. Therefore, enum seems to be only working for the UI?
While it's possible to have a constant parameter with just one possible value, such as ?param1=true:
parameters:
- name: param1
in: query
type: boolean
required: true
enum: [true]
if a parameter has multiple possible values, such as true / false (as in your example), the spec cannot force any specific value for the parameter. It's up to the client to decide which value to use.
That is, the generated client code needs to be modified to use a specific parameter value.
I have created a site using LocomotiveCMS, I have created two content types called Photo and Gallery, these content types have a relationship so that I can create image galleries on my site.
I am currently looking to use the RESTful API in order to create multiple content entries for Photo as it traverses through a file.
I can connect to the API with no issue and modify the site etc.
I would assume that the cURL command for a new content entry would take the form of:
curl -X POST -d 'photo[image_id]=blah&photo[gallery]=1234&photo[file]=<filepath>photo[published]=true' 'http://<your site>/locomotive/api/current_site.json?auth_token=xxxx'
However I am unsure how to pass a file through in this command, I have substituted this for for now, how would you write this part?
My fields are set up as follows for Photo:
fields:
- image_id:
label: Image ID
type: string
required: true
localized: false
- file: # Name of the field
label: File
type: file
required: true
localized: false
- gallery: # Name of the field
label: Gallery
type: belongs_to
required: true
localized: false
# Slug of the target content type (eg post if this content type is a comment)
class_name: gallery
I ended up making a Ruby Script to parse files and upload them by sending the post data to
/locomotive/api/content_types/photos/entries.json?auth_token=XXXX
The following code can potentially help with this task:
data = {
content_entry: {
title: 'Title',
image: File.new('media/images/screen.png'),
}
}
HTTMultiParty.post(
"http://localhost:8080/locomotive/content_types/blogs/entries.json?auth_token=#{#token}",
query: data,
headers: { 'Content-Type' => 'application/json' }
)
I'm using HTTMultiParty since we actually need to do a multipart-post. Helpful information on how to do this with curl:
https://github.com/locomotivecms/documentation/pull/175
To get the token you need something like this:
HTTParty.post(
'http://localhost:8080/locomotive/api/tokens.json',
body: { api_key: 'YOUR_API_KEY_HERE' }
)
I hope that helps.
There is an api gem for LocomotiveCMS by now, works for 2.5.x and 3.x https://github.com/locomotivecms/coal
the attribute used need to end with _url for content entry fields with type=file https://github.com/locomotivecms/engine/pull/511/commits/f3a47ba5672b7a560e5edbef93cc9a4421192f0a