18
Views
5
Comments
Solved by AI
Calling APIs Dynamically Between Two Applications

Hi everyone, 

I have a scenario involving two applications: 

APP1: This application exposes a set of APIs. 

APP2: In this application, I’ve created an entity to store API configuration details such as: Base URL (of APP1) API endpoints 

In APP2, I’m storing these API values (base URL and endpoint) that correspond to services in APP1. In APP2, I have a detail screen for a specific record with a button. On clicking this button, I want to: 

Retrieve the base URL and endpoint from the entity 

Call the corresponding API exposed by APP1 

Question: Is it possible to dynamically call an API using values (base URL + endpoint) stored in an entity in APP2? If yes, could you guide me on: 

How to dynamically build and invoke the API call 

Any OutSystems-specific considerations (since this is an ODC context) 


Thanks in advance for your help!

2023-12-26 10-35-28
OutSystems Neo
Staff
Solution by AI
AI Generated

Yes, it’s possible, but in OutSystems (O11) you can’t “create” REST methods at runtime. You must have at least one consumed REST API defined at design time, and then you use its extensibility hooks (OnBeforeRequest / OnBeforeRequestAdvanced) to turn it into a dynamic caller.

Below is a practical pattern you can apply in your O11 context, even if APP2 is storing the configuration and APP1 exposes the APIs. The same concepts apply if/when you move to ODC (I’ll call out any differences).


1. High‑level approach

  1. In APP2, create a generic consumed REST API (e.g., “GenericCallerAPI”).
  2. Define one or more methods whose purpose is to be “generic”:
    • For example: POST_Generic, GET_Generic, etc.
  3. Use the Base URL and Path parameters in a flexible way, and override them at runtime:
    • Base URL: override via OnBeforeRequest callback.
    • Endpoint / path: pass as an input parameter to the method and map it to the URL path.
  4. Store configuration in an entity in APP2:
    • BaseURL
    • Endpoint (e.g., /Customer/Create, /Order/Close)
    • HTTP Method
    • Optional: expected headers, body templates, etc.
  5. On the Detail Screen button:
    • Read config from entity
    • Call the generic REST method and set:
      • Endpoint input
      • Payload (JSON) input
    • In OnBeforeRequest, override the URL & headers according to the record.

This lets you “dynamically” call whatever endpoint APP1 exposes, using data you stored in APP2.


2. Concrete steps in O11

2.1. Create a generic REST API consumer in APP2

  1. In Service Studio, right‑click your module → Consume REST API… Consume REST APIs

  2. Use any URL as a placeholder (e.g., https://dummy-base-url.com), since we’ll override it.

  3. Create a method, for example:

    • Name: Execute
    • HTTP Method: POST (or GET; you may want one per HTTP method)
    • URL: /generic/{Endpoint} (Endpoint as a URL parameter)
    • Request body: Text (or a Structure) to accept arbitrary JSON.
    • Response: Text (if you just want to pass-through).
  4. On the REST API node:

    • Set Authentication to something appropriate for your scenario (or None if you’ll handle headers manually in callbacks) Consume REST APIs.
    • Implement the OnBeforeRequest callback:
      • This is where you’ll:
        • Override the Base URL
        • Set Authorization / custom headers
        • Possibly adjust the path.

2.2. Entity to store configuration (APP2)

Suppose you have APIConfig entity with attributes:

  • Id (Identifier)
  • Name (Label)
  • BaseURL (Text)
  • Endpoint (Text) — e.g., customers/create
  • HttpMethod (Text or Static Entity) — e.g., GET, POST
  • AuthType (optional: Basic, Token, None)
  • Token or Username / Password (for simple use cases)
  • DefaultPayload (Text) — optional JSON “template”

On the detail screen, you have a record of APIConfig.

2.3. Passing dynamic values into the REST call

On your button’s screen action:

  1. Fetch the APIConfig record (already on the screen).

  2. Build the request:

    • Endpoint input: APIConfig.Endpoint
    • Payload (if POST): derive from user input or APIConfig.DefaultPayload.
  3. Call GenericCallerAPI.Execute with:

    • Endpoint: APIConfig.Endpoint
    • Body: JSON/Text input as needed.

2.4. Overriding Base URL and headers (OnBeforeRequest)

In the OnBeforeRequest callback of your generic REST API:

  1. Inputs: Request (record with URL, Headers, etc.) and your custom inputs if needed.

  2. Steps:

    • Use the Endpoint input you passed to the method (it will be part of the URL).
    • Set Request.BaseURL to the BaseURL stored in your entity record.
    • Add any Authorization header if necessary.

Because callbacks don’t directly know which APIConfig was used, you typically:

  • Add an extra input parameter to the REST method (e.g., ConfigId) so that:
    • You call Execute(ConfigId: APIConfig.Id)
    • In OnBeforeRequest, you fetch the configuration using that ConfigId (server action call) and override Request.BaseURL, Request.Headers, etc.

Pseudo logic in OnBeforeRequest:

// Input: Request, ConfigId

APIConfig = GetAPIConfigById(ConfigId)

Request.BaseURL = APIConfig.BaseURL

// Optionally adjust Request.UrlPath if needed:
Request.UrlPath = "/" + APIConfig.Endpoint

// Headers
If APIConfig.AuthType = AuthType.Token {
   Request.Headers.Add("Authorization", "Bearer " + APIConfig.Token)
}

This pattern leverages the “REST customization capabilities” OutSystems provides for advanced use cases such as custom authentication and dynamic headers Consume REST APIs.


3. OutSystems‑specific considerations (O11 vs ODC)

You mentioned ODC context, but this question is tagged O11, so:

3.1. O11

  • You have OnBeforeRequest and OnBeforeRequestAdvanced on consumed REST APIs.
  • For most scenarios, OnBeforeRequest is enough; use OnBeforeRequestAdvanced + extension if you need client certificates or very low‑level control Consume REST APIs.
  • For authentication:
    • If APP1 uses Basic Auth, you can configure it in the REST API properties, or dynamically set headers in the callback.
    • If APP1 uses token-based auth, follow the token pattern: acquire & cache token, then inject it via header in OnBeforeRequest Consume REST APIs.

3.2. ODC (if you later move)

  • Conceptually similar, but:
  • You still can’t create methods at runtime; you must have at least one generic method and customize its URL and headers dynamically.

4. Alternative: Service Actions instead of REST

Since both apps are in the same OutSystems O11 environment, consider:

  • Expose APP1 logic via Service Actions instead of REST if the consumer is only other OutSystems modules.
  • Service Actions handle:
    • Type-safe calls
    • Impact analysis
    • Easier refactoring
      They are effectively REST-based calls under the hood but managed by the platform REST.

Your dynamic “endpoint” approach is more appropriate when:

  • You truly need a single generic caller (e.g., for many external systems), or
  • APP1/APP2 must communicate over REST for architectural reasons.

5. Summary

  • You can dynamically call an API in APP1 using config stored in APP2, but:
    • The REST method itself is defined at design-time.
    • The dynamic part is the Base URL, path, headers, and body, all set at runtime using:
      • Entity configuration
      • Inputs to the generic method
      • OnBeforeRequest callback to override Base URL and headers.
  • In an internal O11 environment, consider Service Actions when you do not strictly need REST.

If you share a bit about how different the payloads/endpoints are (all similar or completely different), I can propose a more concrete structure for the generic method (number of methods, input types, error handling, etc.).

This answer was AI-generated. Please read it carefully and use the forums for clarifications
2020-02-28 09-46-54
Eduardo Jauch

Hello Gowtham,

May I ask you if both applications are in ODC?

If so, why don't you use service actions instead of the exposed API?
There are a few (but very important) advantages over API calls.
Even if you still need the API for non-OutSystems apps, you can still have the Service Action to use with ODC applications.

If you don't want to use service actions because you already have the API and want to use it, or because APP1 is not in ODC, you can just "consume" the API in your APP2 (assuming APP2 is an ODC app and the API is a REST api.

The point is: why do you need to store the Base URL and endpoints in an Entity?
What's your use case?

The short answer is yes, you can dynamically define the base URL or endpoints in different ways, but in most scenarios there is no need to do that... Hence my questions.

Cheers!

2023-10-30 06-03-17
Gowtham

Thanks @Eduardo Jauch for your reply.

My both apps are in ODC

My use case here is: I need to create a test manager application to do the testing for server action created during the development. The test manager app is generic and independent of all other application. It should not have any direct reference between the application. So if any developer creates a server action and needs to test their action, they just need to expose that action as an API and configure that endpoint in the test manager action. Through test manager application I should be able to call that server action.

2020-02-28 09-46-54
Eduardo Jauch

Ok. I understand the use case now.

I still think the best approach would still be to use a service action.
For your use case, there are some benefits, like the fact you don't need to keep the base url/endpoints (and parameters/output structures) in a configuration entity.

Inside app2, when you make the reference for the service action in app1, it creates a "weak reference", as a service action is a REST endpoint (without the extra work).
This means App1 will never really care about App2 and it will not impact its deployments in any way.

But yes, if the tester does not have access to the make references to the application, or if the applications are not in the same organization, it's not possible to do it this way.
Neo gave you some ways of doing it using REST :)

Cheers!

2023-10-30 06-03-17
Gowtham

The solution provided by @OutSystems Neo works perfect for my scenario. the solution is dynamically replace the endpoint using the On_Before_Request callback action when consuming the API.

Thanks you

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.