How to search multiple api services - api

I am developing a search engine with angular 2.
Therefore I use APIs from multiple platforms.
It works if I call the search function from every api service manually.
But is it possible to do the same foreach api service?
Every api service has the same function:
search (query: string): Observable<Array<SearchResult>> { ... }
In the UI I want to separate the results by tabs.
Therefore every api service has a title:
public title: string = "the title";
For storing the search results locally I have a class that is extended by every api service. This class has helper functions etc.

Depending on the behaviour you need you can use merge, concat or forkJoin to merge multiple streams into one.
The code would look pretty much the same.
For example using merge in order to merge 2 streams into one.
If you have a list of apis you need to call for the search. Your code would look like this.
let apis: string[] = [];
let observables = apis.map(api => search(api)); // get an array of observables
let merged = observables.reduce((previous, current) => previous.merge(current), new EmptyObservable()); // merge all obserbable in the list into one.
merged.subscribe(res => doSomething(res));
This article might be helpful.

Related

How can I get and use the properties I need from this GraphQL API using Dart?

Before you start reading: I have looked at the GraphQL documentation, but my usecase is so specific and I only need the data once, and therefore I allow myself to ask the community for help on this one to save some time and frustration (not planning to learn GraphQL in the future)
Intro
I am a CS student developing an app for Flutter on the side, where I need information about the name and location of every bus stop in a specific county in Norway. Luckily, there's an open GraphQL API for this (API URL: https://api.entur.io/stop-places/v1/graphql). The thing is, I don't know how to query a GraphQL API, and I do not want to spend time learning it as I am only going to fetch the data once and be done with it.
Here's the IDE for the API: https://api.entur.io/stop-places/v1/ide
And this is the exact query I want to perform as I want to fetch bus stops located in the county of Trondheim:
{
stopPlace(stopPlaceType: onstreetBus, countyReference: "Trondheim") {
name {
value
}
... on StopPlace {
quays {
geometry {
coordinates
}
}
}
}
}
The problem with this query though, is that I don't get any data when passing "Trondheim" to the countyReference (without countyReference I get the data, but not for Trondheim). I've tried using the official municipal number for the county as well without any luck, and the documentation of the API is rather poor... Maybe this is something I'll have to contact the people responsible for the API to figure out, which shouldn't be a problem.
But now back to the real problem - how can I make this query using the GraphQL package for Dart? Here's the package I'm planning to use: (https://pub.dev/packages/graphql)
I want to create a bus stop object for each bus stop, and I want to put them all in a list. Here is my bus stop model:
class BusStop with ChangeNotifier {
final String id;
final String name;
final LatLng location;
BusStop({
this.id,
this.name,
this.location
});
}
When it comes to authentication, here's what the documentation says:
This API is open under NLOD licence, however, it is required that all consumers identify themselves by using the header ET-Client-Name. Entur will deploy strict rate-limiting policies on API-consumers who do not identify with a header and reserves the right to block unidentified consumers. The structure of ET-Client-Name should be: "company - application"
Header examples: "brakar - journeyplanner" "fosen_utvikling - departureboard" "norway_bussekspress - nwy-app"
Link to API documentation: https://developer.entur.org/pages-nsr-nsr
Would be great to know how I should go about this as well! I'm grateful for every answers to this, I know I am being lazy here as of learning GraphQL, but for my usecase I thought it would take less time and frustration by asking here!
Getting the query right
First of all you seem to have GraphQL quite figured out. There isn't really much more to it than what you are doing. What queries an API supports depends on the API. The problem you seem to have is more related to the specific API that you are using. I might have figured the right query out for you and if not I will quickly explain what I did and maybe you can improve the query yourself:
{
stopPlace(stopPlaceType: onstreetBus, municipalityReference: "KVE:TopographicPlace:5001") {
name {
value
}
... on StopPlace {
quays {
geometry {
coordinates
}
}
}
}
}
So to get to this I started finding out more about "Trondheim" bei using the topographicPlace query.
{
topographicPlace(query: "Trondheim") {
id
name {
value
}
topographicPlaceType
parentTopographicPlace {
id
name {
value
}
}
}
}
If you do that you will see that "Trondheim" is not a county according to the API: "topographicPlaceType": "municipality". I have no idea what municipality is but the is a different filter for this type on the query that you provided. Then putting "Trondheim" there didn't yield any results so I tried the ID of Trondheim. This now gives me a bunch of results.
About the GraphQL client that you are using:
This seems to be an "Apollo Client" clone in Dart. Apollo Client is a heavy piece of software that comes with a lot of awesome features when used in a frontend application. You probably just want to make a single GraphQL request from a backend. I would recommend using a simple HTTP client to send a POST request to the GraphQL API and a JSON body (don't forget content type header) with the following properties: query containing the query string from above and variables a JSON object mapping variable names to values (only needed if you decide to add variables to your query.

Designing of a RESTful API endpoint filter and search

I am in the process of developing some custom API endpoints (using loopback.io), on top of its existing CRUD endpoints.
In the past I've used some other Node RESTful API frameworks for prototyping, and really enjoyed the powerful filtering features they provide out of the box.
What I'd like to do is provide a similar set (or subset) of some kind of filtering for a custom endpoint. The endpoint just does a SQL query (with some JOINs) and returns an array of objects.
Is there any kind of standardized approach that I should use to design some filtering? For example, I may want to filter on fields of the base table, or filter on relations. I like the way loopback.io and sequelize allow relatively easy specification of includes to link related objects, as well as their filtering syntax.
How is this type of problem usually approached when a custom implementation is done?
As you probably noticed with CRUD endpoints, LoopBack provides querying out of the box via filter parameter. You can nicely experiment with it in API Explorer. If you want to expose querying for a custom remote method, just add filter as a parameter too.
example-model.js
module.exports = ExampleModel => {
const search = async (filter = {}) => {
return await ExampleModel.find(filter)
}
ExampleModel.remoteMethod('search', {
description: 'Returns a set of ExampleModel based on provided query.',
accepts: [
{arg: 'filter', type: 'object', required: false}
],
http: {path: '/search', verb: 'get'},
returns: {root: true}
})
ExampleModel.search = search
}

Kendo grid server side grouping

I am using Asp net 5, NHibernate 3.3 and Kendo UI MVC wrapper for grid to render the table of client orders. There are lots of orders in database already and the number is constantly growing. So I decided to use server side paging to avoid fetching all orders from database. As far as I know you can't do paging manually and delegate filtering, sorting and grouping to ToDataSourceResult method. It's either all or nothing. Therefore I made an attempt to implement so called 'custom binding'. No problem until I get to grouping. I need to group first, then sort inside of a group, then extract data for specific page and all that without loading all data to memory. My code is something like this (I put it all in one piece to simplify reading):
var orderList = CurrentSession.QueryOver<Order>();
// Filtering. Filter is a search string obtained from DataSourceRequest
var disjunction = new Disjunction();
disjunction.Add(Restrictions.On<Order>(e => e.Number).IsLike("%" + filter + "%"));
disjunction.Add(Restrictions.On<Order>(e => e.Customer).IsLike("%" + filter + "%"));
orderList = orderList.Where(disjunction);
// Sorting. sortColumn is also from DataSourceRequest
switch (sortColumn)
{
case "Number":
orderList = orderList.OrderBy(x => x.Number).Desc;
break;
case "GeneralInfo.LastChangeDate":
orderList = orderList.OrderBy(x => x.LastChangeDate).Desc;
break;
default:
orderList = orderList.OrderBy(x => x.Number).Desc;
break;
}
}
// Total is required for kendo grid when you do paging manually
var total = orderList.RowCount();
var orders = orderList
.Fetch(x => x.OrderGoods).Eager
.Fetch(x => x.OrderComments).Eager
.Fetch(x => x.Documents).Eager
.Fetch(x => x.Partner).Eager
.Skip((request.Page - 1)*request.PageSize).Take(request.PageSize).List();
I will be glad to have any advice on how to add grouping here.
I worked for literally months to figure out server-side grouping using the Kendo DataSource with a Kendo Grid. Paging, sorting and filtering were fairly easy. But for whatever reason, Telerik did not offer sufficient support documentation for such a critical LOB process as grouping. I’m glad you posted this question so I’d have an opportunity to share my code.
The Solution
Basically, the solution comes down to knowing 2 key parts, and they can be viewed in the following sample project: https://www.dropbox.com/s/ygtk8rwl1hwjvth/KendoServerGrouping.zip?dl=0
There is a single web application project in the Visual Studio (2012 | 2013) solution you’re downloading, which contains a reference to the Kendo.Mvc library. You can download the latest UI for ASP.NET binaries from Telerik's Control Panel installation program. The binaries will be located in the following Windows directory after install: C:\Program Files (x86)\Telerik\UI for ASP.NET MVC [Telerik Release Version]\wrappers\aspnetmvc\Binaries\ [Your Version of MVC]\Kendo.Mvc.dll.
Note: My solution uses Telerik’s MVC transport mechanism, which provides full-fledged server-side paging, filtering, sorting and, most notably, grouping. However, I use pure JavaScript to configure the Kendo DataSource and not the MVC wrappers. Still, I've recently found a link in Telerik's documentation that shows the MVC wrapper declaration in Razor/ASPX.
The Server Magic
Basically, the first part of the magic is the following server side code, residing in the sample WebApi controller in the KendoServerGrouping.Web\Controllers directory:
[System.Web.Http.AcceptVerbs("GET", "ASPNETMVC-AJAX")]
public Kendo.Mvc.UI.DataSourceResult GetAllAccounts([System.Web.Http.ModelBinding.ModelBinder(typeof(WebApiDataSourceRequestModelBinder))] Kendo.Mvc.UI.DataSourceRequest request)
{
var kendoRequest = new Kendo.Mvc.UI.DataSourceRequest
{
Page = request.Page,
PageSize = request.PageSize,
Filters = request.Filters,
Sorts = request.Sorts,
Groups = request.Groups,
Aggregates = request.Aggregates
};
// Set this to your ORM or other data source
IQueryable accounts = dbContext.Accounts;
/*
The data source can even be a MongoDB collection using the
.AsQueryable() extension and the MongoDB C# driver
var accounts = collection.FindAllAs<Account>().AsQueryable();
*/
var data = accounts.ToDataSourceResult(kendoRequest);
var result = new DataSourceResult()
{
AggregateResults = data.AggregateResults,
Data = data.Data,
Errors = data.Errors,
Total = data.Total
};
return result;
}
This is all you’ll need for any of the four server-side actions that the grid will handle auto-magically when the user interacts with it. Pay special attention to the AcceptVerbs attribute above the method; it must include the “ASPNETMVC-AJAX” attribute for the DataSourceRequest input parameter to work properly. ToDataSourceResult() is an extension provided by recent versions of the Kendo.Mvc.dll library, which I pointed to earlier.
The code above will (to my knowledge) work with any IQueryable data source, such as those from ORMs (I've tested Entity Framework and Telerik Data Access/Open Access). I've also been able to group a MongoDB collection using the MongoDB C# driver. However, this is meant as a proof-of-concept, and it has not been tested for performance.
For the purposes of this example, there is static data source in the WebAPI controller to fake an IQueryable collection. Naturally, you can delete the static data from lines 45-57 when you've swapped in your own data source.
The Client Magic
The Kendo DataSource automatically passes in a specialized DataSourceRequest object from the grid containing all the parameters for server-side paging, filtering, sorting and grouping, provided you wrap your DataSource schema inside the following JavaScript:
schema: $.extend(true, {}, kendo.data.schemas["aspnetmvc-ajax"], {
});
This was perhaps the single most elusive line of code I’ve ever tracked down. It took about a dozen exchanges with Telerik over several months to get them to cough it up. And even then, it was by pure chance that it was revealed. Why such a critical nuance was absent in their documentation is beyond me.
Carefully review each of the Kendo DataSource configuration settings toward the bottom half of index.html file. Most importantly, pay attention to what isn’t there, such as the batch and mvcTransport options. Including the latter option somehow negates the above “aspnetmvc-ajax” schema attribute.
In the DataSource's parmaterMap function, make note that when – and only when - performing a read operation, the following line must be present:
return mvcTransport.parameterMap(options, operation);
You will also want to be sure to include this in your HTML, before the DataSource executes:
<script src="//cdn.kendostatic.com/[Version]/js/kendo.aspnetmvc.min.js"></script>
The End Result
Run the KendoServerGrouping.Web project (index.html) and, if all goes well, a grid will be populated with 5 records containing AccountId, AccountName, AccountTypeCode and CreatedOn fields. If you set the number of visible grid rows to 2 and group by AccountTypeCode or CreatedOn, you’ll see that the grouping traverses the paging, which I believe is the end result you are looking for.
I hope the sample project works and is a good fit for your situation. Please let me know if you have any questions, and I’ll do my best to help.
P.S. This is my first post to SO, so please go easy on me if something isn’t up to SO standards. Good luck!
I would like to add onto #aaron-jessen answer with this jewel I found on Telerik's forums:
$("#grid").kendoGrid({
dataSource: {
type: "aspnetmvc-ajax", // If missing may cause NULL values in ApiController
}
})

CodeIgniter Rest API (Phil Sturgeon) - How to chop up a very large api file

I have been building a rest api (using Phil Sturgeons Codeigniter-Restserver) and Ive been sticking closely to the tutorial at:
http://net.tutsplus.com/tutorials/php/working-with-restful-services-in-codeigniter-2/
in particular Ive been paying attention to this part of the tutorial:
function user_get()
{
// respond with information about a user
}
function user_put()
{
// create a new user and respond with a status/errors
}
function user_post()
{
// update an existing user and respond with a status/errors
}
function user_delete()
{
// delete a user and respond with a status/errors
}
and Ive been writing the above functions for each database object that is accessible by the api, and also:
function users_get() // <-- Note the "S" at the end of "user"
{
// respond with information about all users
}
I currently have approximately 30 database objects (users, products, clients, transactions etc), all of which have the above functions written for them, and all functions are dumped into /controllers/api/api.php, and this file has now grown to be quite large (over 2000 lines of code).
QUESTION 1:
Is there a way to split this api file up, into 30 files for example, and keep all api functions relating to a single database object in a single place, rather than just dumping all api functions into a single file?
QUESTION 2:
I would also like to keep a separation between my current model functions (non-api related functions) and the functions that are used by the api.
Should I be doing this?
Is there a recommended approach that I should use here? For example should I write separate models that are used by the api, or is ok to keep all model functions (both non-api functions, and api functions) for a given database object in the same file?
Any feedback or advice would be great..
You can create api controllers the same way you do regular controllers; you can do the same with models.
application/controllers/api/users.php
class Users extends REST_Controller{
function user_post(){
$this->users_model->new_user()
...
POST index.php/api/user
--
application/controllers/api/transactions.php
class Transactions extends REST_Controller{
function transaction_get(){
$this->transactions_model->get()
...
GET index.php/api/transaction
I would also like to keep a separation between my current model functions (non-api related functions) and the functions that are used by the api.
I don't see why you couldn't use the same methods so long as they return what you need.

RESTful API - How do I return different results for the same resource?

Question
How do I return different results for the same resource?
Details
I have been searching for some time now about the proper way to build a RESTful API. Tons of great information out there. Now I am actually trying to apply this to my website and have run into a few snags. I found a few suggestions that said to base the resources on your database as a starting point, considering your database should be structured decently. Here is my scenario:
My Site:
Here is a little information about my website and the purpose of the API
We are creating a site that allows people to play games. The API is supposed to allow other developers to build their own games and use our backend to collect user information and store it.
Scenario 1:
We have a players database that stores all player data. A developer needs to select this data based on either a user_id (person who owns the player data) or a game_id (the game that collected the data).
Resource
http://site.com/api/players
Issue:
If the developer calls my resource using GET they will receive a list of players. Since there are multiple developers using this system they must specify some ID by which to select all the players. This is where I find a problem. I want the developer to be able to specify two kinds of ID's. They can select all players by user_id or by game_id.
How do you handle this?
Do I need two separate resources?
Lets say you have a controller name 'Players', then you'll have 2 methods:
function user_get(){
//get id from request and do something
}
function game_get(){
//get id from request and do something
}
now the url will look like: http://site.com/api/players/user/333, http://site.com/api/players/game/333
player is the controller.
user/game are the action
If you use phil sturgeon's framework, you'll do that but the url will look like:
http://site.com/api/players/user/id/333, http://site.com/api/players/game/id/333
and then you get the id using : $this->get('id');
You can limit the results by specifying querystring parameters, i.e:
http://site.com/api/players?id=123
http://site.com/api/players?name=Paolo
use phil's REST Server library: https://github.com/philsturgeon/codeigniter-restserver
I use this library in a product environment using oauth, and api key generation. You would create a api controller, and define methods for each of the requests you want. In my case i created an entirely seperate codeigniter instance and just wrote my models as i needed them.
You can also use this REST library to insert data, its all in his documentation..
Here is a video Phil threw together on the basics back in 2011..
http://philsturgeon.co.uk/blog/2011/03/video-set-up-a-rest-api-with-codeigniter
It should go noted, that RESTful URLs mean using plural/singular wording e.g; player = singular, players = all or more than one, games|game etc..
this will allow you to do things like this in your controller
//users method_get is the http req type.. you could use post, or put as well.
public function players_get(){
//query db for players, pass back data
}
Your API Request URL would be something like:
http://api.example.com/players/format/[csv|json|xml|html|php]
this would return a json object of all the users based on your query in your model.
OR
public function player_get($id = false, $game = false){
//if $game_id isset, search by game_id
//query db for a specific player, pass back data
}
Your API Request URL would be something like:
http://api.example.com/player/game/1/format/[csv|json|xml|html|php]
OR
public function playerGames_get($id){
//query db for a specific players games based on $userid
}
Your API Request URL would be something like:
http://api.example.com/playerGames/1/format/[csv|json|xml|html|php]