lud

lud

Hello!

I’ve been working on the Oaskit library for a while now, and just released a first version.

Since I’ve built JSV I wanted to be able to use the latest JSON schemas specifications with OpenAPI, which is possible since version 3.1.

The OpenAPI specification 4.0 has been delayed, and the 3.2 is on its way, so I needed a solid foundation to support those in the future. Also, I have the feeling that next iterations of the spec will have more LLM-oriented features, so I wanted to be able to follow those evolutions with ease.

What is it?

Oaskit is heavily inspired from OpenApiSpex.

It is a set of macros and plugs that automatically validate incoming HTTP requests based on OpenAPI specifications.

It is built around JSON Schema validation provided by JSV and the operation macro.

Key features

  • Request validation plug.
  • Leverages JSV error formatter in API responses. An HTML error page is also built-in if you need it (a must have for user-facing prototypes).
  • Spec generation from router paths.
  • Supports specs from JSON documents or arbirary elixir code.
  • Spec JSON generation. Not supporting YAML at the moment, and I don’t plan to. But I’d be happy to open for custom formatters in the codebase.
  • Test helper to validate responses in your tests.

Missing features

A couple things are missing and on the roadmap:

  • A JSON schema for the built-in error formatter, so you can build 400/415/422 errors in your client generators. My team uses Orval and it’s pretty neat.
  • A controller to serve the JSON spec, and maybe a controller to serve SwaggerUI or Redoc, though I never use those but I know some love it.
  • Header validation (Never used it either, as we generally put validation plugs after the authentication/negociation plugs).

I’m also open for ideas!

Quick example

Here’s what defining an operation looks like:

defmodule MyAppWeb.UserController do
  use MyAppWeb, :controller

  operation :create,
    summary: "Create a new user",
    request_body: {CreateUserAttrsSchema, description: "The user payload"},
    responses: [
      created: UserSchema,
      unprocessable_entity: ErrorSchema
    ]

  def create(conn, _params) do
    # ...
  end
end

Getting started

If you want to try it for yourself, the Quickstart Guide covers everything you need to get up and running!

Current status

This is an early release, so while it’s functional and tested, it may have shortcomings and bugs. I need to test it thoroughly in production before calling it production ready.

I’d love to hear your thoughts! Any feedback, bug reports, or feature requests are welcome!

Thanks for reading!

https://github.com/lud/oaskit

Showing Posts 1 to 10

lud

lud OP

I’ve just released a new version with a controller that can serve the spec and Redoc ui :slight_smile:

lud

lud OP

I just released version 0.2 with a guide on how to use the library with an existing OpenAPI JSON document instead of defining the operations in the controller: Using an External Specification — oaskit v0.2.0 cc @mayel .

(Spoiler, there is still a tiny macro to use).

Asd

Asd

Hi, nice library. I have one question:
It looks very very very similar to open_api_spex. Whats the difference between your library and open_api_spex and why/when should I choose your one?

lud

lud OP

Hello,

Yes it’s very inspired from OpenApiSpex, basically the same thing. OpenApiSpex is based on OpenAPI 3.0 and Oaskit on OpenAPI 3.1.

Those two version are not really compatible infortunately. 3.1 works with standard JSON schemas and I needed that so I built Oaskit.

phcurado

phcurado

@lud awesome library, using OpenAPI 3.1 and following JSON Schema spec is just what I need it

lud

lud OP

Oaskit JSON shema validation is based on JSV, you might want to have a look if you are going to work with schemas!

phcurado

phcurado

I did use JSV to validate the schemas I was generating with my library, another great addition to the elixir ecosystem :flexed_biceps:.

lud

lud OP

Hey everyone!

This is an important update for Oaskit with one breaking change!

The library can now automatically delegate authorization of requests to a custom plug of yours, using the security requirements defined on operations.

Please read this post before upgrading if you’re using the library.

The security requirements definitions on operations are now checked. If your OpenAPI specification defines security options, Oaskit will now expect a custom plug that you provide to authorize requests.

From now on, Oaskit will automatically respond to requests on those operations with a 401 HTTP Error unless you provide a custom plug to handle authorization.

This is all covered in a new security guide.

To keep the current behaviour of the library (not verifying authorization), please update your code to set the :security option to false.

plug Oaskit.Plugs.ValidateRequest,
  security: false

Security is important so any feedback will be highly appreciated! Also, many thanks to @MrYawe for the motivation and the bug reports :hugs:

Changelog

[0.6.0] - 2025-10-11

:rocket: Features

  • Added operation-level security check using user-defined plugs
  • Added support for root level security requirements
  • [breaking] Handling security is now mandatory

:bug: Bug Fixes

  • Ensure response body is a binary in Oaskit.Test.valid_response (#23)
  • Fixed normalization of %Reference{} structs

How do I know if I am concerned by this update?

You are concerned if your OpenAPI specification defines security at the root level:

---
openapi: 3.1.1
info:
  title: Oaskit Security API
  version: 0.0.0
servers:
- url: http://localhost:5001/
# Global security
security:
- global:
  - some:global1
  - some:global2

Or at the operation level:

---
openapi: 3.1.1
info:
  title: Oaskit Security API
  version: 0.0.0
servers:
- url: http://localhost:5001/
paths:      
  "/example":
    post:
      operationId: "..."
      # Operation Level security
      security:
      - someApiKey:
        - some:scope1
        - some:scope2
      responses:
        '200':
          content:
            application/json:
              schema: {}
          description: "..."

You are also concerned if your were using the operation macro by passing the :security option (which was not used but could be defined):

operation :create_post,
  operation_id: "CreatePost",
  request_body: PostSchema,
  security: [%{api_key: ["post:read", "post:create"]}]

def create_post(conn, _) do
  # ...
end

Thank you for using Oaskit! Have a nice evening :slight_smile:

lud

lud OP

Just bumping my own topic as dependabot will trigger this morning and there is an important step to do before upgrading :slight_smile:

lud

lud OP

Hello!

Oaskit now has experimental support for extensions, limited on the operation only.

You can add any key to the operation macro and it will be forwarded into the conn.private.oaskit.extensions map that controllers and subsequent plugs can access.

If you do not use macros from Oaskit, this also works with unknown keys that are defined in your OpenAPI specification document (from YAML for instance) that you feed to Oaskit.

If you do use the macros, and generate JSON dumps of your specification with mix openapi.dump, only the extensions prefixed with x- are exported.

Here is a complete example of how it could be used:

defmodule MyAppWeb.UserController do
  use MyAppWeb, :api_controller
  use JSV.Schema

  # This could be defined by `use MyAppWeb, :api_controller` directly, below 
  # the Oaskit request validation plug
  plug MyAppWeb.Plugs.RateLimiter

  defschema CommentRequest,
    message: string(),
    author: string()

  defschema CommentResponse,
    id: integer(),
    message: string(),
    author: string()

  operation :create,
    # Generic OpenAPI fields
    summary: "Post a comment",
    request_body: CommentRequest,
    responses: [
      ok: CommentResponse, 
      bad_request: MyAppWeb.Schemas.BadRequest
    ],

    # Public extensions with `x-`
    "x-rate-limit": 100,
    
    # Private extensions
    skip_antispam_for: :admin

  def create(conn, params) do
    %CommentRequest{} = comment = body_params(conn)

    spam_comment? =
      if user_role(conn) == conn.private.oaskit.extensions.skip_antispam_for do
        false
      else
        spam_comment?(comment)
      end

    if spam_comment? do
      reject_comment(conn)
    else
      create_comment(conn, comment)
    end
  end
end

You can find more information in the short extensions guide. I hope this can cover most customization needs for now, we’ll see how it is used and how we can make it evolve in the future.

Many thanks to maximejimenez for the help!

Cheers :slight_smile:

Where Next? Top

Trending in Announcing Top

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New
quatermain
Hello, I’m sharing my plugin here in forum after some time so it has time to mature and proof yourself. I use Claude Code daily on a pr...
New

Other Trending Topics Top

KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews