Get a string from any API using Chainlink Large Response Example - oracle

I just need to get a string from this json, for example: https://filesamples.com/samples/code/json/sample1.json
I took the Chainlink example and just change the URL and path. The example works fine, but if you use a different json o jobid it do not work.
Link to chainlink example: https://docs.chain.link/docs/large-responses/
Is there any way to solve this?
Code used:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
/**
* #notice DO NOT USE THIS CODE IN PRODUCTION. This is an example contract.
*/
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
// variable bytes returned in a signle oracle response
bytes public data;
string public dataS;
/**
* #notice Initialize the link token and target oracle
* #dev The oracle address must be an Operator contract for multiword response
*
*
* Kovan Testnet details:
* Link Token: 0xa36085F69e2889c224210F603D836748e7dC0088
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink DevRel)
*
*/
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8);
}
/**
* #notice Request variable bytes from the oracle
*/
function requestBytes(
)
public
{
bytes32 specId = "7a97ff8493ec406d90621b2531f9251a";
uint256 payment = 100000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("get","https://filesamples.com/samples/code/json/sample1.json");
req.add("path", "fruit");
requestOracleData(req, payment);
}
event RequestFulfilled(
bytes32 indexed requestId,
bytes indexed data
);
/**
* #notice Fulfillment function for variable bytes
* #dev This is called by the oracle. recordChainlinkFulfillment must be used.
*/
function fulfillBytes(
bytes32 requestId,
bytes memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
emit RequestFulfilled(requestId, bytesData);
data = bytesData;
dataS = string(data);
}
}

The response of that API is:
{
"fruit": "Apple",
"size": "Large",
"color": "Red"
}
The fruit has a value of Apple. You'll need to have the API return the bytes edition of Apple instead.
You'll notice the example returns JSON that looks like:
{
"image": "0x68747470733a2f2f697066732e696f2f697066732f516d5358416257356b716e3259777435444c336857354d736a654b4a4839724c654c6b51733362527579547871313f66696c656e616d653d73756e2d636861696e6c696e6b2e676966"
}
Which is the hex edition of the URL of the image.

Related

Echo golang - issue with Swagger example values

I have ECHO server on GO and assigned on it Swagger.
If I'm using the structure which is on the same package (file) then example values are working well, ex:
type Test struct {
TestField string `json:"test_field" example:"testfield"`
type MaintenanceConfigPage struct {
ConfigFile string `json:"config_file" example:"configfile"`
Test TestField `json:"test"`
}
// maintenance godoc
// #Accept json
// #Produce json
// #Param data body MaintenanceConfigPage true "Config configuration"
// #Success 200 {object} string
// #Failure 400 {object} string
// #Router /maintenance [post]
func maintenanceSetupPost(echo_context echo.Context) error {
return echo_context.JSON(http.StatusOK, "test")
}
So, that on Swagger example value I'm getting correct value:
{ "config_file": "configfile", "test": {
"test_field": "testfield" } }
But issue is coming when I'm trying to import the struct from another package, like:
type MaintenanceConfigPage struct {
ConfigFile string `json:"config_file" example:"configfile"`
Test anotherPackage.TestField `json:"test"`
}
The everything is working, but swagger on example value providing just a
{}
If someone also receive before such problems and found the solution, please share

GraphQL Dataloader fails if backend returns null values

I have a GraphQL object type Student. And each student may or may not have Phone data.
Phone is another GraphQL type object (A child object in Student).
I have GraphQL dataloader registered on Phone. Things work fine as long as each student record has a corresponding Phone record. But if there is any student record who does not have a corresponding phone record, Dataloader fails with error:
"message": "Exception while fetching data (/students[0]/phone) : The size of the promised values MUST be the same size as the key list",
I believe this is because, dataloader is trying to assert that size-of-keys-in-list should be same as size-of-values-resolved-in-list.
Is there anyway to accept null as values which is a valid case in my requirement.
Found that the backend server is not even sending 'null', it just ignores the missing record.
From official source:
https://github.com/graphql-java/java-dataloader/blob/7bf46ea182b1f8ab255c3107b1b61d4afd36ad88/src/main/java/org/dataloader/BatchLoader.java
Dataloader does support null values:
*
* <pre>
* [
* { id: 2, name: 'San Francisco' },
* { id: 9, name: 'Chicago' },
* null,
* { id: 1, name: 'New York' }
* ]
* </pre>

RxJS: Rate limit and concurrently limit HTTP requests made at different places

I am writing a script using an external API that needs to limit the requests based on:
a maximum number of requests per second
a maximum of current requests
I found and achieved have this behavior working for a single request, but I have a workflow where I need to:
deal with pagination
make two different kind of requests to the same API, the second one being dependent of the first one.
The snippet below illustrates the requests workflow, I tried several things with the mergeMap and expand concurrent parameters and some techniques I found here that has I said work well for one request but I am a little bit confused on how to track all the requests to "sync" the limits across all the requests.
* Get a page of 1000 companies and the total number of companies.
*
* #param afterId Optional id of the last fetched company (to get the next ones).
*/
function getCompanies(afterId?: string): Observable<{ count: number; companies: Company[] }> {
const options = { limit: 1000, afterId }
return this.http.post('https://example.com/searches/companies', options)
}
function getAllCompanies(): Observable<Company[]> {
let alreadyFetchedCount = 0
this.getCompanies().pipe(
expand(({ count, companies }) =>
count <= alreadyFetchedCount ? EMPTY : this.getCompanies(companies[companies.length - 1].uuid)
),
tap(({ companies }) => (alreadyFetchedCount += companies.length))
)
}
/**
* Get a page of 1000 funding rounds.
*
* #param companyUuid The funding rounds company uuid.
* #param afterId Optional id of the last fetched company (to get the next ones).
*/
function getFundingRounds(
companyUuid: string,
afterId?: string
): Observable<{ count: number; fundingRounds: FundingRound[] }> {
const options = { limit: 1000, companyUuid, afterId }
return this.http.post('https://example.com/searches/companies', options)
}
function getAllFundingRounds(companyUuid: string): Observable<FundingRound[]> {
let alreadyFetchedCount = 0
this.getFundingRounds().pipe(
expand(({ count, fundingrounds }) =>
count <= alreadyFetchedCount ? EMPTY : this.getFundingRounds(fundingrounds[fundingrounds.length - 1].uuid)
),
tap(({ fundingrounds }) => (alreadyFetchedCount += fundingrounds.length)),
reduce((acc, value) => [...acc, ...value], [])
)
}
function main() {
getAllCompanies().pipe(
// Here I get a stream of 1000 or less companies until all companies have been fetched.
// Let's work one company by one company.
mergeMap((companies) => companies),
// For each company, get the funding rounds and return the company extended with them.
mergeMap((company) =>
getAllFundingRounds(company.uuid).pipe(map((fundingRounds) => ({ ...company, fundingRounds })))
),
toArray(),
tap(companies =>
// Do something with the result
)
)
}
You can make use of delay that will make sure that you are making http requests within specified time and concatMap that will help you make requests in sequence
this.function1().pipe(
mergeAll(),
delay(1000),
concatMap((data: any) => this.function2(data.id)),
).subscribe(
console.log
);
function2(id: string = ''): Observable<any> {
console.log('id', id);
return serviceCAll().pipe(
delay(1000)
);
}

Type of return data in API platform

I have a problem of changing types of returned data in API platform:
I have an entity:
final class ModelClass
{
/**
* #var float
*/
public $total;
}
And a configuration:
ModelClass:
properties:
total:
attributes:
swagger_context:
type: float
And Controller:
public function __invoke(CustomRequest $request): Paginator
{
return $this->service->getTotals($request);
}
The return of this is Paginator, which holds custom doctrine query, result of which looks like this:
{
"#type": "hydra:Collection",
"hydra:member": [
{
"id": 1,
"total": "120.00",
},
]
}
As you see, total is a string (because in the result of query it is a string). What i want it to be: a float: "total": 120.00. And what i would also like to be able to do, is to format it differently, for example separator sign ',' instead '.'
I didnt find in documentation how to do it. Is it a missing documentation or missing feature?
I would expect that API platform reads DocBlock to understand the type of Model. And i think that there is some intercept mechanism after query is executed, but before response is sent back to client, so i could change format/type.
Thank you.

sailsjs - what's the best way to track rooms at app level

sails.sockets.rooms() and sails.sockets.socketRooms() are both deprecated
In the doc:
This method is deprecated. Please keep track of your rooms in app-level code.
I am new to SailsJS.
Question 1: How could I get started with that? Where should I declare my room array or hash?
Question 2: How do I get the list of the clients connected?
Here the way I did it. Hope this helps a little, although I am not confident it's perfect, BUT it worked for me. Feel free to suggest corrections, enhancements.
I declared a sails.rooms = {}; in the controller (Question 1) where I needed it most. (You can name it whatever you want.)
sails. gives it access across the application.
In the controller
/**
* Socket connection
*/
connect: function(req, res) {
// Check if it's socket connection
if (!req.isSocket) { return res.badRequest(); }
// label the room to ROOM_NAME
sails.sockets.join(req, ROOM_NAME);
/**
* Manage my `sails.rooms` HERE
* e.g.
*/
if (!sails.rooms[ROOM_NAME]) {
sails.rooms[ROOM_NAME] = {};
}
sails.rooms[ROOM_NAME][req.socket.id] = HUMAN_FRIENDLY_LABEL;
}
I end up with a JSON that looks like this:
{
{ "room1" :
{
"ksadj1234clkjnelckjna" : "john",
"eroiucnw934cneo3vra09" : "marie"
}
},
{ "room2" :
{
"kslaksdjfnasjdkfa9jna" : "antoine",
"qweuiqcnw934cne3vra09" : "michelle"
}
}
}
In config/sockets.js, I manage disconnections
afterDisconnect: function(session, socket, cb) {
console.log(socket.id + " disconnected");
/**
* Manage sails.rooms HERE
* e.g.
*/
for (r in sails.rooms) {
delete sails.rooms[r][socket.id];
//
// YOUR CODE
//
}
return cb();
},
NOTE: that you can list the WebSockets in a certain room using sails.io.sockets.in(ROOM_NAME). This should also help to purge the sails.rooms from disconnected sockets.

Resources