exegesis-js / exegesis Goto Github PK
View Code? Open in Web Editor NEWTools for implementing server-side OpenAPI 3.0.0
License: MIT License
Tools for implementing server-side OpenAPI 3.0.0
License: MIT License
Exegesis only pays attention to "servers" in the root Open API Object, and ignores "servers" anywhere else.
Is there a reason that setHeader
in ExegesisResponseImpl.ts
in a controller does not return this
and therefore is not chainable? The example in Exegesis Controllers.md
uses setHeader
in a chainable fashion if I am not mistaken.
Is there a difference besides the if(this.ended && !this._afterController)
check and chainability compared to to the method header
?
Currently the raw options are passed to preCompile(). However, it may be (more?) useful to have the compiledOptions. Specifically I'd like to create a plugin that can reference the controllers. But this currently fails if the controllers are passed as a path in the original options. The compiledOptions have already resolved the controllers string into an object but that is not accessible in preCompile().
"promise-breaker": "^4.1.11"
is broken, bc. it install version 4.1.13 when you reinstall deps.
with this version i get error in build process
> tsc
src/index.ts:185:25 - error TS2345: Argument of type 'Callback<MiddlewareFunction> | undefined' is not assignable to parameter of type 'Callback<(ctx: Context, next: Callback<void>) => Promise<void>> | null | undefined'.
Type 'Callback<MiddlewareFunction>' is not assignable to type 'Callback<(ctx: Context, next: Callback<void>) => Promise<void>> | null | undefined'.
Type 'Callback<MiddlewareFunction>' is not assignable to type 'Callback<(ctx: Context, next: Callback<void>) => Promise<void>>'.
Types of parameters 'value' and 'result' are incompatible.
Types of parameters 'next' and 'next' are incompatible.
Type 'Callback<void> | undefined' is not assignable to type 'Callback<void>'.
Type 'undefined' is not assignable to type 'Callback<void>'.
185 return pb.addCallback(done, async () => {
also package-lock.json should`nt be gitted.
Using exegesis-express, I am not sure how to access the express res object (for example, to call res.cookie)... The class ExegesisResponseImpl does not offer all those functions. Is the user expected to use origRes for those?
Idea: could the exegesis-express offer a res that is a proxy or a mixin to both the express res object and ExegesisReponse... I could dig into a more concrete suggestion
We are recording start and end time when the request is served, so we start recording time in postRouting and try to end recording just when a response is about to write headers. For this i am using onHeaders library (https://github.com/jshttp/on-headers) where we can override onHeaders listener, but it looks like it never invokes this listener. I suspect when it reaches to postController the header is already sent. please suggest
10.12.15
to 10.12.16
.This version is covered by your current version range and after updating it in your project the build failed.
@types/node is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
8.1.6
to 8.1.7
.This version is covered by your current version range and after updating it in your project the build failed.
lint-staged is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 2 commits.
315890a
fix: Resolve security vulnerability in dependencies (#615)
cbf0e0e
docs: Correct section about filtering files (#612)
See the full diff
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
Is-it possible to have an option or a plugin to automatically returns the answers provided in the swagger specification file inside a controller?
That will avoid us to create the same thing from the Swagger specification file and inside the controller.
Thanks a lot for your help.
Does this project have a license it is being released under?
I built a simple API to gain an understanding of your library. There is a single endpoint that is secured with the following scheme, which uses the sample authenticator that is detailed in OAS3 Security.md
securitySchemes:
sessionKey:
type: apiKey
in: header
name: session
When the session
header is missing from the request the expected message is returned with a 401
status.
curl -i -X GET 'http://localhost:3000/v1/greet?name=ted'
HTTP/1.1 401 Unauthorized
content-type: application/json
Date: Fri, 31 Aug 2018 09:47:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked
{"message":"Must authenticate using one of the following schemes: sessionKey."}
However, if the session header is specified but it is invalid, the same message is returned.
curl -i -X GET 'http://localhost:3000/v1/greet?name=ted' -H 'session: secret1'
HTTP/1.1 401 Unauthorized
content-type: application/json
Date: Fri, 31 Aug 2018 09:48:42 GMT
Connection: keep-alive
Transfer-Encoding: chunked
{"message":"Must authenticate using one of the following schemes: sessionKey."}
My initial conclusion was that the library was not detecting the session header, so I went digging into the code. I got down to the authenticate
method on in lib/oas3/Operation.js
and realised that it does detect the header, but noticed that it doesn't return the result if the security type is invalid
.
I would've expected that the message and status code that I defined and returned in the authenticator to be set in the response.
For multiple authenticators, I would expect the behaviour to the same as a successful authentication. That is, it would return the result of the first invalid authenticator encountered.
Really like this project, since currently there are no other alternatives to swagger-tools and swagger-node for OpenAPI 3.0, this seems like a great project.
I want to use it for one of my projects, but before I go on that journey wanted to understand your plans for 1.0 release.
master
branch failed. 🚨I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master
branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here is some links that can help you:
If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.
semantic-release cannot push the version tag to the branch master
on remote Git repository.
Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment.
Good luck with your project ✨
Your semantic-release bot 📦🚀
If the validation is part of OAS spec than it gives a nice Error object e.g.,
{
"message" : "Validation errors",
"errors" : [
{
"location" : {
"path" : [],
"name" : "message",
"docPath" : [
"paths",
"/hello",
"get",
"parameters",
"0"
],
"in" : "query"
},
"type" : "error",
"message" : "Missing required query parameter \"message\""
}
]
}
What is the best way to do additional validations (more complex ones) in controllers and return the error in similar format, obviously I can build it manually but ideally if the framework has a standard way to send such errors that would help in being consistent.
When building with tsc following error occures:
node_modules/exegesis/lib/types/bodyParser.d.ts:2:8 - error TS1192: Module '"http"' has no default export.
2 import http from 'http';
~~~~
error An unexpected error occurred: "Command failed.
I'm trying to add a custom onResponseValidationError
callback that sets the status to 400 and returns JSON containing validation errors.
Here is what I have so far:
const options = {
controllers: path.resolve(__dirname, './controllers'),
allowMissingControllers: false,
validateDefaultResponses: true,
onResponseValidationError: (result) => {
console.log("There is a validation error.");
return result.context.res.status(400).json(result.errors);
}
};
However I keep getting this as the response:
{
"message": "Trying to set status after response has been ended."
}
This is my controller for the reference:
exports.getGreeting = (context) => {
const name = context.params.query.name;
context.res
.status(200)
.setBody({invalidField: `Hello ${name}`});
}
I'm puzzled how to intercept regular controller flow on validation error and send a different response.
I'd like to create the controllers as classes and not in the functional way. I'd like to propose controllers to also support classes. This could be implemented as such:
I use request module to stream a image from another source to context response as below
exports.getResourceByName = async context => {
request('https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png').pipe(context.res);
};
and get this error
TypeError: dest.on is not a function
at Request.Stream.pipe (internal/streams/legacy.js:28:8)
at Request.pipe (D:\br24\projects\cps\node_modules\request\request.js:1488:34)
...
it works with res
from express
app.get('/google', (req, res) => {
request('https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png').pipe(res);
});
I am migrating a project from swagger-connect to exegesis-express.
If an endpoint is recognized, but the method is not swagger-connect will generate a 405 error message:
{
"message": "Path [/items] defined in Swagger, but POST operation is not.",
"statusCode": 405,
"status": 405,
"allowedMethods": [
"GET"
],
"code": "Method Not Allowed"
}
If I make the same request against my Exegesis server it is falling through to my 404 error handling.
In the 2 samples using Exegesis. One endpoint returns a string with a 200 status code.
What would be the recommended way to return a desired status code.
Taking an example of searching a database for a value that isn't there, one might return a 404 or 400 status code to the user depending on whether they are following a REST spec.
How can we the dev, catch any potential errors and then send a 404/400/XXX status code.
I found one method which would be to take an instance of ExegesisContext as a parameter to the controller being used and calling context.res.setStatus(404)
before returning any values but would this be the preferred way of doing things?
Hey there,
I was trying to convert a former Swagger 2 application to OpenAPI 3, switching to Exegesis. I began by following the Exegesis Tutorial which worked. Then I replaced the OpenAPI yaml and adjusted some names. Now my requests are still accepted and reply as expected - except if one of the fields is null. This was the original reason why I wanted to switch to OpenAPI 3 - it has the "nullable" attribute. Sadly, this seems to be ignored by exegesis.
So, here is my OpenAPI doc (it describes something similar to the payload sent by Bitbucket with webhooks):
openapi: 3.0.1
info:
title: My API
version: 1.0.0
paths:
'/push':
post:
summary: Greets the user
operationId: processMessageForPush
x-exegesis-controller: incoming
parameters:
- name: GIT_BRANCH
in: query
schema:
type: string
style: form
explode: false
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Payload"
responses:
'200':
description: YEAH
components:
schemas:
Payload:
description: >-
Message object. Containing set of control parameters and a payload
KeyValuePair array.
type: object
properties:
actor:
$ref: "#/components/schemas/User"
repository:
type: object
push:
$ref: "#/components/schemas/PushInfo"
PushInfo:
type: object
properties:
changes:
type: array
items:
$ref: "#/components/schemas/ChangeInfo"
ChangeInfo:
type: object
properties:
new:
$ref: "#/components/schemas/StateInfo"
old:
$ref: "#/components/schemas/StateInfo"
links:
$ref: "#/components/schemas/Links"
created:
type: boolean
forced:
type: boolean
closed:
type: boolean
commits:
type: array
items:
$ref: "#/components/schemas/CommitInfo"
truncated:
type: boolean
CommitInfo:
type: object
properties:
hash:
type: string
type:
type: string
message:
type: string
author:
$ref: "#/components/schemas/User"
links:
$ref: "#/components/schemas/Links"
StateInfo:
type: object
nullable: true
properties:
type:
type: string
name:
type: string
target:
$ref: "#/components/schemas/TargetInfo"
links:
$ref: "#/components/schemas/Links"
TargetInfo:
type: object
properties:
type:
type: string
hash:
type: string
author:
$ref: "#/components/schemas/User"
message:
type: string
date:
type: string
parents:
type: array
items:
$ref: "#/components/schemas/Parent"
links:
$ref: "#/components/schemas/Links"
Parent:
type: object
properties:
type:
type: string
hash:
type: string
links:
$ref: "#/components/schemas/Links"
User:
type: object
Links:
type: object
properties:
html:
$ref: "#/components/schemas/href"
diff:
$ref: "#/components/schemas/href"
commits:
$ref: "#/components/schemas/href"
self:
$ref: "#/components/schemas/href"
href:
type: object
properties:
href:
type: string
The request I send is a POST request to the URL http://localhost:3000/push?GIT_BRANCH=develop with the body as follows:
{
"push": {
"changes": [
{
"forced": false,
"old": null,
"links": {
"commits": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
},
"truncated": true,
"commits": [
{
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"comments": {
"href": "asdf"
},
"patch": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"diff": {
"href": "asdf"
},
"approve": {
"href": "asdf"
},
"statuses": {
"href": "asdf"
}
},
"author": {
"raw": "One Author",
"type": "author",
"user": {
"username": "test",
"display_name": "One Author",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "test",
"uuid": "asdf"
}
},
"summary": {
"raw": "sdfhsdhfsdf\n",
"markup": "markdown",
"html": "<p>sdfhsdhfsdf</p>",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-10-30T16:19:16+00:00",
"message": "sdfhsdhfsdf\n",
"type": "commit"
},
{
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"comments": {
"href": "asdf"
},
"patch": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"diff": {
"href": "asdf"
},
"approve": {
"href": "asdf"
},
"statuses": {
"href": "asdf"
}
},
"author": {
"raw": "One Author",
"type": "author",
"user": {
"username": "test",
"display_name": "One Author",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "test",
"uuid": "asdf"
}
},
"summary": {
"raw": "because I need real commits to test my triggers, I will fix all the spelling mistakes\n",
"markup": "markdown",
"html": "<p>because I need real commits to test my triggers, I will fix all the spelling mistakes</p>",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-10-30T15:46:20+00:00",
"message": "because I need real commits to test my triggers, I will fix all the spelling mistakes\n",
"type": "commit"
},
{
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"comments": {
"href": "asdf"
},
"patch": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"diff": {
"href": "asdf"
},
"approve": {
"href": "asdf"
},
"statuses": {
"href": "asdf"
}
},
"author": {
"raw": "asdf",
"type": "author",
"user": {
"username": "asdf",
"display_name": "asdf",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "asdf",
"uuid": "asdf"
}
},
"summary": {
"raw": "Updated Version to 1.0\n",
"markup": "markdown",
"html": "<p>Updated Version to 1.0</p>",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-09-07T12:38:19+00:00",
"message": "Updated Version to 1.0\n",
"type": "commit"
},
{
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"comments": {
"href": "asdf"
},
"patch": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"diff": {
"href": "asdf"
},
"approve": {
"href": "asdf"
},
"statuses": {
"href": "asdf"
}
},
"author": {
"raw": "asdf",
"type": "author",
"user": {
"username": "asdf",
"display_name": "asdf",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "asdf",
"uuid": "asdf"
}
},
"summary": {
"raw": "Updated Version to 1.0.2-testprod\n",
"markup": "markdown",
"html": "<p>Updated Version to 1.0.2-testprod</p>",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-07-19T09:24:19+00:00",
"message": "Updated Version to 1.0.2-testprod\n",
"type": "commit"
},
{
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"comments": {
"href": "asdf"
},
"patch": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"diff": {
"href": "asdf"
},
"approve": {
"href": "asdf"
},
"statuses": {
"href": "asdf"
}
},
"author": {
"raw": "One Author",
"type": "author",
"user": {
"username": "test",
"display_name": "One Author",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "test",
"uuid": "asdf"
}
},
"summary": {
"raw": "asdf",
"markup": "markdown",
"html": "asdf",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-07-19T08:29:02+00:00",
"message": "asdf",
"type": "commit"
}
],
"created": true,
"closed": false,
"new": {
"target": {
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
},
"author": {
"raw": "One Author",
"type": "author",
"user": {
"username": "test",
"display_name": "One Author",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "test",
"uuid": "asdf"
}
},
"summary": {
"raw": "sdfhsdhfsdf\n",
"markup": "markdown",
"html": "<p>sdfhsdhfsdf</p>",
"type": "rendered"
},
"parents": [
{
"type": "commit",
"hash": "123412341234",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
}
}
],
"date": "2018-10-30T16:19:16+00:00",
"message": "sdfhsdhfsdf\n",
"type": "commit"
},
"links": {
"commits": {
"href": "asdf"
},
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
}
},
"default_merge_strategy": "merge_commit",
"merge_strategies": [
"merge_commit",
"squash",
"fast_forward"
],
"type": "branch",
"name": "spelling"
}
}
]
},
"repository": {
"scm": "git",
"website": "",
"name": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"project": {
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "project",
"uuid": "asdf",
"key": "asdf",
"name": "asdf"
},
"full_name": "asdf/asdf",
"owner": {
"username": "asdf",
"type": "team",
"display_name": "asdf",
"uuid": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
}
},
"type": "repository",
"is_private": true,
"uuid": "asdf"
},
"actor": {
"username": "test",
"display_name": "One Author",
"account_id": "asdf",
"links": {
"self": {
"href": "asdf"
},
"html": {
"href": "asdf"
},
"avatar": {
"href": "asdf"
}
},
"type": "user",
"nickname": "test",
"uuid": "asdf"
}
}
As you can see, the value for push.changes[0].old is null, which is why I made the according schema nullable. Still, I receive the following answer:
{
"message": "Validation errors",
"errors": [
{
"message": "should be object",
"location": {
"in": "request",
"name": "body",
"docPath": "/paths/~1push/post/requestBody/content/application~1json/schema",
"path": "/push/changes/0/old"
}
}
]
}
How is that possible? Apart from some names, I did not change the options or the content of index.js as explained in the tutorial.
(Field contents in the payload have been partly anonymized.)
How do I add the cors middleware to express?
I tried with app.use(cors(exegesisMiddleware));
But it does not work.
I have searched for an exegesis-plugin-cors plugin also, but only found: exegesis-plugin-context
Can this be used for cors?
🚨 You need to enable Continuous Integration on all branches of this repository. 🚨
To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.
Since we didn’t receive a CI status on the greenkeeper/initial
branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.
If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/
.
Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial
branch in this repository, and then remove and re-add this repository to the Greenkeeper App’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.
Parameters with "label" style are not supported.
I have seen other OpenAPI/Swagger frameworks which provide a live documented version of the API usually located at the '/ui' path. I believe this is achieved using swagger-ui.
Would this be possible to include functionality for this with Exegesis as an optional feature? I would be happy to help via PR's
Story:
As a Developer, I want to have the option for generating a UI docs page so that when needed, developers won't have to code it themselves.
In openapi.yaml, defining a server url like below is currently not working
servers:
- url: '/api/0.1'
I have traced the bug to this line where basepath
should be set using match[0]
instead of match[1]
That fixed it for me.
oas3/Path.js does not list PATCH among HTTP-methods:
const HTTP_METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE'];
This results in all paths with patch is ignored.
Some client library automatically adds a "content-type: application/json" header to all requests if such header is absent, which causes the api server to return "Invalid content-type: application/json" on GET requests. Since it doesn't make much sense to have a content-type header in get requests, is it possible to add an option to not validate content type for GET?
Thanks
I have been building out an API which utilises Exegesis to map an OpenAPI doc to routes. I am wondering how this can be tested, given the setup of Exegesis is a little different than a normal Express API. It would be great to have some resource to reference on how testing can be done.
As a Exegesis API developer
I want a streamlined way to test my routes
So that automated testing can be done on the routes; This would allow for CI/CD testing also.
Acceptance Criteria:
Scenario 1:
Given a number of controllers in the controllers folder
And each of these routes mapped to a OpenAPI path
When it comes to testing
There should be a boilerplate that can be followed or some documentation
I can help with this but would need some guidance on where to start.
I realize the following structure is not great, but it matches a legacy API that we can't change without potentially breaking customer's programs. If I was implementing this today, we would do this differently.
I have a body property that can either be a positive integer (minValue: 1) or it can be a string value representing the name of something. The integer and the string both uniquely identify something.
POST .../object/{objectID}
{
tagIdentifier: 15
}
OR
POST .../object/{objectID}
{
tagIdentifier: "Name of label"
}
I wrote up the definition for tagIdentifier as:
Object:
properties:
tagIdentifier:
oneOf:
- type: string
- type: number
format: int64
minimum: 1
Howerver, the following was passing schema validation:
POST .../object/{objectID}
{
tagIdentifier: -1
}
Digging into the issue I traced it back to the validator which was coercing the 'tagIdentifier' value to always be a string value, so when it went through validation it was checking this as "-1"
instead of as the actual -1
value.
Digging through the code it appears the issue is tied to the initialization of Ajv.
exegesis/src/oas3/Schema/validators.ts
Line 193 in 41ccdb8
This is hardly beautiful, but I was able to test out a fix by adding the following lines right before the ajv initialization:
let coerceTypesOveride = allowTypeCoercion ? 'array' : false;
if (allowTypeCoercion && parameterLocation.in === 'request') {
// We do not want to allow type coercion on request bodies in any form.
coerceTypesOveride = false;
}
Changing the type coercion to NOT coerce arrays fixed a separate issue I was having as well, where an array of enum values was accepting a non-array. It was a lesser issue that I was going to ignore, but this resolves that as well.
Currently I am in crunch trying to get our swagger-node to exegesis-express conversion done, but once that is finished I will see if I can send a pull request to resolve this if you agree with the changes. Maybe there could be a configuration option to choose when to allow type coercion? I think query and path are pretty much required to do type coercion, but it should be an option for request bodies.
@jwalton What's the best way of returning all the errors when validating the request body. It feels like bad user experience to not respond with all the information available.
Would it be ok to just set allErrors: true
in the ajv
options by default?
I have a path (Please excuse any formatting errors, I am typing this up in the text box):
'/items':
get:
x-exegesis-controller: get_Items
description: Gets items
operationId: getItems
parameters:
- name: fields
in: query
schema:
type: array
items:
type: string
enum:
- field1
- field2
- field3
- field4
responses:
'200':
description: Success
I am expecting to be able to run the following query: GET /api/v0/items?field1,field2
However when I run that I get the following error:
{
"message": "Validation errors",
"errors": [
{
"message": "should be equal to one of the allowed values",
"location": {
"in": "query",
"name": "fields",
"docPath": "/paths/items/get/parameters/1/schema",
"path": "/0"
}
}
]
}
I did some digging, and I think this issue is tied to this line:
I was able to hack around the problem by changing that line from return [decodeURIComponent(value)];
to return decodeURIComponent(value).split(',');
Getting an error when using floats in my spec:
Error: unknown format "float" is used in schema at path "#/properties/price"
In Operation.js line 315, notice how the code sets a message in the response body directly. This makes it hard for applications to format the error response, for instance, if we need to always return RFC 7807 Problem Details for HTTP APIs.
Since the rest of Exegesis already has an HttpError type defined and even an option parameter that controls whether Exegesis should handle the conversion of these errors into HTTP error responses, shouldn't the authentication process also use this code flow?
It would avoid creating extra code in our applications specifically for 401 responses.
15.9.15
to 15.9.16
.This version is covered by your current version range and after updating it in your project the build failed.
semantic-release is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 2 commits.
b9ae7d2
fix(package): update env-ci to version 3.0.0
c27e18e
chore(package): update nock to version 10.0.0
See the full diff
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
Headers field names are case-insensitive as per RFC7230, but they're being treated as case-sensitive in requests.
The root of the problem seems to be that in oas3/parameterParsers/index.ts
, many parameters go through the toStructuredParser
function, that does const value = rawParamValues[location.name]
. rawParamValues
has the header keys already in lower-case, while location.name
is still in Train-Case.
I've got a PR to fix this in the works, though I'm not sure if the way I solved this was the best approach possible. I copied the one used for query parameters -- to call a different function in oas3/Operation.ts
in parseParameters
for them and, do a little preprocessing -- but it feels a little redundant to do this for each location (i.e. in: query / in: header), when we already have custom parsers that vary by style / format.
4.14.124
to 4.14.125
.This version is covered by your current version range and after updating it in your project the build failed.
@types/lodash is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
4.14.126
to 4.14.127
.This version is covered by your current version range and after updating it in your project the build failed.
@types/lodash is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
My openAPI.yaml is:
openapi: "3.0.1"
info:
version: 1.0.0
title: Exegesis Integration Test
license:
name: MIT
paths:
/greet:
get:
summary: List all pets
x-exegesis-controller: greetController
operationId: greetGet
parameters:
- name: name
in: query
description: Name of user to greet
required: true
schema:
type: string
responses:
'200':
description: Greet message.
content:
application/json:
schema:
type: object
required:
- greeting
properties:
greeting: {type: string}
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/secure:
get:
summary: A secure operation
x-exegesis-controller: secureController
operationId: secureGet
security:
- sessionKey: []
responses:
'200':
description: Greet message.
content:
application/json:
schema: {type: 'object'}
components:
securitySchemes:
sessionKey:
type: 'apiKey'
name: 'session'
in: 'header'
schemas:
Error:
required:
- message
properties:
message: {type: string}
copy from 'https://github.com/exegesis-js/exegesis-express/blob/master/test/integrationSample/openapi.yaml'.
Main is index.js:
import express from 'express';
import path from 'path';
import http from 'http';
import * as exegesisExpress from 'exegesis-express';
async function createServer() {
// See https://github.com/exegesis-js/exegesis/blob/master/docs/Options.md
const options = {
controllers: path.resolve(__dirname, './controllers')
};
const exegesisMiddleware = await exegesisExpress.middleware(
path.resolve(__dirname, './openApi.yaml'),
options
);
const app = express();
// If you have any body parsers, this should go before them.
app.use(exegesisMiddleware);
app.use((req, res) => {
res.status(404).json({message: `Not found`});
});
app.use((err, req, res, next) => {
res.status(500).json({message: `Internal error: ${err.message}`});
});
const server = http.createServer(app);
server.listen(3000);
}
createServer();
when I run babel-node index.js, then I get:
➜ exegesis babel-node index.js
(node:6771) UnhandledPromiseRejectionWarning: Error: Operation /paths/~1secure/get references security scheme "sessionKey" but no authenticator was provided.
at new Operation (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/Operation.ts:133:27)
at Path._operations.HTTP_METHODS.map.filter.reduce (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/Path.ts:36:38)
at Array.reduce (<anonymous>)
at new Path (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/Path.ts:34:14)
at new Paths (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/Paths/index.ts:17:32)
at new OpenApi (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/OpenApi.ts:50:23)
at Object.<anonymous> (/Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/src/oas3/index.ts:16:12)
at Generator.next (<anonymous>)
at /Users/yaojifeng/WebstormProjects/exegesis/node_modules/exegesis/lib/oas3/index.js:7:71
at new Promise (<anonymous>)
(node:6771) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:6771) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1.2.0
to 1.2.1
.This version is covered by your current version range and after updating it in your project the build failed.
supertest-fetch is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 1 commits.
dddfd29
fix: Fix to handle case when passed in server is bound to a UNIX domain socket.
See the full diff
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
Hi Jason,
It would be great for developers using the library to be able to provide custom error formats.
For example, I would like to provide data so that a front end could localize an error message in the browser user's locale or customise the message entirely.
I noticed that exegesis uses Ajv
which provides a lot of data points. See ajv#error-objects
My thoughts are to:
IValidationError
and set appropriatelysrc/core/exegesisRunner.ts#handleError
to maintain current format for backward compatibility.autoHandleHttpErrors
to false, catch and format the errors as they wish.I would appreciate your feedback. I don't mind giving this a stab if you think it is a good idea.
Cheers,
Niall
1.0.3
to 1.1.0
.This version is covered by your current version range and after updating it in your project the build failed.
openapi3-ts is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.
The new version differs by 4 commits.
e0f2a55
version 1.1.0
57f828f
upgrade libs
a372e24
Merge pull request #35 from mauriedo/fix-references-in-components-types
2204058
fix references in components
See the full diff
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
@jwalton I am trying to figure out a way to get the custom extensions from yaml file for the current path.
I was able to get it using,
context.api.pathItemObject.get["x-rate-limit"]
Is this the recommended way of getting these custom extensions?
I implemented a controller that send mocks response using json-schema-faker v0.4.7.
myController.js
const jsf = require('json-schema-faker');
jsf.option({ optionalsProbabilty: 0.5 });
const jsonSchema = require("exegesis/lib/utils/jsonSchema");
exports.getPartenaireById = function getPartenaireById(context) {
const path = `${context.api.operationPtr}/responses/200/content/application~1json/schema`;
let schema = jsonSchema.extractSchema(context.api.openApiDoc, path);
const mock = jsf(schema);
return mock;
}
Perhaps you have a good solution to make it generic and integrate it in the core or in a plugin?
Thanks
exegesis-express
does not validate the body of a JSON response even if response validation is enabled with the onResponseValidationError
option.
Install node v10.12.0
(current LTS) or newer.
Extract the minimal example: exegesis-example.zip
Run npm i && node .
Send a GET
request against http://localhost:8080/
The server responds with status code 500 and message Response validation failed
The server responds with status code 200 and message { "message": {} }
.
Stepping through Response.validateResponse
reveals, that response validation is skipped silently (in itself arguably not correct if a response specification exists) if the body is a string, which it always seems to be, even if the controller returns an object or calls res.json
.
12.0.1
to 12.0.2
.This version is covered by your current version range and after updating it in your project the build failed.
@types/node is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
Exegesis has support for x-www-form-urlencoded bodies, but if you give it a complicated schema, it will probably have a hard time finding your properties, or may get the types wrong.
You can avoid this by using a schema where all the properties are at the top level. But what really needs to happen here is, we need to replace this with something which recursively traverses all the allOf
, oneOf
, and anyOf
keys to extract a schema for each property.
I have two different 'paths' in my application:
POST /api/v0/{grouping}/items/generate
GET /api/v0/{grouping}/items/{id}
The two paths appear in my openapi.yaml file in that order. While doing testing I noticed that when I called POST /api/v0/{grouping}/items/generate
no controller was getting called.
I stepped through the exegesisRunner until I hit the PathResolver.resolvePath
function and noticed that when I ran POST /api/v0/{grouping}/items/generate
, resolvePath
was returning GET /api/v0/{grouping}/items/{id}
with 'grouping' set as a parameter, and with 'id' set as 'generate'.
When I stepped through resolvePath
I noticed that the for loop @
exegesis/src/oas3/Paths/PathResolver.ts
Line 128 in 3dd1f3d
As in, it first finds the 'generate' endpoint, then keeps processing the path and the last path it processes that matches is the GET .../items/{id}, so it returns that.
As a temporary hack, I have changed my local code such that the for
loop stops once it matches any path, but then it leaves the end user at the mercy of the order they define their endpoints in their specification file.
I am not sure if there is a way you can change the code to build up a list of 'matched' paths, and then prefer paths that have more 'fixed' values over paths that have more variables?
As an exegesis user
I want a way to test my controllers
so that I can also test certain parts of the context (does the controller set the correct status code for example)
given an exegesis controller
when my controller modifies the status code
then I should be able to asset this change with access to the context object
given an exegesis controller
when my controller returns a result to the user
then I should be able review the returned payload to ensure it conforms to specs
I could try to implement this but wondering where to start.
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.