Search code examples
perlurlopenapimojolicious

OpenAPI: is it possible to include IP address (string with dots) in URL path?


Using Mojolicious::Plugin::OpenAPI, is it possible to include an IP address in a URL path (not query parameter)? As per RFC 3986 §2.2, . is not a reserved character.

When I try:

curl 'localhost:3000/api/echo/192.168.1.1'

I get an http/404 Not Found error:

{
    "errors": [
        {
            "message": "Not Found.",
            "path": "/"
        }
    ],
    "status": 404
}

What I expect is:

{
    "ip": "192.168.1.1"
}

Here's a sample Mojolicious full-app:

./api.yaml

---
openapi: 3.0.3
servers:
  - url: /api
info:
  version: 1
  title: MyAPI
paths:
  /echo/{ip}:
    get:
      x-mojo-to: Example#echo
      parameters:
      - name: ip
        in: path
        required: true
        schema:
          type: string
          format: ipv4
      responses:
        '200':
          description: OK
        '500':
          description: Internal Server Error

./lib/MyApp.pm

package MyApp;
use Mojo::Base 'Mojolicious', -signatures;

sub startup ($self) {
  $self->plugin(OpenAPI => {url=>$self->home->rel_file("api.yaml")});
  $self->plugin(SwaggerUI => {route=>$self->routes()->any('/swagger'),url=>"/api"});
}

1;

./lib/MyApp/Controller/Example.pm

package MyApp::Controller::Example;
use Mojo::Base 'Mojolicious::Controller', -signatures;

sub echo($self) {
  my $app   = $self->openapi->valid_input or return;
  my $input = $app->validation->output;
  my $ip    = $input->{ip};
  $app->render(openapi=>{ip=>$ip});
}

1;

Solution

  • Inspired by mojo discussions and from this answer:

    • Standard : placeholders can match all characters except . and /
    • Relaxed # placeholders can match all characters except /
    • Wildcard * placeholders can match all characters

    So in my api.yaml, I need to set x-mojo-placeholder to "#" (Relaxed)

    ---
    openapi: 3.0.3
    servers:
      - url: /api
    info:
      version: 1
      title: MyAPI
    paths:
      /echo/{ip}:
        get:
          x-mojo-to: Example#echo
          parameters:
          - name: ip
            x-mojo-placeholder: "#"
            in: path
            required: true
            schema:
              type: string
              format: ipv4
          responses:
            '200':
              description: OK
            '500':
              description: Internal Server Error