alisinabh

alisinabh

Prex - API client scaffolder for elixir

Hi everyone.

In last month i was dealing with REST Api services mostly from client perspective and i realized how much people don’t care about documentation of their APIs. That’s Crazy! There was even one company who hadn’t any docs at all! They just sent me their real-time generated docs (seriously?) as we were talking on messenger and almost all of it were WRONG!

But even when there was a cool and fair documentation, it was still a time consuming task developing every single action in those documents.

So there is something called ApiBlueprint.
It is simply:

A powerful high-level API description language for web APIs.

It is so nice. If you are familiar with apiary you hopefully know what an ApiBlueprint is.

Since ApiBlueprint is fairly rich, I came up with the idea of writing a code generator based on ApiBlueprint that takes .apib files and convert them to Elixir code for usage.

I’ve named it Prex

Simply Prex can take .apib file and generate Elixir modules like this:

# Created by Prex
defmodule Example.Posts do
  @moduledoc """
  This section groups App.net post resources.
  """

  @base_url "https://alpha-api.app.net"

  ###
  # API Calls
  ###

  # Post

  @doc """
  Returns a specific Post.

  ## Parameters
    - postid: The id of the Post.
  """
  def retrieve_a_post(postid \\ "") do
    req_url = Path.join @base_url, "/stream/0/posts/{post_id}"
    HTTPoison.request(:get, req_url, body: Poison.encode!(%{"post_id" => postid}), headers: ["Content-Type": "application/json"])
  end

  def retrieve_a_post!(postid \\ "") do
    {:ok, result} = retrieve_a_post(postid)
    result
  end

  @doc """
  Delete a Post. The current user must be the same user who created the Post. It
returns the deleted Post on success.

  ## Parameters
    - postid: The id of the Post.
  """
  def delete_a_post(postid \\ "") do
    req_url = Path.join @base_url, "/stream/0/posts/{post_id}"
    HTTPoison.request(:delete, req_url, body: Poison.encode!(%{"post_id" => postid}), headers: ["Content-Type": "application/json"])
  end

  def delete_a_post!(postid \\ "") do
    {:ok, result} = delete_a_post(postid)
    result
  end

  # Posts Collection

  @doc """
  Create a new Post object. Mentions and hashtags will be parsed out of the post
text, as will bare URLs...
  """
  def create_a_post do
    req_url = Path.join @base_url, "/stream/0/posts"
    HTTPoison.request(:post, req_url)
  end

  def create_a_post! do
    {:ok, result} = create_a_post()
    result
  end

  @doc """
  Retrieves all posts.
  """
  def retrieve_all_posts do
    req_url = Path.join @base_url, "/stream/0/posts"
    HTTPoison.request(:get, req_url)
  end

  def retrieve_all_posts! do
    {:ok, result} = retrieve_all_posts()
    result
  end

  # Stars

  @doc """
  Save a given Post to the current User’s stars. This is just a “save” action,
not a sharing action.

*Note: A repost cannot be starred. Please star the parent Post.*

  ## Parameters
    - postid: The id of the Post.
  """
  def star_a_post(postid \\ "") do
    req_url = Path.join @base_url, "/stream/0/posts/{post_id}/star"
    HTTPoison.request(:post, req_url, body: Poison.encode!(%{"post_id" => postid}), headers: ["Content-Type": "application/json"])
  end

  def star_a_post!(postid \\ "") do
    {:ok, result} = star_a_post(postid)
    result
  end

  @doc """
  Remove a Star from a Post.

  ## Parameters
    - postid: The id of the Post.
  """
  def unstar_a_post(postid \\ "") do
    req_url = Path.join @base_url, "/stream/0/posts/{post_id}/star"
    HTTPoison.request(:delete, req_url, body: Poison.encode!(%{"post_id" => postid}), headers: ["Content-Type": "application/json"])
  end

  def unstar_a_post!(postid \\ "") do
    {:ok, result} = unstar_a_post(postid)
    result
  end

end

I’ve been working on this for only about 48 hours now. It’s super buggy. :cold_sweat:
It is going to support SOAP with WSDL too.

I just want to know how much do you think this is useful?

Please share your opinion with me. Even if you think this is very useless.

Thank’s for reading this. :slight_smile:

https://github.com/alisinabh/prex

Most Liked

alisinabh

alisinabh

The ? (Question mark) before a variable name is a standard for ApiBlueprint which indicates that parameter is not mandatory. So this is not possible to have it in ApiBlueprint.

This is also applied to HTTP, you cannot have a variable in HTTP Query strings (Which is same as application/x-www-form-urlencoded in post body) that contains a ?.

However you can achieve ? in variable name by using %3F instead of ? in both ApiBluprint and HTTP requests.

Thank you @OvermindDL1 :blush:

mbuhot

mbuhot

This is really neat!

My current workflow uses phoenix_swagger to generate a swagger spec, then bureaucrat to generate markdown documentation.

With good tools available, there’s no excuse to not have a well documented REST API :smiley:

One idea I haven’t tied out yet is to replace custom mix tasks that generate json/markdown/html files with a more integrated mix compiler, this post makes it look pretty strait forward.

For prex, you might be able to use macros to generate the module body from the api blueprint, using @external_resource to cause a recompile when the blueprint changes.

OvermindDL1

OvermindDL1

That looks quite cool. :slight_smile:

Hold on to your sanity! ^.^;

Where Next?

Popular in Discussions Top

Jayshua
I recently came across the javascript library htmx. It reminded me a lot of liveview so I thought the community here might be interested....
New
pillaiindu
In django there is a cache framework backed by memcached. Rails also puts a lot of emphasis on caching, and even the idea of russian-doll...
New
WolfDan
After doing a port from a c++ library to my project in phoenix I’ve seen that I need a faster way to run this algorithm and I found this ...
New
mmport80
I have put far too much effort into Dialyzer over the last year or so - and basically - I doubt it’s worth the effort. It’s not as easy ...
New
arpan
Hello everyone :wave: Today I am very excited to announce a project that I have been working on for almost 3 months now. The project is...
New
lucaong
Hello Elixir and Nerves community, I have been working for a while on an open-source embedded key-value database for Elixir, that I call...
230 13924 124
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -> H; nth(N, [_|T]) when N > 1 -> nth(N - 1, T). Elixir Enum.at … coo...
New
fireproofsocks
I’ve been working on an Elixir project that has required a lot of scripting. I usually reach for Elixir because I like it more (and in th...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

We're in Beta

About us Mission Statement