Giter Site home page Giter Site logo

ahx / openapi_first Goto Github PK

View Code? Open in Web Editor NEW
77.0 6.0 10.0 1.15 MB

Build your API on top of OpenAPI. Ensure that your implementation follows exactly your API description.

License: MIT License

Ruby 99.69% Shell 0.12% Dockerfile 0.14% Lua 0.06%
openapi rest-api api-server web-framework rack ruby jsonapi openapi3 apifirst

openapi_first's People

Contributors

ahx avatar brerx avatar dependabot[bot] avatar gitter-badger avatar gobijan avatar jan-bw avatar jf-lalonde avatar jzobel avatar theaamanda avatar twe4ked avatar ursm avatar y-yagi avatar yassenb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

openapi_first's Issues

The purpose of hanami in this gem?

Hi there 👋🏻

We're considering using openapi_first in a Rails app - particularly given the support for OpenAPI v3.1 - but I'm wondering why hanami-router is a dependency for the validation process? To be clear: I'm a fan of hanami, and use it in other projects - it's just that I don't want to bring in a tonne of new indirect dependencies for such a focused need, and I don't immediately grok the purpose of it here. If you have the time to enlighten me, that'd be much appreciated :)

Add option to find a custom handler

Sometimes you dont want to change the operationId so map the operation to a handler. The library should support that.

Some options:

  • Use a x-handler field that overwrites the operationId field
  • Use code to map one operationId to a certain handler

🤔

Manual response validation breaking change in 1.0.0->1.1.0 upgrade

Hi!

I just upgraded to 1.0.0 and then to 1.1.0. I am using the manual response validation (more or less) as follows:

# in my middleware
definition = OpenapiFirst.load(...)
response = @app.call(env)
definition.request(Rack::Request.new(env)).response(Rack::Response[*response]).validate!

My response validation breaks in 1.1.0 with NoMethodError: undefined method 'join' for #<ActionDispatch::Response::RackBody:... on @rack_response.body.join in OpenapiFirst::RuntimeRequest (here) because my @rack_response.body is a ActionDispatch::Response::RackBody.

In the rack repo I found that the body is usually expected to respond to each or call so maybe we could go back to using each? :)

Improve error message if value is not defined in enum

In the error {"errors":[{"source":{"pointer":"/data/type"},"title":"is not valid: \"my_type1\""}]} I have no clues which are the valid values, which would be nice to print in case of an enum so it's easier to find out what error one did when specifying the endpoint in the openapi.yaml

415 Unsupported Media Type when posting form data from Postman

Hi there @ahx ,

I have this spec:

paths:
  /api/v1/test:
    post:
      summary: test
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              properties:
                id:
                  type: string
                  format: uuid

And when I try to do a POST with form-data on Postman, I get

{
    "errors": [
        {
            "status": "415",
            "title": "Unsupported Media Type"
        }
    ]
}

Is is my Postman request body:
Screen Shot 2022-12-20 at 9 45 44 PM

and headers:

Screen Shot 2022-12-20 at 9 47 01 PM

Any idea why the response is unsupported Media Type?

thanks so much for this gem!

Manual request/response validation

The idea is to programatically validate requests/responses.

See also #169 (comment) #140.

Api proposal:

OpenapiFirst::RequestValidator.new('my/openapi.yaml')

request = Rack::Request.new(env)
validator.validate(request)  # Returns an object with details about the validation result (error?, schema, data, etc.)
validator.validate!(request) # Raises an exception if request is invalid

UPDATE: See Variant 1

Invalid JSON not gracefully handled

When providing a post body with invalid JSON (i.e. a trailing ,), I get an error 500 with a stack trace in the response instead of well formatted JSON error response:

MultiJson::ParseError: expected array element, not an array close (data.attributes.queueIds) at line 7, column 8 [parse.c:554]
	/Users/thomas.fruetel/.asdf/installs/ruby/2.7.0/lib/ruby/gems/2.7.0/gems/multi_json-1.14.1/lib/multi_json/adapters/oj.rb:34:in `load'
	/Users/thomas.fruetel/.asdf/installs/ruby/2.7.0/lib/ruby/gems/2.7.0/gems/multi_json-1.14.1/lib/multi_json/adapters/oj.rb:34:in `load'
	/Users/thomas.fruetel/.asdf/installs/ruby/2.7.0/lib/ruby/gems/2.7.0/gems/multi_json-1.14.1/lib/multi_json/adapter.rb:21:in `load'
	/Users/thomas.fruetel/.asdf/installs/ruby/2.7.0/lib/ruby/gems/2.7.0/gems/multi_json-1.14.1/lib/multi_json.rb:122:in `load'
	/Users/thomas.fruetel/.asdf/installs/ruby/2.7.0/lib/ruby/gems/2.7.0/gems/openapi_first-0.6.9/lib/openapi_first/request_validation.rb:47:in `parse_and_validate_request_body!'
...

Feel free to contact me on Slack/Discord if you need more detailed instructions to reproduce this.

Find handler methods during initialization

Currently handler functions are searched during each request, which is time consuming and not neccessary.

The plan:

  • move the namespace option from OperationResolver to Router and let Router find the handler method during initialization
  • replace OperationResolver with a very simple CallHandler class or the like

Spec has a binary field - openapi-first failing with exception trying to get the :tempfile

Field isn't in required so by default it is optional. Yet it's tried to be read.

data is the payload, property the name (image in my case) but it wasn't sent so data['image'] # nil

    def binary_format(data, property, property_schema, _parent)
      return unless property_schema.is_a?(Hash) && property_schema['format'] == 'binary'

      data[property] = data[property][:tempfile].read ### 
    end

Response validation middleware

Having a Rack middleware that does response validation (in development env) should be useful to help keeping implementation and API description even closer.

v1.0.0.beta5 release not available via rubygems.org

Hi :) I (and a couple of other people) have an issue with installing the newest version (beta5) from rubygems.
I know it's probably not a code-related issue (I tested the gem directly from the main branch and it works fine), but I couldn't find a better place to raise it.

# when using gem install
gem install openapi_first --pre --version "1.0.0.beta5"
ERROR:  Could not find a valid gem 'openapi_first' (= 1.0.0.beta5) in any repository
ERROR:  Possible alternatives: openapi_first

# when setting version in the Gemfile
Your bundle is locked to openapi_first (1.0.0.beta5) from rubygems repository https://rubygems.org/ or installed
locally, but that version can no longer be found in that source. That means the author of openapi_first (1.0.0.beta5)
has removed it. You'll need to update your bundle to a version other than openapi_first (1.0.0.beta5) that hasn't been
removed in order to install.

At the same time I can successfully download the gem from the rubygems https://rubygems.org/gems/openapi_first/versions/1.0.0.beta5 🤔

Performance benchmarks

Compare performance of this with a generic Sinatra, Rails, Hanami app that about the same request validation features.

Capture names affects finding definitions for nested routes

We had a surprising issue that lead us to hanami/router (see this issue: hanami/router#252) where defining routes with different capture names can lead to definitions not being found for nested paths.

Given the following paths:

/foo/{id}
/foo/{foo_id}/bar

The second route won't be found by the router. Luca suggested adding the /foo/{foo_id}/bar route first so it matches earlier.

I see a few options:

  1. Do nothing, maybe document the behaviour in the README to tell people not to mix capture names
  2. Order the paths intelligently before building the router
  3. Warn while building the router if there are path conflicts

Any other ideas?

Overwork Coverage testing

While Using the coverage functionality of openapi first i found some problem. In general it is a good idea to use the test_helper base class with before all and after all. But from this class it get inhertated several times. So it is not really a before all tests. Small example:

class RouteTest < Minitest::Test
  include Minitest::Hooks

  before(:all) do
    spec = OpenapiFirst.load('./openapi/openapi.yaml')
    @app_wrapper = OpenapiFirst::Coverage.new(VacationApi::App, spec)
  end

  after(:all) do
    message = 'The following paths have not been' \
              "called yet: #{@app_wrapper.to_be_called}"
    assert_empty @app_wrapper.to_be_called, message
  end

  def app
    @app_wrapper
  end
end

And inherit in different classes:

class QuotaTest < RouteTest
   ...
end

class OtherTest < RoutTest
   ...
end

As you see the coverage test is executed for QuotaTest and OtherTest class. So Test fails because OtherTest covers not QuotaTest routes.

Feedback wanted 👋🏼

I am wondering if anyone is using this and what they like and dislike about this tool. I have some ideas what to change, but I'd like to hear from people outside. Feel free to create issues or reply here or write something in the chat.

Set a valid default content-type from API description

Currently you have to set the response's content-type by yourself. Let's change that so that OpenapiFirst sets the content-type if it is not set by the app. Let's just pick the first content-type in the API description for the the status code returned by the app.

What's the best way to validation request/responses without using the router (in Rails)?

Hey,

We're currently (slowly) adding OpenAPI for request/response validation to an existing Rails app. We can't easily switch all the way to adding operations and the router to replace our controllers but I'd like to introduce some middleware to log schema errors so we can build a dashboard to track exceptional cases.

I've had a bit of a poke through the validator and middlewares included in the app but they all seem to reference operations and expect the router to be in place. I'd really appreciate a nudge in the right direction as I'll probably be digging into the private API a bit.

Cheers!

Custom error messages for request validation

When defining for example a parameter that represents a hex color ("/#[0-9a-f]{6}/i") a generic message like "does not match pattern" is not helpful.
Also think about i18n and fallbacks.

Support readOnly and writeOnly keywords

You can use the readOnly and writeOnly keywords to mark specific properties as read-only or write-only. This is useful, for example, when GET returns more properties than used in POST – you can use the same schema in both GET and POST and mark the extra properties as readOnly. readOnly properties are included in responses but not in requests, and writeOnly properties may be sent in requests but not in responses.

Related to davishmcclurg/json_schemer#55

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.