Coder Social home page Coder Social logo

jonasbn / perl-mojolicious-plugin-openapi-tutorial-hello-world Goto Github PK

View Code? Open in Web Editor NEW
5.0 3.0 2.0 79 KB

Tutorial for Mojolicious::Plugin::OpenAPI: Hello World

Home Page: https://dev.to/jonasbn/tutorial-mojoliciouspluginopenapi-3jgd

License: MIT License

Perl 31.27% HTML 1.80% Dockerfile 5.16% Shell 61.77%
perl mojolicious openapi tutorial

perl-mojolicious-plugin-openapi-tutorial-hello-world's Introduction

Tutorial on Mojolicious::Plugin::OpenAPI: Hello World

I have always wanted to get my hands dirty with Swagger. I recently fell over Mojolicious::Plugin::OpenAPI, which fits into my boring stack and I decided to do a prototype.

I followed the tutorial for Mojolicious::Plugin::OpenAPI and found it a bit confusing, so I decided to write up a more simple tutorial.

This tutorial requires that you have Mojolicious installed and recommends carton. The installation of these components is however beyond the scope of this tutorial.

OpenAPI comes from Swagger, which I have had a look at, much water has run under that bridge, so now it is time to look at OpenAPI a specification on how to write RESTful APIs in a standardised format.

Here goes, lets start with a basic hello world example, all files are available on GitHub.

Hello World

First we set up an application, yes we could do a Mojolicious lite-app, but I primarily use Mojolicious apps, so I think it makes sense to keep stick to this for reference.

$ mojo generate app HelloWorld

Jump into our newly generated application directory

$ cd hello_world

We then install the plugin we need to enable OpenAPI in our Mojolicious application

Using CPAN shell:

$ perl -MCPAN -e shell install Mojolicious::Plugin::OpenAPI

Using cpanm:

$ cpanm Mojolicious::Plugin::OpenAPI

If you need help installing please refer to the CPAN installation guide.

Create a definition JSON file based on OpenAPI to support an Hello World implementation based on the OpenAPI specification:

$ touch openapi.conf

The exact name of this file is insignifcant, I just prefer to have clear and understandable filenames for easy identification.

Open openapi.conf and insert the following snippet:

{
    "swagger": "2.0",
    "info": { "version": "1.0", "title": "Hello World example" },
    "basePath": "/api",
    "paths": {
      "/hello_world": {
        "get": {
          "operationId": "helloWorld",
          "x-mojo-name": "hello_world",
          "x-mojo-to": "example#hello_world",
          "summary": "Example app returning hello world",
          "responses": {
            "200": {
              "description": "Returning string 'hello world'",
              "schema": {
                "type": "object",
                "properties": {
                    "greeting": {
                        "type": "string"
                    }
                }
              }
            },
            "default": {
              "description": "Unexpected error",
              "schema": {}
            }
          }
        }
      }
    }
}

Now lets go over our definiton.

  • basePath: defines the root of our URL, so we would be able to access our application at /api, recommendations on versioning APIs using this part is do exist, but for our example application, this is out of scope.

  • paths: here we define our first API path, so our Hello World application can be accessed at: /api/hello_world

  • operationId: the is an operation identifier, it is important for the OpenAPI part, whereas the two following definitions are mappings of the same operation identifier towards the Mojolicious application

  • x-mojo-name: this is the name used to identify our operation in the Mojolicious application

  • x-mojo-to: this is the specification for the route to be used for our operation in the Mojolicious application, more on this later

  • responses: here we define the type we want to handle, for now we settle for 200. The response definition outline our response, this could be boiled down to a string instead of an object, with properties, but the example would be come too simple and in my opinion we work primarily with objects over basic types, so this extended example makes for a better reference.

Next step is to enable the MetaCPAN: Mojolicious::Plugin::OpenAPI plugin in the application

Open the file: lib/HelloWorld.pm and add the following snippet:

$self->plugin("OpenAPI" => {url => $self->home->rel_file("openapi.json")});

Note the pointer to our previously created file: openapi.json.

The complete file should look like the following:

package HelloWorld;
use Mojo::Base 'Mojolicious';

# This method will run once at server start
sub startup {
  my $self = shift;

  $self->plugin('OpenAPI' => {url => $self->home->rel_file('openapi.json')});

  # Load configuration from hash returned by "my_app.conf"
  my $config = $self->plugin('Config');

  # Documentation browser under "/perldoc"
  $self->plugin('PODRenderer') if $config->{perldoc};

  # Router
  my $r = $self->routes;

  # Normal route to controller
  $r->get('/')->to('example#welcome');
}

1;

Then we add the actual operation, open the file: lib/HelloWorld/Controller/Example.pm and add the following snippet:

sub hello_world {
    my $c = shift->openapi->valid_input or return;

    my $output = { greeting => 'Hello World' };
    $c->render(openapi => $output);
}

Note that this maps to the definition in our API definition: openapi.conf

"x-mojo-to": "example#hello_world",

The complete file should look like the following:

package HelloWorld::Controller::Example;
use Mojo::Base 'Mojolicious::Controller';

# This action will render a template
sub welcome {
  my $self = shift;

  # Render template "example/welcome.html.ep" with message
  $self->render(msg => 'Welcome to the Mojolicious real-time web framework!');
}

sub hello_world {
    my $c = shift->openapi->valid_input or return;

    my $output = { greeting => 'Hello World' };
    $c->render(openapi => $output);
}

1;

I decided to implement the tutorial in a scaffolded application, you could create your own controller, but changing an existing controller this way demonstrates how our newly added OpenAPI API end-point, can live in unison with existing and additional end-points.

Now start the application

$ morbo script/hello_world

And finally - lets call the API, do note you do not need jq and your could use curl or httpie, so this is just for sticking to the already available tools, jq being the exception.

$ mojo get --verbose http://localhost:3000/api/hello_world | jq
GET /api/hello_world HTTP/1.1
Host: localhost:3000
User-Agent: Mojolicious (Perl)
Content-Length: 0
Accept-Encoding: gzip

HTTP/1.1 200 OK
Server: Mojolicious (Perl)
Content-Length: 26
Date: Fri, 27 Jul 2018 08:47:33 GMT
Content-Type: application/json;charset=UTF-8

{
  "greeting": "Hello World"
}

Yay! and our first Mojolicious OpenAPI implementation works!

In addition to the operation, you can obtain the specification by calling the following URL: /api

$ mojo get http://localhost:3000/api/

And as mentioned earlier our existing operations and parts of the application still works as expected, try calling the URL: /

$ mojo get http://localhost:3000/

That is it for now, good luck with experimenting with Mojolicious OpenAPI integration and OpenAPI. Thanks to Jan Henning Thorsen (@jhthorsen) for the implementation of Mojolicious::Plugin::OpenAPI.

References

perl-mojolicious-plugin-openapi-tutorial-hello-world's People

Contributors

jonasbn avatar renovate-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

4to4 briandfoy

perl-mojolicious-plugin-openapi-tutorial-hello-world's Issues

minor typo

"Then we add the acual operation" -> "Then we add the actual operation" in README.md

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

cpanfile
cpanfile
dockerfile
.devcontainer/Dockerfile
  • perl 5

  • Check this box to trigger a request for Renovate to run again on this repository

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.