https://avo.cool logo
Hey y'all Been trying to get Avo to work with ...
# resources
c
Hey y'all Been trying to get Avo to work with remote HTTP resources. Tried ActiveResource, failed miserably. Then, found those docs for Avo 4 https://docs.avohq.io/4.0/http-resources.html I understand that it's still in alpha and the timeframe to Avo 4 might not be as clear. STILL It looks like HTTP resources are only available for fancier licenses like Pro or Advanced. Is it gonna be the case after the release? If so, what kind of license would that require?
m
Thread automatically created by Morozzzko in #1141725701549072486
l
Hi @clever-pillow-79177 > Been trying to get Avo to work with remote HTTP resources. Tried ActiveResource, failed miserably. I can relate, it’s not straightforward to implement, which is why we ended up building a native solution. > It looks like HTTP resources are only available for fancier licenses like Pro or Advanced. Is it gonna be the case after the release? We're still organizing things, so I don't have a clear answer yet. One thing's for sure, it'll be under a paid license, not the community version.
c
Awesome, thank you! Having it under a paid license makes sense! Would be amazing if that feature made it to the main demo (or any demo, actually) once it's ready I don't get to deal with greenfield software often – so there's usually an existing system with its history and implications. And it's quite regular that the backoffice / admin panel / whatever is taking a lot of effort. I usually take the time to demo how little effort it would take with Avo. Obviously I won't be able to showcase HTTP resources until we've bought the subscription, and we won't buy the subscription until I've demonstrated that it can do what we need. BUT it'd still work if I could show how much effort we'd need once we've acquired the license AND showcased the feature using an official demo app Please read that as a feedback with a descriptive context (and a job to be done) and not as "I expect you to do that"
l
Got it! We already have a demo set up, the demo app is live and includes two working HTTP resources. One resource fetches records from https://docs.openalex.org The other fetches records from the app itself using the Avo API that will ship with Avo 4. Basically, the Avo API enables CRUD operations through an API. I enabled the Avo API on the Users resource in this demo app, so we have the normal Users resource fetching data from the database, and the HTTP Users resource fetching the same data but through the first resource's API. This setup is useful if you have two Avo apps and want to display a resource from one app in another. The idea is simple: 1. Enable the API on the resource in the first app. 2. Fetch and display those records in the second app using an HTTP resource. The demo repo is private for now, but I'll send you the relevant code, demo app link, and docs in a few minutes.
[Avo API Docs (work in progress, I'm currently working on compacting the docs and reorganizing them.)](https://docs.avohq.io/4.0/rest-api/)
c
Ooooh myy goodness, you're amazing
l
This one is the easiest to showcase IMO. This resource is an ActiveRecord-backed Avo resource, a normal one let's say. https://avo-4.avodemo.com/admin/resources/users Code:
Copy code
ruby
# app/avo/resources/user.rb

class Avo::Resources::User < Avo::BaseResource
  self.discreet_information = [
    {
      label: -> { record.persisted? ? "GET #{avo_api.resources_v1_user_path(record)}" : nil },
      url: -> { record.persisted? ? avo_api.resources_v1_user_path(record) : nil  },
      url_target: "_blank",
    }
  ]
  
  self.index_controls = -> do
    link_to "GET #{avo_api.resources_v1_users_path}", avo_api.resources_v1_users_path, target: "_blank"
    default_controls
  end

  self.search = {
    query: -> {
      query.order(created_at: :desc).where("last_name LIKE ?", "%#{q}%")
        .or(query.order(created_at: :desc).where("first_name LIKE ?", "%#{q}%"))
        .or(query.order(created_at: :desc).where("id = ?", q))
    },
    item: -> do
      {
        title: record.name,
        description: "#{record.email}",
        image_url: "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(record.email.strip.downcase)}?s=100 ",
        image_format: :circle
      }
    end
  }
  def fields
    discover_columns
  end

  def form_fields
    discover_columns except: [:created_at, :updated_at]
    field :password, as: :password
  end
end
Adding this controller enables the avo api
Copy code
ruby
# app/controllers/avo/api/resources/v1/users_controller.rb

module Avo
  module Api
    module Resources
      module V1
        class UsersController < BaseResourcesController
          # Add any custom logic for User resources here
          #
          # Example: Override methods to customize behavior
          # def index
          #   super
          #   # Add custom logic after calling super
          # end
          #
          # def show
          #   super
          #   # Add custom logic for show action
          # end
        end
      end
    end
  end
end
Check index endpoint for example: https://avo-4.avodemo.com/api/resources/v1/users
Now, this http resource uses the API endpoints from the above ☝️ https://avo-4.avodemo.com/admin/resources/http_users
And it looks like this:
Copy code
ruby
class Avo::Resources::HttpUser < Avo::Core::Resources::Http
  self.http_adapter = {
    endpoint: Rails.env.production? ? "https://avo-4.avodemo.com/api/resources/v1/users" : "http://localhost:3000/api/resources/v1/users",
    # Basic auth example
    headers: -> {
      {
        "Authorization" => "Basic #{Base64.encode64(request.cookies["email_password"] || "avo@avohq.io:secret")}".gsub("\n", "")
      }
    },
    parse_collection: -> {
      if raw_response.code == 401
        raise Avo::HttpError.new "Unauthorized"
      end

      raise Avo::HttpError.new response["message"] if response["error"].present?

      response["records"]
    },
    parse_record: -> {
      response["record"]
    },
    parse_count: -> {
      response["pagination"]&.dig("total_count")
    }
  }
  self.description = "This is a HttpResource (avo-http_resource) to the Avo::Resources::User endpoints (avo-api)"
  self.visible_on_sidebar = false
  
  def fields
    field :first_name
    field :last_name
    field :email
    field :created_at
    field :updated_at
  end
end
You're amazing! πŸ˜„
Let me know if you have any questions
c
Looks awesome! Pretty neat and compact Thank you for taking the time to showcase and explain! And for all the work you're doing
l
Cooool! You're welcome, anytime! Thank you for the feedback!