Giter VIP home page Giter VIP logo

openapiclient.jl's Introduction

OpenAPIClient

Build Status codecov.io

This is the Julia library needed with code generated by the OpenAPI generator.

The goal of OpenAPIClient is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via OpenAPI, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, OpenAPI removes the guesswork in calling the service.

Check out OpenAPI-Spec for additional information about the OpenAPI project, including additional libraries with support for other languages and more.

How do I use this?

Code Generation

Use instructions provided for the Julia OpenAPI code generator plugin to generate Julia code.

Generated Code Structure

APIs

Each API set is generated into a file named api_<apiname>.jl. It is represented as a struct and the APIs under it are generated as methods. An API set can be constructed by providing the OpenAPI client instance that it can use for communication.

The required API parameters are generated as regular function arguments. Optional parameters are generated as keyword arguments. Method documentation is generated with description, parameter information and return value. Two variants of the API are generated. The first variant is suitable for calling synchronously and returns a single instance of the result struct.

# example synchronous API that returns an Order instance
getOrderById(api::StoreApi, orderId::Int64)

The second variant is suitable for asynchronous calls to methods that return chunked transfer encoded responses, where in the API streams the response objects into an output channel.

# example asynchronous API that streams matching Pet instances into response_stream
findPetsByStatus(api::PetApi, response_stream::Channel, status::Vector{String})

A client context holds common information to be used across APIs. It also holds a connection to the server and uses that across API calls. The client context needs to be passed as the first parameter of all API calls. It can be created as:

Client(root::String;
    headers::Dict{String,String}=Dict{String,String}(),
    get_return_type::Function=(default,data)->default,
    timeout::Int=DEFAULT_TIMEOUT_SECS,
    long_polling_timeout::Int=DEFAULT_LONGPOLL_TIMEOUT_SECS,
    pre_request_hook::Function,
)

Where:

  • root: the root URI where APIs are hosted (should not end with a /)
  • headers: any additional headers that need to be passed along with all API calls
  • get_return_type: optional method that can map a Julia type to a return type other than what is specified in the API specification by looking at the data (this is used only in special cases, for example when models are allowed to be dynamically loaded)
  • timeout: optional timeout to apply for server methods (default OpenAPIClient.DEFAULT_TIMEOUT_SECS)
  • long_polling_timeout: optional timeout to apply for long polling methods (default OpenAPIClient.DEFAULT_LONGPOLL_TIMEOUT_SECS)
  • pre_request_hook: user provided hook to modify the request before it is sent

The pre_request_hook must provide the following two implementations:

  • pre_request_hook(ctx::OpenAPIClient.Ctx) -> ctx
  • pre_request_hook(resource_path::AbstractString, body::Any, headers::Dict{String,String}) -> (resource_path, body, headers)

In case of any errors an instance of ApiException is thrown. It has the following fields:

  • status::Int: HTTP status code
  • reason::String: Optional human readable string
  • resp::Downloads.Response: The HTTP Response for this call
  • error::Union{Nothing,Downloads.RequestError}: The HTTP error on request failure

An API call involves the following steps:

  • If a pre request hook is provided, it is invoked with an instance of OpenAPIClient.Ctx that has the request attributes. The hook method is expected to make any modifications it needs to the request attributes before the request is prepared, and return the modified context.
  • The URL to be invoked is prepared by replacing placeholders in the API URL template with the supplied function parameters.
  • If this is a POST request, serialize the instance of OpenAPIModel provided as the body parameter as a JSON document.
  • If a pre request hook is provided, it is invoked with the prepared resource path, body and request headers. The hook method is expected to modify and return back a tuple of resource path, body and headers which will be used to make the request.
  • Make the HTTP call to the API endpoint and collect the response.
  • Determine the response type / model, invoke the optional user specified mapping function if one was provided.
  • Convert (deserialize) the response data into the return type and return.
  • In case of any errors, throw an instance of ApiException

Models

Each model from the specification is generated into a file named model_<modelname>.jl. It is represented as a mutable struct that is a subtype of the abstract type OpenAPIModel. Models have the following methods defined:

In addition to these standard Julia methods, these convenience methods are also generated that help in checking value at a hierarchical path of the model.

  • function haspropertyat(o::T, path...) where {T<:OpenAPIModel}
  • function getpropertyat(o::T, path...) where {T<:OpenAPIModel}

E.g:

# access o.field.subfield1.subfield2
if haspropertyat(o, "field", "subfield1", "subfield2")
    getpropertyat(o, "field", "subfield1", "subfield2")
end

# access nested array elements, e.g. o.field2.subfield1[10].subfield2
if haspropertyat(o, "field", "subfield1", 10, "subfield2")
    getpropertyat(o, "field", "subfield1", 10, "subfield2")
end

Validations

Following validations are incorporated into models:

  • maximum value: must be a numeric value less than or equal to a specified value
  • minimum value: must be a numeric value greater than or equal to a specified value
  • maximum length: must be a string value of length less than or equal to a specified value
  • minimum length: must be a string value of length greater than or equal to a specified value
  • maximum item count: must be a list value with number of items less than or equal to a specified value
  • minimum item count: must be a list value with number of items greater than or equal to a specified value
  • enum: value must be from a list of allowed values

Validations are imposed in the constructor and setproperty! methods of models.

openapiclient.jl's People

Contributors

tanmaykm avatar

Stargazers

Aditya Puranik avatar

Watchers

 avatar  avatar

openapiclient.jl's Issues

Spurious `convert` exported.

# export models
export convert, ApiResponse
export convert, Category
export convert, Order
export convert, Pet
export convert, Tag
export convert, User
# export operations
export convert, PetApi, StoreApi, UserApi

Comes from expanding

# export models
{{#models}}
export convert{{#model}}, {{classname}}{{/model}}
{{/models}}

# export operations
{{#apiInfo}}
export convert{{#apis}}, {{classname}}{{/apis}}
{{/apiInfo}}

in client.mustache. I guess this model and apis key does not exist.

Experiences from trying to generate a client from GitHub

Command to generate it:

java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
   -i https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.yaml \
   -g julia \
   -o ~/GitHubClient

Some files missing:

julia> include("src/APIClient.jl")
[ Info: Precompiling OpenAPIClient [12741cc8-1e73-42f3-a27c-379dbea8d6a3]
ERROR: LoadError: SystemError: opening file "/Users/kristoffercarlsson/GitHubClient/src/model_ModelImport.jl": No such file or directory

There is however a file called model_Import that contains the ModelImport type.

Invalid field names

mutable struct ReactionRollup <: OpenAPIClient.APIModel
    url::Any # spec type: Union{ Nothing, URI } # spec name: url
    total_count::Any # spec type: Union{ Nothing, Int32 } # spec name: total_count
    1::Any # spec type: Union{ Nothing, Int32 } # spec name: +1
    _1::Any # spec type: Union{ Nothing, Int32 } # spec name: -1

The 1 is invalid. The var"1" syntax could be used.

The spec shows this type as:

        total_count:
          type: integer
        "+1":
          type: integer
        "-1":

So the - has turned to _ and the plus has dissapeared.

Invalid function names

function _oacinternal_actions/addCustomLabelsToSelfHostedRunnerForOrg
...

Function name contains /.

Use `var""` syntax instead of escaping etc?

It is possible to have arbitrarily named identifiers with the var"" syntax:

julia> var"function"  = 3
3

julia> var"function"
3

It might be interesting to think about using that for identifiers that cannot be represented directly in Julia instead of doing all the escaping and removal of them.

Some transformations should probably be done so that var"" is not required in most cases but it might be easier for users if they don't have to learn all the escaping rules and can just use the actual name.

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.