zalando-stups / swagger1st Goto Github PK
View Code? Open in Web Editor NEWA Clojure Ring handler that parses, validates and routes requests based on your Swagger definitions
License: ISC License
A Clojure Ring handler that parses, validates and routes requests based on your Swagger definitions
License: ISC License
The basePath
should be prepended to all specified paths.
in api.yaml:
parameters:
- name: firstname
but in clj code:
(-> request :parameters :query :name)
I had a typo so that parameter name differed between definition and usage sites. It would be nice if the library noticed that.
The version 1.3.2 of commons-fileupload
is vulnerable (see CVE). The dependency is included in the project through ring-core
:
[ring/ring-core "1.6.1" :scope "test"]
[commons-fileupload "1.3.2" :scope "test"]
The earliest fixed version of commons-fileupload
is 1.3.3, although 1.4 was also released in Dec 2018 (see https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload).
The library has been updated in ring-core
1.6.3 (see https://mvnrepository.com/artifact/ring/ring-core/1.6.3).
Proposed action: Update ring-core
to 1.6.3
This is applicable for $ref fields in the specification as follows from the JSON Schema definitions.
$ref
should not only look at relative elements but also external files or even URLs.
The New Relic dependency is out of scope of the project and is not required in most cases. OTOH it can be useful as a separate Ring middleware somewhere else. So I suggest to extract New Relic adapter into separate library project.
I can do code changes but since I do not use New Relic I would be unable to verify that it still works.
As an alternative I can prepare the PR that just removes New Relic adapter.
Determines the format of the array if type array is used. Possible values are:
Default value is
csv
- comma separated valuesfoo,bar
.ssv
- space separated valuesfoo bar
.tsv
- tab separated valuesfoo\tbar
.pipes
- pipe separated valuesfoo|bar
.multi
- corresponds to multiple parameter instances instead of multiple values for a single instancefoo=bar&foo=baz
. This is valid only for parametersin
"query" or "formData".csv
.
In the specification for internet date time, the millisec part (also called time-secfrac) is optional. However the current implementation in swagger1st this part is non-optional.
src/io/sarnowski/swagger1st/schemas/swagger_2_0.clj:170:43: deprecations: Var '#'schema.core/either' is deprecated.
See lein-eastwood for more occurences.
An additional primitive data type
"file"
is used by the Parameter Object and the
Response Object to set the parameter type or the response as being a file.
Currently api/throw-error
yields the following json:
{
"message": "Error",
"details": {...}
}
It would be cool if this could be changed to the application/problem+json RFC. The function signature can easily be the same.
Check inheritance of 'scheme' attribute.
Support Content-Type "problem+json" in addition to "application/json"
Hi,
Thanks for amazing project!
Are there any plans on upgrading swagger-ui to the recent versions to 3.x.x? (https://www.npmjs.com/package/swagger-ui#compatibility)
I have a minimal example:
Swagger API:
swagger: '2.0'
info:
title: Dummy example
version: "1.0.0"
basePath: /
paths:
/foo/:
post:
operationId: foo-bar.api/foo
consumes:
- application/json
parameters:
- name: bar
in: body
required: true
schema:
type: array
responses:
202:
description: Pet response
Handler of /foo/
:
(defn foo [request]
(-> (r/response {:message (-> request :parameters :body)})
(r/content-type "application/json")))
The server crashes when passing a JSON array in the body:
curl -v -XPOST -H "Content-Type: application/json" --data '{ "bar": [ ] }' 127.0.0.1:3000/foo
Log:
Nov 18, 2016 2:10:37 PM io.sarnowski.swagger1st.parser invoke
SEVERE: internal server error java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.CharSequence
java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.CharSequence
at clojure.string$split.invoke(string.clj:217)
at io.sarnowski.swagger1st.parser$eval6808$fn__6809.invoke(parser.clj:153)
at clojure.lang.MultiFn.invoke(MultiFn.java:233)
at io.sarnowski.swagger1st.parser$eval6855$fn__6856$fn__6857.invoke(parser.clj:207)
at io.sarnowski.swagger1st.parser$create_parser$fn__6914.invoke(parser.clj:317)
at io.sarnowski.swagger1st.parser$parse$fn__6942.invoke(parser.clj:353)
at clojure.core$map$fn__4553.invoke(core.clj:2624)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)
at clojure.core.protocols$fn__6506.invoke(protocols.clj:101)
at clojure.core.protocols$fn__6452$G__6447__6465.invoke(protocols.clj:13)
at clojure.core$reduce.invoke(core.clj:6519)
at clojure.core$group_by.invoke(core.clj:6861)
at io.sarnowski.swagger1st.parser$parse.invoke(parser.clj:355)
at io.sarnowski.swagger1st.core$chain_handler$chain_handler__7012$fn__7013.invoke(core.clj:33)
at io.sarnowski.swagger1st.mapper$correlate.invoke(mapper.clj:240)
at io.sarnowski.swagger1st.core$chain_handler$chain_handler__7012$fn__7013.invoke(core.clj:33)
at io.sarnowski.swagger1st.discoverer$discover.invoke(discoverer.clj:45)
at clojure.core$partial$fn__4527.invoke(core.clj:2495)
at io.sarnowski.swagger1st.core$chain_handler$chain_handler__7012$fn__7013.invoke(core.clj:33)
at clojure.lang.Var.invoke(Var.java:379)
at ring.middleware.reload$wrap_reload$fn__1444.invoke(reload.clj:22)
at ring.middleware.stacktrace$wrap_stacktrace_log$fn__876.invoke(stacktrace.clj:23)
at ring.middleware.stacktrace$wrap_stacktrace_web$fn__938.invoke(stacktrace.clj:86)
at ring.adapter.jetty$proxy_handler$fn__97.invoke(jetty.clj:24)
at ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
This happens with Swagger1st 0.22.0+
. It turned out the collectionFormat
is applied with parameters in body, which it shouldn't according to Swagger 2.0 spec:
If in is any value other than "body"
Similar to the ring router, implement an http client, that uses a swagger definition to construct an appropriate request.
(def call (create-client "api.yaml"))
(call "my-operation-id" {:path {:param1 "value1"}})
Client will figure out operation by operationId and then construct request with the given parameter map.
Support all security implementations according to the spec, basically always refer to an user-defined configuration or function to actually verify authentication/authorization.
(swagger-security :oauth2-config {:client-id "123" :client-secret "xyz" :idp "https://auth.example.org/"})
Validate all parameters and the response according to the schema given by the swagger definition.
Parsing JSON body parameters uses the "read-json" function which keywordizes JSON keys (https://github.com/sarnowski/swagger1st/blob/master/src/io/sarnowski/swagger1st/parser.clj#L89), this corrupts data containing keys such as "8080/tcp" or "key/with/slashes".
Pier One has a serious bug (zalando-stups/pierone#9) because of this behavior.
The TODO comment already mentions that the JSON body parsing behavior should be configurable.
The swagger spec allows parsing parameters from collection styles like 'csv', meaning comma separated parameters:
GET /users/123,456,789
would get the user 123, 456 and 789.
Currently missing:
(striked through entries are already done)
Introduced by me. Sorry.
Fix with PR is on the way.
Should not spam the log with WARNINGS about client's missing permissions. I propose changing these log lines to "INFO" and delete some places (e.g. if no auth was given).
See also zalando/friboo#34
This issue is about having clean logs. Internet-facing services will always get random requests without authentication --- this should not lead to WARNINGs in the logs as it does not trigger any action (developers will see WARNINGs but can't do anything about it as you cannot "control the internet" to avoid "random" requests from spiders etc).
WARNINGs should always be "actionable", i.e. I should be able to fix them as a developer.
Like done in Friboo.
Running lein new swagger1st myproject
as instrcuted in README finds [swagger1st/lein-template "0.15.1"] on Clojars and generates a project that has [io.sarnowski/swagger1st "0.15.0"]
as dependency.
lein new swagger1st foobar
If a requests with an undefined key comes in, drop it silently instead of rejecting the request as this is better for compatiblity.
This should be an option in the parser module :allow-undefined-keys
.
It seems that path parameters (ones that have property "in: path") are passed to handler function as is.
This causes a problem since handler should now process values these parameters differently depending on how they are passed to API.
So parameters that are passed via path should be url-decoded before passing them to handler.
Example:
With API declared as
"/somepath/{parameter_name}":
get:
parameters:
- name: parameter-name
in: path
type: string
and actual call curl "localhost:8080/somepath/abc%3D%3D"
the handler function should get parameter map {:parameter_name "abc=="}
Used swagger1st implementation passes instead parameter map as {:parameter_name "abc%3D%3D"}
Version used 0.22.0-beta2
I admit that this is backwards-incompatible change but the right one.
Array parameters don't support empty arrays: collection format multi
returns (nil)
, all other collection formats raise an exception if no array is passed. The expected result is []
in all cases.
How should we handle the empty string? In the multi
case I would treat it as an array element, but how about the other formats? Would an empty string be equivalent to the parameter being absent, or should we interpret it as an array with a single element (i.e. the empty string)? @harti2006, @neremic, do you have an opinion?
However, the
format
property is an openstring
-valued property, and can have any value to support documentation needs. Formats such as"email"
,"uuid"
, etc., can be used even though they are not defined by this specification.
Instead of letting everyone specify it. s1st depends on this middleware so its not optional and s1st expects its behaviour, so its unlikely to be exchanged with some other parser
With schema parameters like:
parameters:
- in: "body"
name: "body"
description: "JSON array of words to add to the corpus"
required: true
schema:
type: "object"
required:
- words
properties:
words:
type: "array"
items:
type: "string"
Sending a request like:
{"words":"foobar"}
The create-value-parser "array" will use the string value "foobar" since body is the first value in path. The subsequent map function applies the items-parser to each character of the string.
I would expect just the word "foobar" to be parsed since the default split array would be a csv split.
multipart/form-data
- each parameter takes a section in the payload with an internal header. For example, for the headerContent-Disposition: form-data; name="submit-name"
the name of the parameter issubmit-name
. This type of form parameters is more commonly used for file transfers.
For development, it would be convenient to automatically reload the Swagger definition when it changes. One way could be to load the definition again on each request - as this is only meant for development purposes, this could be a clean start. Either implement supporting code for that or provide a documentation, how to set up your Ring handler, so that it reloads everything all the time.
Deserialization of application/json
already works, also support application/yaml
and application/xml
.
Serialize data structure during response according to response mimetype.
(swagger-endpoints :discovery "/.discovery" :definition "/.definition" :ui "/ui")
discovery document:
{
"definition": "/.definition",
"ui": "/ui"
}
Content-Type: application/json; charset=UTF-8
...should be handled correctly
i'm currently working on a project that will need parse swagger definitions and was looking around for a lib in clojure(-script) to do that. this project seem to be the most complete, but i will not need all of the other functionality here, so i wondered if you would be interested in splitting the swagger parsing into it's own lib.
I would also need to call from cljs, so maybe it's feasible to make one cljc lib instead of me including half a fork.
As we expected swagger1st to allow undefined properties in definitions, but it didn't, it took me a while to find out actually we can allow this using an option(:allow-undefined-keys) in parser, like below.
(s1st/parser :allow-undefined-keys true)
This and if there are other undocumented options, it should be documented so that devs can easily discover the option and use them.
The RFC 5785 specifies /.well-known/
paths for discovery documents of all kinds. The default in swagger1st should be /.well-known/schema
instead of /.discovery
.
Which means something else than clojure.data.json
, see this gist as proof.
parameters with 'in: body' parameter only works under the Operation Object.
Check 'Fixed Fields' of 'Path Item Object' on (http://swagger.io/specification/)
Currently the s1st parser serializes json responses with automatically: https://github.com/zalando/swagger1st/blob/183cba7e30e62da6a23df9078e7062830885d72e/src/io/sarnowski/swagger1st/parser.clj#L344
Unfortunately this happens only if the content type matches "application/json" exactly. In other words
are not recognized and hence not serialized.
Swagger1st should either support all possible json formats (like https://github.com/ring-clojure/ring-json) or not none at all.
For named maps, e.g.
{
"john": { "age": 24 },
"mary": { "age": 21 }
}
The current schema for the swagger definition parsing is too weak (e.g. number validation). Make the validation more precise.
In addition add more functional validation too (like existants of mappings for operationIds)
3 scenarios should be shown:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.