Git Product home page Git Product logo

pb33f / wiretap Goto Github PK

View Code? Open in Web Editor NEW
81.0 1.0 16.0 2.53 MB

The world's coolest API Validation and compliance tool. Validate APIs against OpenAPI specifications and much more

Home Page: https://pb33f.io/wiretap/

License: Other

Go 49.54% HTML 0.51% TypeScript 43.31% CSS 5.80% Makefile 0.03% Dockerfile 0.12% JavaScript 0.69%
api api-gateway api-rest api-server api-testing openapi openapi-spec openapi-specification openapi-validate openapi-validation

wiretap's People

Contributors

daveshanley avatar epictek avatar jacobm-splunk avatar macyabbey avatar martinsirbe avatar n0rig avatar rautio 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  avatar  avatar  avatar  avatar

Watchers

 avatar

wiretap's Issues

Request with query param style `deepObject` failing validation

This is a bit of a tough one as deepObject serialization is not very well defined but we support deepObject serialization that is compatible with a number of different server frameworks, but wiretap is failing validation on a request that does work with other services.

Here is the spec (btw this is a distilled down version of the real spec I am using and this distilled version causes this issue #81 so hard to test in isolation and I can't provide the full spec I am using atm):

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
paths:
  /anything/queryParams/deepObject/map:
    get:
      operationId: deepObjectQueryParamsMap
      parameters:
        - name: mapParam
          in: query
          style: deepObject
          schema:
            type: object
            additionalProperties:
              type: string
            example: { "test": "value", "test2": "value2" }
          required: true
        - name: mapArrParam
          in: query
          style: deepObject
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                type: string
            example: { "test": ["test", "test2"], "test2": ["test3", "test4"] }
      responses:
        "200":
          description: OK

The error returned is:

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":500,"detail":"Error: Query parameter 'mapArrParam' is not a valid deepObject, Reason: The query parameter 'mapArrParam' has the 'deepObject' style defined, There are multiple values (2) supplied, instead of a single value, Line: 1498, Column: 18\nError: Query parameter 'mapArrParam' failed to validate, Reason: The query parameter 'mapArrParam' is defined as an object, however it failed to pass a schema validation, Validation Errors: [Reason: expected array, but got string, Location: /additionalProperties/type Reason: expected array, but got string, Location: /additionalProperties/type], Line: 1500, Column: 13"}

The query string being sent is:

"mapArrParam%5Btest2%5D=test3&mapArrParam%5Btest2%5D=test4&mapArrParam%5Btest%5D=test&mapArrParam%5Btest%5D=test2&mapParam%5Btest2%5D=value2&mapParam%5Btest%5D=value"

basically the array is represented by listing the same key multiple times

request unexpectedly fails validation

Consider this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
paths:
  /requestbody#map:
    post:
      operationId: requestBodyPostApplicationJsonMap
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/mapValue"
        required: true
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                title: res
                type: object
                additionalProperties:
                  $ref: "#/components/schemas/simpleObject"
  /requestbody#arrayCamelCase:
    post:
      operationId: requestBodyPostApplicationJsonArrayCamelCase
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/arrValueCamelCase"
        required: true
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                title: res
                type: array
                items:
                  $ref: "#/components/schemas/simpleObjectCamelCase"
components:
  schemas:
    arrValueCamelCase:
      type: array
      items:
        $ref: "#/components/schemas/simpleObjectCamelCase"
    mapValue:
      type: object
      additionalProperties:
        $ref: "#/components/schemas/simpleObject"
    simpleObject:
      description: "A simple object that uses all our supported primitive types and enums and has optional properties."
      externalDocs:
        description: "A link to the external docs."
        url: "https://docs.speakeasyapi.dev"
      type: object
      properties:
        str:
          type: string
          description: "A string property."
          example: "test"
        bool:
          type: boolean
          description: "A boolean property."
          example: true
        int:
          type: integer
          description: "An integer property."
          example: 1
        int32:
          type: integer
          format: int32
          description: "An int32 property."
          example: 1
        num:
          type: number
          description: "A number property."
          example: 1.1
        float32:
          type: number
          format: float
          description: "A float32 property."
          example: 1.1
        enum:
          $ref: "#/components/schemas/enum"
        date:
          type: string
          format: date
          description: "A date property."
          example: "2020-01-01"
        dateTime:
          type: string
          format: date-time
          description: "A date-time property."
          example: "2020-01-01T00:00:00.000001Z"
        any:
          description: "An any property."
          example: "any"
        strOpt:
          type: string
          description: "An optional string property."
          example: "testOptional"
        boolOpt:
          type: boolean
          description: "An optional boolean property."
          example: true
        intOptNull:
          type: integer
          description: "An optional integer property will be null for tests."
        numOptNull:
          type: number
          description: "An optional number property will be null for tests."
        intEnum:
          type: integer
          description: "An integer enum property."
          enum:
            - 1
            - 2
            - 3
          example: 2
          x-speakeasy-enums:
            - First
            - Second
            - Third
        int32Enum:
          type: integer
          format: int32
          description: "An int32 enum property."
          enum:
            - 55
            - 69
            - 181
          example: 55
        bigint:
          type: integer
          format: bigint
          example: 8821239038968084
        bigintStr:
          type: string
          format: bigint
          example: "9223372036854775808"
        decimal:
          type: number
          format: decimal
          example: 3.141592653589793
        decimalStr:
          type: string
          format: decimal
          example: "3.14159265358979344719667586"
      required:
        - str
        - bool
        - int
        - int32
        - num
        - float32
        - enum
        - date
        - dateTime
        - any
        - intEnum
        - int32Enum
    simpleObjectCamelCase:
      description: "A simple object that uses all our supported primitive types and enums and has optional properties."
      externalDocs:
        description: "A link to the external docs."
        url: "https://docs.speakeasyapi.dev"
      type: object
      properties:
        str_val:
          type: string
          description: "A string property."
          example: "example"
        bool_val:
          type: boolean
          description: "A boolean property."
          example: true
        int_val:
          type: integer
          description: "An integer property."
          example: 999999
        int32_val:
          type: integer
          format: int32
          description: "An int32 property."
          example: 1
        num_val:
          type: number
          description: "A number property."
          example: 1.1
        float32_val:
          type: number
          format: float
          description: "A float32 property."
          example: 2.2222222
        enum_val:
          $ref: "#/components/schemas/enum"
        date_val:
          type: string
          format: date
          description: "A date property."
          example: "2020-01-01"
        date_time_val:
          type: string
          format: date-time
          description: "A date-time property."
          example: "2020-01-01T00:00:00Z"
        any_val:
          description: "An any property."
          example: "any example"
        str_opt_val:
          type: string
          description: "An optional string property."
          example: "optional example"
        bool_opt_val:
          type: boolean
          description: "An optional boolean property."
          example: true
        int_opt_null_val:
          type: integer
          description: "An optional integer property will be null for tests."
          example: 999999
        num_opt_null_val:
          type: number
          description: "An optional number property will be null for tests."
          example: 1.1
        int_enum_val:
          type: integer
          description: "An integer enum property."
          enum:
            - 1
            - 2
            - 3
          example: 3
          x-speakeasy-enums:
            - First
            - Second
            - Third
        int32_enum_val:
          type: integer
          format: int32
          description: "An int32 enum property."
          enum:
            - 55
            - 69
            - 181
          example: 69
        bigint_val:
          type: integer
          format: bigint
        bigint_str_val:
          type: string
          format: bigint
        decimal_val:
          type: number
          format: decimal
      required:
        - str_val
        - bool_val
        - int_val
        - int32_val
        - num_val
        - float32_val
        - enum_val
        - date_val
        - date_time_val
        - any_val
        - int_enum_val
        - int32_enum_val
    enum:
      type: string
      description: "A string based enum"
      enum:
        - "one"
        - "two"
        - "three"
        - "four_and_more"
      example: "one"
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

When sending the request body like so:

[{"any_val":"any","bigint_str_val":"1344719667586153181419716641724567886890850696275767987106294472017884974410332069524504824747437757","bigint_val":8821239038968084,"bool_opt_val":true,"bool_val":true,"date_time_val":"2020-01-01T00:00:00.000000001Z","date_val":"2020-01-01","enum_val":"one","float32_val":1.1,"int32_enum_val":55,"int32_val":1,"int_enum_val":2,"int_val":1,"num_val":1.1,"str_opt_val":"testOptional","str_val":"test"}]

I get this error from wiretap:

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":500,"detail":"Error: POST request body for '/requestbody' failed to validate schema, Reason: The request body is defined as an object. However, it does not meet the schema requirements of the specification, Validation Errors: [Reason: expected object, but got array, Location: /type], Line: 55, Column: 7"}

I believe this is related to #78

Basically I think its validating against the wrong operation and it seems to be non-deterministic (prob due to map order in Go) as sometimes I start wiretap and it works and sometimes I start it and it doesn't work.

I imagine this would be sorted by looping through all operations that match the path instead of just the first found?

consider changing license type

Hi, awesome tool. I'd love to use it at work for my development team, however, the AGPL license forces any system that connects to it to be open sourced. That forces proprietary business services, both internal and external, to be open sourced. As such it's not useable. Would you consider using a BSL license or similar, which prohibits anyone for making money by providing the software as a service while still enabling internal use cases for businesses. Thanks for your consideration.

Spec with multiple alternate security schemes fails request when one is missing

Consider this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - xApiKey: []
  - apiKey: []
paths:
  /test:
    get:
      responses:
        '200':
          description: OK
components:
  securitySchemes:
    xApiKey:
      type: apiKey
      in: header
      name: x-api-key
    apiKey:
      type: apiKey
      in: header
      name: Authorization

this error is returned when making a request:

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":401,"detail":"apiKey not found, no `x-api-key` header found in request"}

The sent request had the Authorization header set but not the x-api-key header.

but the security:

security:
  - xApiKey: []
  - apiKey: []

defines either xApiKey OR apiKey can be sent.

And AND relationship is defined like so:

security:
  - xApiKey: []
    apiKey: []

Path with Fragment is not handled as expected

Consider this example spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /auth#basicAuth:
    post:
      operationId: basicAuth
      security:
        - basicAuth: []
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schemas:
              type: object
        required: true
      responses:
        "200":
          description: OK
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

wiretap will return the below error when sending a request to /auth

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":404,"detail":"Error: POST Path '/auth' not found, Reason: The POST request contains a path of '/auth' however that path, or the POST method for that path does not exist in the specification"}

Using a fragment in the OpenAPI spec is a pretty common way of reusing a path multiple times ie /auth#instance1 and /auth#instance2 so for the same path & method combination a different schema can be provided instead of needing to use oneOf for example on the request/response bodies.

Log improvement for faster debugging

Given Wiretap as a proxy , Given that there is HTTP rewritting it would be nice to have better logging on the rewrite applied

here i got in wiretap logs this

level=info msg="[wiretap] request /trades: completed (307)" fileName=handle_request.go goroutine=686 package=daemon

would be nice to have received /trades , redirecting to http://ggg:zzz/agivenconfigurepath/toto/trades in the logs

could be also something to put in the UI either

here it s even not clear who reply the 307
looking on the ui , it propose a location https://localhost:8443/trades but looks not clear where does it comes from

Add support for HAR files

Allow wiretap to import HAR files and show the replay in the monitor UI, complete with compliance check on OpenAPI spec. I should be able to run this as a headless command and have the tool spit out a compliance report to stout or a file.

unexpected validate error when dealing with exploded query params

Consider this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /anything/queryParams/form/camelObj:
    get:
      x-speakeasy-test: true
      operationId: formQueryParamsCamelObject
      tags:
        - parameters
      parameters:
        - name: obj_param_exploded
          in: query
          explode: true
          schema:
            type: object
            properties:
              search_term:
                type: string
                example: foo
              item_count:
                type: string
                example: "10"
          required: true
        - name: obj_param
          in: query
          explode: false
          schema:
            type: object
            properties:
              encoded_term:
                type: string
                example: bar
              encoded_count:
                type: string
                example: "11"
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                title: res
                type: object
                properties:
                  url:
                    type: string
                    example: http://localhost:35123/anything/queryParams/form/camelObj?item_count=10&obj_param=encoded_count%2C11%2Cencoded_term%2Cbar&search_term=foo
                    x-speakeasy-test-internal-directives:
                      - sortQueryParameters: {}
                  args:
                    type: object
                    properties:
                      search_term:
                        type: string
                        example: "foo"
                      item_count:
                        type: string
                        example: "10"
                    required:
                      - search_term
                      - item_count
                required:
                  - url
                  - args
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

And a url to call it like http://localhost:35123/anything/queryParams/form/camelObj?item_count=10&obj_param=encoded_count%2C11%2Cencoded_term%2Cbar&search_term=foo

This request fails with the below error from wiretap:

{
  "type": "https://pb33f.io/wiretap/errors#validation_failed_and_spec_insufficient_error",
  "title": "Invalid request, specification is insufficient (500)",
  "status": 500,
  "detail": "The request failed validation, and the specification does not contain a '422' or '400' response for this operation. Check payload for validation errors.",
  "payload": [
    {
      "message": "Query array parameter 'obj_param_exploded' failed to validate",
      "reason": "The query parameter (which is an array) 'obj_param_exploded' is defined as an object, however it failed to pass a schema validation",
      "validationType": "parameter",
      "validationSubType": "query",
      "specLine": 1066,
      "specColumn": 13,
      "howToFix": "Ensure that the object being submitted, matches the schema correctly",
      "validationErrors": [
        {
          "reason": "expected string, but got number",
          "location": "/properties/item_count/type"
        }
      ]
    }
  ]
}

This should be a valid request and I wouldn't expect it to fail, especially as the validation error doesn't really seem to be calling out anything valid

Line numbers when there is a repetition in data in json is not correct

Line Number JSON Path Issue Description
150 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/BookingDateTime/format '2024-01-15T18:45:14' is not valid 'date-time'
155 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/ValueDateTime/format '2024-01-15T18:45:14' is not valid 'date-time'
49 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/TransactionDateTime/format '2024-01-15T18:45:14' is not valid 'date-time'
72 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/TransactionType/enum value must be one of "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx"
49 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/TransactionDateTime/format '2024-01-11T15:39:37' is not valid 'date-time'
72 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/TransactionType/enum value must be one of "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx", "xxxxxxxx"
155 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/ValueDateTime/format '2024-01-11T15:39:37' is not valid 'date-time'
150 /xxxx/xxxx/xxxxx/xxxxxx/items/properties/BookingDateTime/format '2024-01-11T15:39:37' is not valid 'date-time'

Issue description

The issue is the line numbers getting printed are incorrect in wiretap UI if the data schema repeats internally representing multiple data set for example transactions

If possible require a immediate fix on the same. Thanks in advance!!

Panic encountered making request

This spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
paths:
  /anything/queryParams/deepObject/map:
    get:
      operationId: deepObjectQueryParamsMap
      parameters:
        - name: mapParam
          in: query
          style: deepObject
          schema:
            type: object
            additionalProperties:
              type: string
            example: { "test": "value", "test2": "value2" }
          required: true
        - name: mapArrParam
          in: query
          style: deepObject
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                type: string
            example: { "test": ["test", "test2"], "test2": ["test3", "test4"] }
      responses:
        "200":
          description: OK

Seems to cause the below panic:

2024/01/14 13:03:24 http: panic serving 127.0.0.1:40818: runtime error: invalid memory address or nil pointer dereference
goroutine 109 [running]:
net/http.(*conn).serve.func1()
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:1868 +0xb9
panic({0xce4100?, 0x1dbe3b0?})
        /opt/hostedtoolcache/go/1.21.5/x64/src/runtime/panic.go:920 +0x270
github.com/pb33f/wiretap/mock.(*ResponseMockEngine).ValidateSecurity(0x1?, 0xc0000d8500?, 0xc000054280?)
        /home/runner/work/wiretap/wiretap/mock/mock_engine.go:48 +0x24
github.com/pb33f/wiretap/mock.(*ResponseMockEngine).runWorkflow(0xc000400390, 0xc0000d8500)
        /home/runner/work/wiretap/wiretap/mock/mock_engine.go:226 +0x73
github.com/pb33f/wiretap/mock.(*ResponseMockEngine).GenerateResponse(...)
        /home/runner/work/wiretap/wiretap/mock/mock_engine.go:43
github.com/pb33f/wiretap/daemon.(*WiretapService).handleMockRequest(0xc0000caa90, 0xc0000344e0, 0xc000196600, 0xc0000d8b00)
        /home/runner/work/wiretap/wiretap/daemon/handle_mock.go:31 +0xb3
github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest(0xc0000caa90, 0xc0000344e0)
        /home/runner/work/wiretap/wiretap/daemon/handle_request.go:172 +0x12ba
github.com/pb33f/wiretap/daemon.(*WiretapService).HandleHttpRequest(...)
        /home/runner/work/wiretap/wiretap/daemon/wiretap_service.go:99
github.com/pb33f/wiretap/cmd.handleHttpTraffic.func1.1({0x166f830?, 0xc0000c4230}, 0xc0000d8500)
        /home/runner/work/wiretap/wiretap/cmd/handle_http_traffic.go:27 +0xd5
net/http.HandlerFunc.ServeHTTP(0xc000101400?, {0x166f830?, 0xc0000c4230?}, 0xc000391a38?)
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:2136 +0x29
net/http.(*ServeMux).ServeHTTP(0xc0000521f0?, {0x166f830, 0xc0000c4230}, 0xc0000d8500)
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:2514 +0x142
github.com/pb33f/wiretap/cmd.handleHttpTraffic.func1.CompressHandler.CompressHandlerLevel.func3({0x16704d0, 0xc0004460e0}, 0xc0000d8500)
        /home/runner/go/pkg/mod/github.com/gorilla/[email protected]/compress.go:148 +0x69f
net/http.HandlerFunc.ServeHTTP(0x1e0c340?, {0x16704d0?, 0xc0004460e0?}, 0xc000391b50?)
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:2136 +0x29
net/http.serverHandler.ServeHTTP({0xc000400f60?}, {0x16704d0?, 0xc0004460e0?}, 0x6?)
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:2938 +0x8e
net/http.(*conn).serve(0xc0000f23f0, {0x1672020, 0xc0003803f0})
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:2009 +0x5f4
created by net/http.(*Server).Serve in goroutine 86
        /opt/hostedtoolcache/go/1.21.5/x64/src/net/http/server.go:3086 +0x5cb

when a request is made

Rewriting paths leads to: unsupported protocol scheme \"\""

Something seems to have broken in v0.1.0 release.

Routing requests to an RT server running on localhost:

$ podman run --rm --publish 9090:9090 --publish 9091:9091 --publish 9092:9092 --volume $PWD:/work:rw pb33f/wiretap:v0.1.0 --spec my_spec.yaml --url https://host.containers.internal

...

 INFO  wiretap is proxying all traffic to 'https://host.containers.internal'

 INFO  [wiretap] Re-writing path 'https://host.containers.internal/REST/2.0/rt' to '/REST/2.0/rt'

The info about the rewrite appears only after making a request, doesn't seem to matter which one.

And the response is:

{
	"type": "https://pb33f.io/wiretap/error",
	"title": "Unable to call API",
	"status": 500,
	"detail": "Get \"/REST/2.0/rt\": unsupported protocol scheme \"\"",
	"payload": null
}

Same thing works fine in v0.0.49 and doesn't inform of any rewrites.

Bug : Glitch on % display on error level

in some circunstances the computation of the compliance rate kind of over flow

image

check the image ,
compliance should be rounded to unit , like here 84% would be enough

Monitor Request Body not cleared when switching to request which does not have Body

When clicking around in the monitor to inspect requests, the Body option is correctly greyed out when switching to the DELETE request. However, if the previous view was the Body option of a request which had a Body, the bottom view does not reset/clear and instead shows the error JSON.parse: unexpected character at line 1 column 1 of the JSON data (what is shown in the screenshot).

Expected behavior is something to the effect of "Field does not exist for request" instead of showing a parse error. I'm not sure if the view should reset to the first valid option (like Query), since users will probably expect the same option to be selected when switching back to a request which does have a Body.

This occurs in wiretap 0.1.1.

image

Fail response when request and/or response don't pass validation

Add a new configuration-driven possibility to fail proxied request-response when the request and/or response don't pass OpenAPI validation.
For example, add a boolean configuration parameter that will trigger to return an unsuccessful status code from wiretap when a request and/or response don't pass OpenAPI validation. Maybe, the second configuration parameter with error status code.
Goal - use wiretap in the pipeline with any API mock and get an error when mocked request and/or response don't pass OpenAPI validation

Feature Request : send back error details

When setting WireTap as a validation proxy , it would be nice to return as well the error details to the client and not only the 502

could be returning HTTP RFC problem format or whaterver

meanning instead of empty payload returning something like to have better understanding as well from client point of view.

it should include response violation as well as type and how to fix

(i know all those are in the UI but having them as well in the return would help the debugging lifecycle.

Percentage computation

image

given the fact that for a given request there is validation of the inbound + validation of the outbound i cannot get how we get to 75%

could be 0 % compliance , if we consider the round trip , could be 50 % if we consider that it is 2 check one succeed , and one fail but not 75%

notice that if i repeat it keeps it to 75%

feature request: support speakeasy example expansion directive

consider the below schemas:

  map:
    type: object
    additionalProperties:
      $ref: "#/components/schemas/simpleObject"
    example: { "key": "...", "key2": "..." }
  arr:
    type: array
    items:
      $ref: "#/components/schemas/simpleObject"
    example: ["...", "..."]

These use an example expansion directive of "..." (btw this is a special directive value speakeasy uses to direct our generator how to generate examples, we would be open to discussing alternative directives that both speakeasy and wiretap could use if you didn't want to support this one) which tells our generator to expand the example with an example value generated from the child schema, ie the additionalProperties schema or items schema.

In the examples above we are saying we want the map example to contain two keys (key and key2) where the values are using the example generated from the simpleObject component. This provides a shorthand to avoid having to define the whole json object in the example at this level and instead take advantage of the fact the examples have already been defined in the component.

The array version is just saying I want two values of the example defined in the simpleObject component.

Would love if the mocking from wiretap also supported this (or something similar that we can converge on) as it does reduce the burden for the example implementor.

Wiretap fails to validate correct request

While running mock server with command yarn wiretap -s ./swagger.yml -u http://localhost:3000 -x I have incosistent behaviour of path parameter validator.

I have this parameter defined in OpenApi yaml file:

PathTrackId:
      in: path
      name: trackId
      required: true
      schema:
        type: string
        pattern: ^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
        example: 123e4567-e89b-12d3-a456-426614174000
        format: uuid
        minLength: 32
        maxLength: 36

and it is used in a path like this:

/contents/tracks/{trackId}:
    get:
      tags:
        - Contents
      summary: Get tracks based on {trackId}, from contents
      operationId: contentsTracksTrackIdGet
      parameters:
        - $ref: '#/components/parameters/PathTrackId'

My frontend app sends request with some example ID:

GET http://localhost:4200/api/contents/tracks/123e4567-e89b-12d3-a456-426614174010

where http://localhost:4200/api/ is a proxy for default wiretap http://localhost:9000.

Issue

Wiretap returns

{
    "type": "https://pb33f.io/wiretap/error",
    "title": "unable to serve mocked response",
    "status": 500,
    "detail": "Error: Path parameter 'trackId' failed to validate, Reason: The path parameter 'trackId' is defined as an string, however it failed to pass a schema validation, Validation Errors: [Reason: 'tracks' is not valid 'uuid', Location: /format Reason: length must be \u003e= 32, but got 6, Location: /minLength Reason: does not match pattern '^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$', Location: /pattern], Line: 47, Column: 9"
}

when request is send for the first time but its ok if the same request is send once again.

First request - 500:

GET /api/contents/tracks/123e4567-e89b-12d3-a456-426614174010 HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Authorization: test_token
Connection: keep-alive
DNT: 1
Host: localhost:4200
Referer: http://localhost:4200/app/game/track/123e4567-e89b-12d3-a456-426614174010
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
sec-ch-ua: "Not-A.Brand";v="99", "Chromium";v="124"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

Second request - OK:

GET /api/contents/tracks/123e4567-e89b-12d3-a456-426614174010 HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Authorization: test_token
Connection: keep-alive
DNT: 1
Host: localhost:4200
Referer: http://localhost:4200/app/game/track/123e4567-e89b-12d3-a456-426614174010
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
sec-ch-ua: "Not-A.Brand";v="99", "Chromium";v="124"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

Feature : Restrictive / Lock down API specification

do you think it would be possible to kind of lock down the spec
Kind of setting aditionnal Properties to false with a flag in wiretab command line

meanning given the spec
"schema" : {
"type" : "object",
"properties" : {
"message" : {"type" : "string"},
"who" : {"type" : "string"}
}

if i send "message" : "Hello" , "who":"bob" , "offender":12 , Flag Off = it says green , FlagOn = it says red
the topic beeing to spot that the server returns undocumented fields ...

Proxying different urls

Is there a way to proxy different urls to different backends?

I tried setting up multiple instances of wiretap in a docker compose but the monitoring webpage displays the same content

Operation that overrides global security with no auth fails with 401 when no auth sent

When sending a request to an operation that defines no security in a document with global security wiretap returns a 401 if a request to that operation doesn't include an auth header.

Here is an example spec that causes the issue:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /anything/no-auth:
    get:
      operationId: noAuth
      security:
        - {}
      responses:
        "200":
          description: O
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization

Here is the response I get back from wiretap:

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":401,"detail":"apiKey not found, no `Authorization` header found in request"}

Panic encountered during jsonschema validation

This spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /anything/queryParams/deepObject/obj:
    get:
      operationId: deepObjectQueryParamsObject
      parameters:
        - name: objParam
          in: query
          style: deepObject
          schema:
            $ref: "components.yaml#/components/schemas/simpleObject"
          required: true
        - name: objArrParam
          in: query
          style: deepObject
          schema:
            type: object
            properties:
              arr:
                type: array
                items:
                  type: string
                  examples:
                    - test
                    - test2
      responses:
        "200":
          description: OK
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

when a request is sent causes the below panic:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x68 pc=0xade1e6]

goroutine 264 [running]:
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validateValue.func1()
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:178 +0xa9
panic({0xce4100?, 0x1dbe3b0?})
        /opt/hostedtoolcache/go/1.21.5/x64/src/runtime/panic.go:914 +0x21f
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validate(0x0, {0x0, 0x0, 0x0}, 0x0, {0x0, 0x0}, {0xcd4cc0, 0xc00034d350?}, {0x0, ...})
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:253 +0x526
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validateValue(0x0, {0xcd4cc0?, 0xc00034d350?}, {0x0, 0x0})
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:182 +0xbf
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).Validate(...)
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:168
github.com/pb33f/libopenapi-validator/parameters.ValidateParameterSchema(0xc0002eaf00, {0xcd4cc0, 0xc00034d350?}, {0xc00095008c, 0x13}, {0xe6ec8a, 0xf}, {0xe718d6, 0x13}, {0xc0005fae78, ...}, ...)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/parameters/validate_parameter.go:84 +0x4c5
github.com/pb33f/libopenapi-validator/parameters.(*paramValidator).ValidateQueryParams(0xc0005e0a40, 0xc00094e000)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/parameters/query_parameters.go:188 +0x1659
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest.func1.2(0x0?, 0x0?, 0x0?)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:225 +0x27
created by github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest.func1 in goroutine 258
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:233 +0x3b2

invalid memory address or nil pointer dereference

when playing with the tool i got this error after about 500 requests.
Unfortunately the tools does not tell me which request caused the issue.

INFO  wiretap is proxying all traffic to 'https://xxxxxxxxxxx'

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x68 pc=0xa4ddca]

goroutine 11173 [running]:
github.com/pb33f/libopenapi-validator/requests.(*requestBodyValidator).ValidateRequestBody(0xc000da9d00, 0xc0004a7b00)
        /go/pkg/mod/github.com/pb33f/[email protected]/requests/validate_body.go:32 +0x16a
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest.func2(0xc000f986c0?, 0x0?)
        /go/pkg/mod/github.com/pb33f/[email protected]/validator.go:247 +0x30
created by github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest in goroutine 11186
        /go/pkg/mod/github.com/pb33f/[email protected]/validator.go:267 +0x346

Null Pointer exception if configuration not correct

given a wrong config files

variables:
someVar: localhost:8000
redirectURL: http://localhost:8000
contract: ./component-descriptor.yml

paths:
/*:
target: ${http://localhost:8000}/ranch <= yes i know it is wrong 😅

call then crash with not clear details cf stack below

config miss configuration could be spot at loading time ; or if not possible just catch the null value

::1 - - [06/Oct/2023:11:03:53 +0200] "GET /ranch HTTP/1.1" 200 0 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47"
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x8 pc=0x5d6b94]

goroutine 573 [running]:
net/url.(*URL).String(0x0)
/opt/hostedtoolcache/go/1.21.0/x64/src/net/url/url.go:810 +0x34
github.com/pb33f/wiretap/daemon.BuildHttpTransaction({0xc00008ec00?, 0xc00008ee00?, 0xc000806ff0?, 0xc000070ea0?}) /home/runner/work/wiretap/wiretap/daemon/build_request.go:140 +0x82f
github.com/pb33f/wiretap/daemon.(*WiretapService).validateRequest(0xc0005f7540, 0xc0009a00c0, 0xc000b82020?)
/home/runner/work/wiretap/wiretap/daemon/validate.go:74 +0x278
created by github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest in goroutine 633
/home/runner/work/wiretap/wiretap/daemon/handle_request.go:157 +0xa65

encountered panic trying to run API in mock mode

The panic was:

::1 - - [21/Nov/2023:14:39:49 +0000] "GET /ranch HTTP/1.1" 200 0 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0x9a42f7]

goroutine 4338 [running]:
github.com/pb33f/libopenapi/datamodel/high/base.(*SchemaProxy).Schema(0x0)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/datamodel/high/base/schema_proxy.go:77 +0x17
github.com/pb33f/libopenapi-validator/paths.comparePaths({0xc0016364c0?, 0x4, 0x1?}, {0xc001636380?, 0x4, 0x4}, {0xc0003ec138, 0x1, 0x4107c5?}, {0xc0024007a0, ...})
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/paths/paths.go:267 +0x37f
github.com/pb33f/libopenapi-validator/paths.FindPath(0xc002380a00, 0xc002292000)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/paths/paths.go:66 +0x5fb
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest(0xc000be4400, 0xc002380a00)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:164 +0x4b
github.com/pb33f/wiretap/daemon.(*WiretapService).validateRequest(0xc001dc2d20, 0xc00174e300, 0xc0023688d0?)
        /home/runner/work/wiretap/wiretap/daemon/validate.go:52 +0x62
created by github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest in goroutine 4336
        /home/runner/work/wiretap/wiretap/daemon/handle_request.go:160 +0xa6e

The command used:

wiretap -s ./tests/specs/test_primary.yaml -x -b ./tests/specs -p 35123

I can send you the spec we were using in DM on discord if you need it.

Feature Request : Simple path URL / Base Path rewrite

Given an API specification that defines /ranch

given an backend running on mymachine with a basepath , so responding on

http://mymachine/aBasePath/ThatcanbeseveralsSegments/ranch

it would be nice that
given the wiretab command line :
wiretap -s .\mySpec.yml -u http://mymachine/aBasePath/ThatcanbeseveralsSegments/

that it runs auto magically , ie that when a call is comming on http://wiretapProxy/ranch it goes directed to http://mymachine/aBasePath/ThatcanbeseveralsSegments/ranch without doing more settings

Unclear error is returned from operation about Media type not supported

For this example spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
paths:
  /auth:
    post:
      operationId: basicAuth
      security:
        - basicAuth: []
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schemas:
              type: object
        required: true
      responses:
        "200":
          description: OK
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

I get the following error:

{"type":"https://pb33f.io/wiretap/errors#build_mock_error","title":"Media type not supported (415)","status":415,"detail":"The media type requested 'application/json' is not supported by this operation"}

It is not clear what this is referring to or why it is failing.

The request as far as I can tell is valid.

Looking into the monitor it does say this about the request body:

Content Type: application/json
[unable to parse JSON body]

the request body being sent is:

{"basicAuth":{"password":"testPass","username":"testUser"}}

with the request content type set to application/json

Install not working using a Windows environment

PS D:\tmp\developer-portal> npm i -g @pb33f/openapi-changes
npm ERR! code 1
npm ERR! path C:\Users\XXX\AppData\Roaming\npm\node_modules@pb33f\openapi-changes
npm ERR! command failed
npm ERR! command C:\Windows\system32\cmd.exe /d /s /c node ./npm-install/postinstall.js
npm ERR! fetching from URL https://github.com/pb33f/openapi-changes/releases/download/v0.0.53/openapi-changes_0.0.53_windows_x86_64.zip
npm ERR! Error: ENOENT: no such file or directory, chmod './bin/openapi-changes'
npm ERR! at Module.chmodSync (node:fs:1916:3)
npm ERR! at install (file:///C:/Users/XXX/AppData/Roaming/npm/node_modules/@pb33f/openapi-changes/npm-install/postinstall.js:54:14)
npm ERR! at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
npm ERR! errno: -4058,
npm ERR! syscall: 'chmod',
npm ERR! code: 'ENOENT',
npm ERR! path: './bin/openapi-changes'
npm ERR! }

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\XXX\AppData\Local\npm-cache_logs\2024-01-25T11_16_47_112Z-debug-0.log

wiretap service crashes when trying to send response

Description

'"{    \"Data\": {        \"CryptId\": \"****************\",        \"Pyro_transactions\": [        ]    },    \"Links\": {        \"Self\": \"/crypt-information/********/crypt/<uuid>/Pyro_transactions\"    },    \"Meta\": {        \"TotalPages\": 1    }}"'

error:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x68 pc=0x1012b45cc]

goroutine 3914 [running]:
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validateValue.func1()
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:178 +0x120
panic({0x101cc5aa0?, 0x1025a6b70?})
        /opt/hostedtoolcache/go/1.22.1/x64/src/runtime/panic.go:770 +0x124
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validate(0x0, {0x0, 0x0, 0x0}, 0x0, {0x0, 0x0}, {0x101cb60c0, 0x1400055fad0}, {0x0, ...})
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:253 +0x43c
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).validateValue(0x0, {0x101cb60c0?, 0x1400055fad0?}, {0x0, 0x0})
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:182 +0x94
github.com/santhosh-tekuri/jsonschema/v5.(*Schema).Validate(...)
        /home/runner/go/pkg/mod/github.com/santhosh-tekuri/jsonschema/[email protected]/schema.go:168
github.com/pb33f/libopenapi-validator/responses.ValidateResponseSchema(0x140006d4b40, 0x140005263f0, 0x14000554508, {0x14000f3e000, 0xfdc5, 0x12000}, {0x14000ff6000, 0x96c6, 0x3?})
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/responses/validate_response.go:132 +0x99c
github.com/pb33f/libopenapi-validator/responses.(*responseBodyValidator).checkResponseSchema(0x14000955b00, 0x140006d4b40, 0x140005263f0, {0x140002b00c0?, 0x14000c42190?}, 0x1400063ab40)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/responses/validate_body.go:140 +0x1fc
github.com/pb33f/libopenapi-validator/responses.(*responseBodyValidator).ValidateResponseBody(0x14000955b00, 0x140006d4b40, 0x140005263f0)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/responses/validate_body.go:54 +0x348
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpResponse(0x140004ec380, 0x140006d4b40, 0x140005263f0)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:116 +0xbc
github.com/pb33f/wiretap/daemon.(*WiretapService).ValidateResponse(0x140009f3040, 0x140004e40c0, 0x140005263f0)
        /home/runner/work/wiretap/wiretap/daemon/validate.go:19 +0x6c
created by github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest in goroutine 3612
        /home/runner/work/wiretap/wiretap/daemon/handle_request.go:196 +0xa54

Expected example data not returned

Related to this (or maybe the same bug not fixed): #84

This spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /anything/queryParams/form/array:
    get:
      x-speakeasy-test: true
      operationId: formQueryParamsArray
      tags:
        - parameters
      parameters:
        - name: arrParam
          in: query
          explode: false
          schema:
            type: array
            items:
              type: string
              examples:
                - test
                - test2
        - name: arrParamExploded
          in: query
          explode: true
          schema:
            type: array
            items:
              type: integer
              examples:
                - 1
                - 2
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                title: res
                type: object
                properties:
                  url:
                    type: string
                    example: http://localhost:35123/anything/queryParams/form/array?arrParam=test%2Ctest2&arrParamExploded=1&arrParamExploded=2
                  args:
                    type: object
                    properties:
                      arrParam:
                        type: string
                        example: "test,test2"
                      arrParamExploded:
                        type: array
                        items:
                          type: string
                          examples:
                            - "1"
                            - "2"
                    required:
                      - arrParam
                      - arrParamExploded
                required:
                  - url
                  - args
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

returns ["gEP"] or similar for the arrParamExploded property in the response object where I would expect ["1", "2"] based on the provided examples

Testing validations with a bad example

Hi there!

Please let me know if this is the wrong way of asking this quest as it's more of a support question than an issue with the project (been using it for 30 min and loving it already)

I'm trying to check how the validations work, so i have an api with an already valid example. I make a request to this endpoint and it works great (all using the mock mode).
Now i go and drop fields from the example that are marked as required in the api spec, at this point i'm expecting that the next request will show up as an error.

The reality is that is that it comes back ok. I've also tested by messing with the types (putting a string in a field that's defined as a bool). This also works ok.

I've been able to trigger the validations by making a bad request with a non valid body and i can see that it works as expected.

Is this the correct behaviour? i was hoping that if a server returns a "bad" response it would show up as a violation, is this because i'm running in mock mode?

wiretap fails to authenticate a operation that uses the same route but unique via a fragment

This is related to this new change I believe: #78

For this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
  - apiKeyAuthNew: []
  - oauth2: []
  - {}
paths:
  /auth#basicAuth:
    post:
      operationId: basicAuthNew
      security:
        - basicAuth: []
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/authServiceRequestBody"
        required: true
      responses:
        "200":
          description: OK
        "401":
          description: Unsuccessful authentication.
  /auth#apiKeyAuthGlobal:
    post:
      operationId: apiKeyAuthGlobalNew
      servers:
        - url: http://localhost:35456
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/authServiceRequestBody"
        required: true
      responses:
        "200":
          description: OK
        "401":
          description: Unsuccessful authentication.
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      x-speakeasy-example: YOUR_USERNAME;YOUR_PASSWORD
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.
      x-speakeasy-example: Token YOUR_API_KEY
    bearerAuth:
      type: http
      scheme: bearer
      x-speakeasy-example: YOUR_JWT
    apiKeyAuthNew:
      type: apiKey
      in: header
      name: x-api-key
      x-speakeasy-example: Token <YOUR_API_KEY>
    oauth2:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: http://localhost:35123/oauth2/authorize
          scopes: {}
      x-speakeasy-example: Bearer YOUR_OAUTH2_TOKEN
    openIdConnect:
      type: openIdConnect
      openIdConnectUrl: http://localhost:35123/.well-known/openid-configuration
      x-speakeasy-example: Bearer YOUR_OPENID_TOKEN
  schemas:
    authServiceRequestBody:
      type: object
      properties:
        headerAuth:
          type: array
          items:
            type: object
            properties:
              headerName:
                type: string
              expectedValue:
                type: string
            required:
              - headerName
              - expectedValue
        basicAuth:
          type: object
          properties:
            username:
              type: string
            password:
              type: string
          required:
            - username
            - password

Trying to do a request against the operation apiKeyAuthGlobalNew fails with the below error:

{"type":"https://pb33f.io/wiretap/error","title":"unable to serve mocked response","status":401,"detail":"basic authentication failed: bearer token not found, no `Authorization` header found in request"}

It looks to not be matching the right route and expecting the basic auth of the basicAuthNew operation

Wiretap fails to retain the requests which are still loading

Issue description

Whenever a synchronous api is being executed the wiretap displays the api in executing status with a loader status, but in between if the user refreshes the wiretap UI, the api request which is being executed vanishes from the UI. Could not post a screenshot of the same as the details are confidential in the UI

Reset State button should reset numbers

As of today the reset state button reset the "call panel" on the left
but it does not reset the statistics about number of call and success

it should (my opinion) or have a way to do it via a tick ( not sure as will make ui with plenty of tick in few years )

Invalid static content directory causes panic.

The static dir needs checking before trying to be read.

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x28 pc=0x10129b7d0]

goroutine 439 [running]:
github.com/pb33f/wiretap/daemon.MonitorStatic.func1.1({0x16f0fb720, 0xc}, {0x0?, 0x0?}, {0x140006a6c30?, 0x140006a6c00?})
	/home/runner/work/wiretap/wiretap/daemon/monitor_static.go:30 +0x30

no requests logged

i followed the examples and did

 $ curl -o giftshop-openapi.yaml https://api.pb33f.io/wiretap/giftshop-openapi.yaml
 $ docker run -p 9090:9090 -p 9091:9091 -p 9092:9092 --rm -v $PWD:/work:rw  pb33f/wiretap -u https://api.pb33f.io -s  gi
ftshop-openapi.yaml

@@@@@@@   @@@@@@@   @@@@@@   @@@@@@   @@@@@@@@
@@@@@@@@  @@@@@@@@  @@@@@@@  @@@@@@@  @@@@@@@@
@@!  @@@  @@!  @@@      @@@      @@@  @@!
!@!  @!@  !@   @!@      @!@      @!@  !@!
@!@@!@!   @!@!@!@   @!@!!@   @!@!!@   @!!!:!
!!@!!!    !!!@!!!!  !!@!@!   !!@!@!   !!!!!:
!!:       !!:  !!!      !!:      !!:  !!:
:!:       :!:  !:!      :!:      :!:  :!:
 ::        :: ::::  :: ::::  :: ::::   ::
 :        :: : ::    : : :    : : :    :

wiretap version: latest | compiled: Fri, 15 Dec 2023 09:30:40 UTC
Designed and built by Princess Beef Heavy Industries: https://pb33f.io/wiretap

 INFO  No wiretap configuration located. Using defaults
 INFO  OpenAPI Specification: 'giftshop-openapi.yaml' parsed and read
 INFO  API Gateway UI booting on port 9090...
 INFO  Monitor UI booting on port 9091...

┌─ wiretap is online! ─────────────────────────────────────┐
|                                                          |
|   ┌─ API Gateway ─────────┐ ┌─ Monitor UI ──────────┐    |
|   | http://localhost:9090 | | http://localhost:9091 |    |
|   └───────────────────────┘ └───────────────────────┘    |
|                                                          |
└──────────────────────────────────────────────────────────┘

 INFO  wiretap is proxying all traffic to 'https://api.pb33f.io'

Then i do

$ curl "http://localhost:9090/wiretap/giftshop/products"
[{"id":"d91a1cc2-ec4e-468a-97dc-7a0325017f1b","shortCode":"pb0001","name":"pb33f t-shirt","description":"A t-shirt with the pb33f logo on the front","price":19.99,"category":"clothes","image":"https://pb33f.io/images/t-shirt.png"},{"id":"3f6713b8-0e05-4724-9553-5f571248a47a","shortCode":"pb0002","name":"pb33f baseball cap","description":"A baseball cap with the pb33f logo on the front","price":29.99,"category":"clothes","image":"https://pb33f.io/images/cap.png"},{"id":"1d4517a3-c099-4a39-a057-b44a66ba6940","shortCode":"pb0003","name":"pb33f coffee cup","description":"A black coffee cup with the pb33f logo on the front and the word 'hack code' on the back","price":15.75,"category":"cups","image":"https://pb33f.io/images/cup.png"},{"id":"457acf29-a43a-413b-908e-017ab048ad19","shortCode":"pb0004","name":"pb33f hoodie","description":"A nice black hoodie with the pb33f logo on the back and 'hack code' on the front","price":39.99,"category":"clothes","image":"https://pb33f.io/images/hoodie.png"},{"id":"91a99caa-8a8b-4176-8f8a-03bb86d1160e","shortCode":"pb0005","name":"pb33f thermos","description":"A black thermos mug with the words 'hack code' written on the front","price":25.99,"category":"cups","image":"https://pb33f.io/images/thermos.png"},{"id":"1c9b473b-b4f0-4b00-8378-f2f99052feb1","shortCode":"pb0006","name":"pb33f shot glass","description":"A solid black shot glass with the words 'hack code' written on the front","price":5.99,"category":"cups","image":"https://pb33f.io/images/shot-glass.png"}]

when i then go to http://localhost:9091 it shows 100% Complinance, 0 Requests and 0 Results

  • why is the request not counted?
  • Can i enable more logging on the console?

Mock response didn't return the expected example data

This may be a bad assumption on my part but I would expect (or want) the responses returned by wiretap in mock mode to use the provided examples if in the spec and only provide truly mocked responses (ie generating responses based on the schema) if there were no provided examples.

If this isn't the intended behavior or my assumption was wrong would be good if it could be configured to react this way?

handle schemas with different format types when mocking/returning responses

I suspect this is likely to be a feature request more than a bug. But consider this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
paths:
  /anything/requestBodies/post/application/json/simple:
    post:
      operationId: requestBodyPostApplicationJsonSimple
      tags:
        - requestBodies
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/simpleObject"
        required: true
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                title: res
                type: object
                properties:
                  json:
                    $ref: "#/components/schemas/simpleObject"
                required:
                  - json
components:
  schemas:
    simpleObject:
      description: "A simple object that uses all our supported primitive types and enums and has optional properties."
      externalDocs:
        description: "A link to the external docs."
        url: "https://docs.speakeasyapi.dev"
      type: object
      properties:
        str:
          type: string
          description: "A string property."
          example: "test"
        bool:
          type: boolean
          description: "A boolean property."
          example: true
        int:
          type: integer
          description: "An integer property."
          example: 1
        int32:
          type: integer
          format: int32
          description: "An int32 property."
          example: 1
        num:
          type: number
          description: "A number property."
          example: 1.1
        float32:
          type: number
          format: float
          description: "A float32 property."
          example: 1.1
        enum:
          $ref: "#/components/schemas/enum"
        date:
          type: string
          format: date
          description: "A date property."
          example: "2020-01-01"
        dateTime:
          type: string
          format: date-time
          description: "A date-time property."
          example: "2020-01-01T00:00:00.000001Z"
        any:
          description: "An any property."
          example: "any"
        strOpt:
          type: string
          description: "An optional string property."
          example: "testOptional"
        boolOpt:
          type: boolean
          description: "An optional boolean property."
          example: true
        intOptNull:
          type: integer
          description: "An optional integer property will be null for tests."
        numOptNull:
          type: number
          description: "An optional number property will be null for tests."
        intEnum:
          type: integer
          description: "An integer enum property."
          enum:
            - 1
            - 2
            - 3
          example: 2
          x-speakeasy-enums:
            - First
            - Second
            - Third
        int32Enum:
          type: integer
          format: int32
          description: "An int32 enum property."
          enum:
            - 55
            - 69
            - 181
          example: 55
        bigint:
          type: integer
          format: bigint
          example: 8821239038968084
        bigintStr:
          type: string
          format: bigint
          example: "9223372036854775808"
        decimal:
          type: number
          format: decimal
          example: 3.141592653589793
        decimalStr:
          type: string
          format: decimal
          example: "3.14159265358979344719667586"
      required:
        - str
        - bool
        - int
        - int32
        - num
        - float32
        - enum
        - date
        - dateTime
        - any
        - intEnum
        - int32Enum
    enum:
      type: string
      description: "A string based enum"
      enum:
        - "one"
        - "two"
        - "three"
        - "four_and_more"
      example: "one"
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

The response has properties like:

bigint:
  type: integer
  format: bigint
  example: 8821239038968084
bigintStr:
  type: string
  format: bigint
  example: "9223372036854775808"
decimal:
  type: number
  format: decimal
  example: 3.141592653589793
decimalStr:
  type: string
  format: decimal
  example: "3.14159265358979344719667586"

ie integers and numbers that are using advances formats. decimal is currently a recognized format in the official OpenAPI format registry and we are trying to get bigint added as well.

currently wiretap just returns nothing for these properties:

{
  "json": {
    "any": "any",
    "bool": true,
    "date": "2020-01-01",
    "dateTime": "2020-01-01T00:00:00.000001Z",
    "enum": "one",
    "float32": 1.1,
    "int": 1,
    "int32": 1,
    "int32Enum": 55,
    "intEnum": 2,
    "num": 1.1,
    "str": "test"
  }
}

where we need it to return the defined examples at least

encountered panic after 4 requests are validated in wiretap

The Panic was:

`panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x68 pc=0xa4db8a]

goroutine 3406 [running]:github.com/pb33f/libopenapi-validator/requests.(requestBodyValidator).ValidateRequestBody(0xc00878e900, 0xc003411700)
/go/pkg/mod/github.com/pb33f/[email protected]/requests/validate_body.go:32 +0x16a
github.com/pb33f/libopenapi-validator.(validator).ValidateHttpRequest.func2(0x0?, 0x0?)
/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:247 +0x30
created by github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest in goroutine 3422
/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:267 +0x332`

command used to run wiretap:
wiretap -u https://my-api-server-url.com/ --ws-host localhost -s smoke.json

Requests checking request method type of previous request

(originally posted in Discord under the associated thread https://discord.com/channels/923258363540815912/1126857048273981551/1208217864054636626)

Originally reported with wiretap 0.1.1

Requests to an endpoint fails if the previous request was to an endpoint that does not have the same request type (GET, POST, etc). This behavior has been encountered using both Python and curl.

The error I'm getting is:

POST operation request content type 'POST' does not exist.
The path was found, but there was no 'POST' method found in the spec.
How to fix this violation:
Add the missing operation to the contract for the path

Current spec: https://github.com/nichwall/audiobookshelf/blob/collection_routes_openapi_v1/build-docs/swagger-output.json

Testing with the /login endpoint just using curl to POST works on a fresh run. However, after running the Python script the same curl POST to /login fails with a line number of 296 instead of 354 (so the violations references /api/items/{id} in the spec instead of /login).

More details

The Python script makes the following requests (all valid calls from before making the OpenAPI spec):

  • POST to /login (succeeds)
  • GET to /api/libraries (fails with missing GET to line 354, or /login in spec)
  • GET to /api/libraries/{id}/items (succeeds)
  • GET to /api/items/{id} (fails with invalid schema, unrelated to this error)

Sending the curl POST to /login then fails with a missing GET definition, referencing /api/items/{id} in spec.

After adding a dummy get request to the /login endpoint, the get request to /api/libraries immediately afterwards passes validation (but the POST to /login after the script will still fail).

Steps to reproduce

Spec without all request types defined on the previous endpoint hit through wiretap.

Return Error Content if validation fails

current behaviour when there is a validation error is that it returns a 502

the enhancement i propose is that the returned payload contains
a structured error containning this list of failures , as well as the payload

this allow to have an off line diagnotics without the usuage of the (nice) UI

context of usage beeing newman + wiretap in CICD

given the fact that in case of error newman log the payload, it allows to understand that there was an error, and then to diagnose

it may requires a dedicated flag

Panic when using API gateway

Hi there. Wiretap is panicing when I attempt to access the API gateway URL. I am running version 0.0.18 on Linux x86-64 bit.

I invoked the program with:

wiretap --spec specs/specification.yaml  --url https://the-live-domain-in-the-specification.com

Wiretap starts up as expected with:

 INFO  API Gateway UI booting on port 9090...
 INFO  Monitor UI booting on port 9091...
INFO [ranch] Yee-Haw! Starting up the ranch's HTTP server at localhost:9092  fileName=server.go goroutine=66 package=server
INFO [ranch] Hot-Dang! Starting up the ranch's STOMP message broker at localhost:9092/ranch  fileName=server.go goroutine=67 package=server

┌─ wiretap is online! ─────────────────────────────────────┐
|                                                          |
|   ┌─ API Gateway ─────────┐ ┌─ Monitor UI ──────────┐    |
|   | http://localhost:9090 | | http://localhost:9091 |    |
|   └───────────────────────┘ └───────────────────────┘    |
|                                                          |
└──────────────────────────────────────────────────────────┘

Accessing http://localhost:9091/ gives me the below page:

image

However, accessing http://localhost:9090/ results in an error:

This page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE

...and in the terminal:

2023/07/10 12:31:02 http: panic serving [::1]:45744: runtime error: invalid memory address or nil pointer dereference
goroutine 156 [running]:
net/http.(*conn).serve.func1()
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:1854 +0xbf
panic({0xab69e0, 0x17335b0})
        /opt/hostedtoolcache/go/1.20.5/x64/src/runtime/panic.go:890 +0x263
github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest(0xc000098500, 0xc000510540)
        /home/runner/work/wiretap/wiretap/daemon/handle_request.go:102 +0x6d6
github.com/pb33f/wiretap/daemon.(*WiretapService).HandleHttpRequest(...)
        /home/runner/work/wiretap/wiretap/daemon/wiretap_service.go:78
github.com/pb33f/wiretap/cmd.handleHttpTraffic.func1.1({0x12c1cc0?, 0xc0004c4410}, 0xc0005d8000)
        /home/runner/work/wiretap/wiretap/cmd/handle_http_traffic.go:27 +0xe5
net/http.HandlerFunc.ServeHTTP(0xc000600000?, {0x12c1cc0?, 0xc0004c4410?}, 0xc000589950?)
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:2122 +0x2f
net/http.(*ServeMux).ServeHTTP(0xc0005120c0?, {0x12c1cc0, 0xc0004c4410}, 0xc0005d8000)
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:2500 +0x149
github.com/gorilla/handlers.CompressHandlerLevel.func1({0x12c2650, 0xc00014e000}, 0xc0005d8000)
        /home/runner/go/pkg/mod/github.com/gorilla/[email protected]/compress.go:148 +0x9e8
net/http.HandlerFunc.ServeHTTP(0x0?, {0x12c2650?, 0xc00014e000?}, 0x46a56e?)
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:2122 +0x2f
net/http.serverHandler.ServeHTTP({0xc00051e2a0?}, {0x12c2650, 0xc00014e000}, 0xc0005d8000)
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:2936 +0x316
net/http.(*conn).serve(0xc00044a120, {0x12c2bc0, 0xc00051e420})
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:1995 +0x612
created by net/http.(*Server).Serve
        /opt/hostedtoolcache/go/1.20.5/x64/src/net/http/server.go:3089 +0x5ed

feature request: validate request based on examples

would be great if wiretap could validate the request included values that matched the examples in the spec.

Some way to configure wiretap to turn on example validation and ensure that the request contained one of the examples

invalid memory address or nil pointer dereference in validator

tested with wiretap_0.0.50_linux_x86_64

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xb7b641]

goroutine 299 [running]:
github.com/pb33f/libopenapi-validator/responses.(*responseBodyValidator).ValidateResponseBody(0xc00012cc00, 0xc000472000, 0xc000291680)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/responses/validate_body.go:51 +0x421
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpResponse(0xc0002f4500, 0xc000309b80?, 0x0?)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:116 +0xd3
github.com/pb33f/wiretap/daemon.(*WiretapService).validateResponse(0xc00032ab40, 0xc000544840, 0xc00026a138?)
        /home/runner/work/wiretap/wiretap/daemon/validate.go:19 +0x68
created by github.com/pb33f/wiretap/daemon.(*WiretapService).handleHttpRequest in goroutine 418
        /home/runner/work/wiretap/wiretap/daemon/handle_request.go:197 +0xdeb

response is e expected 400 error

panic in libopenapi when encountering json encoded path parameter

consider this spec:

openapi: 3.1.0
info:
  title: Test
  version: 0.1.0
security:
  - apiKeyAuth: []
paths:
  /anything/pathParams/json/{jsonObj}:
    get:
      x-speakeasy-test: true
      operationId: pathParameterJson
      tags:
        - parameters
      parameters:
        - name: jsonObj
          in: path
          required: true
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/simpleObject"
      responses:
        "200":
          content:
            application/json:
              schema:
                title: res
                type: object
                properties:
                  url:
                    type: string
                    example: 'http://localhost:35123/anything/pathParams/json/{"any":"any","bigint":8821239038968084,"bigintStr":"9223372036854775808","bool":true,"boolOpt":true,"date":"2020-01-01","dateTime":"2020-01-01T00:00:00.000001Z","decimal":3.141592653589793,"decimalStr":"3.14159265358979344719667586","enum":"one","float32":1.1,"int":1,"int32":1,"int32Enum":55,"intEnum":2,"num":1.1,"str":"test","strOpt":"testOptional"}'
                required:
                  - url
          description: OK
components:
  schemas:
    simpleObject:
      description: "A simple object that uses all our supported primitive types and enums and has optional properties."
      externalDocs:
        description: "A link to the external docs."
        url: "https://docs.speakeasyapi.dev"
      type: object
      properties:
        str:
          type: string
          description: "A string property."
          example: "test"
        bool:
          type: boolean
          description: "A boolean property."
          example: true
        int:
          type: integer
          description: "An integer property."
          example: 1
        int32:
          type: integer
          format: int32
          description: "An int32 property."
          example: 1
        num:
          type: number
          description: "A number property."
          example: 1.1
        float32:
          type: number
          format: float
          description: "A float32 property."
          example: 1.1
        enum:
          $ref: "#/components/schemas/enum"
        date:
          type: string
          format: date
          description: "A date property."
          example: "2020-01-01"
        dateTime:
          type: string
          format: date-time
          description: "A date-time property."
          example: "2020-01-01T00:00:00.000001Z"
        any:
          description: "An any property."
          example: "any"
        strOpt:
          type: string
          description: "An optional string property."
          example: "testOptional"
        boolOpt:
          type: boolean
          description: "An optional boolean property."
          example: true
        intOptNull:
          type: integer
          description: "An optional integer property will be null for tests."
        numOptNull:
          type: number
          description: "An optional number property will be null for tests."
        intEnum:
          type: integer
          description: "An integer enum property."
          enum:
            - 1
            - 2
            - 3
          example: 2
          x-speakeasy-enums:
            - First
            - Second
            - Third
        int32Enum:
          type: integer
          format: int32
          description: "An int32 enum property."
          enum:
            - 55
            - 69
            - 181
          example: 55
        bigint:
          type: integer
          format: bigint
          example: 8821239038968084
        bigintStr:
          type: string
          format: bigint
          example: "9223372036854775808"
        decimal:
          type: number
          format: decimal
          example: 3.141592653589793
        decimalStr:
          type: string
          format: decimal
          example: "3.14159265358979344719667586"
      required:
        - str
        - bool
        - int
        - int32
        - num
        - float32
        - enum
        - date
        - dateTime
        - any
        - intEnum
        - int32Enum
    enum:
      type: string
      description: "A string based enum"
      enum:
        - "one"
        - "two"
        - "three"
        - "four_and_more"
      example: "one"
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Authenticate using an API Key generated via our platform.

it causes this panic in libopenapi when a request is sent:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x30 pc=0xabcfb7]

goroutine 359 [running]:
github.com/pb33f/libopenapi/datamodel/high/base.(*SchemaProxy).Schema(0x0)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/datamodel/high/base/schema_proxy.go:79 +0x17
github.com/pb33f/libopenapi-validator/parameters.(*paramValidator).ValidatePathParams(0x0?, 0xc00024e000)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/parameters/path_parameters.go:91 +0x452
github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest.func1.2(0x0?, 0x0?, 0x0?)
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:225 +0x27
created by github.com/pb33f/libopenapi-validator.(*validator).ValidateHttpRequest.func1 in goroutine 356
        /home/runner/go/pkg/mod/github.com/pb33f/[email protected]/validator.go:233 +0x3b2

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.