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

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.

Related

Retrieve Prismic slices content in Nuxtjs using GraphQL not working in project

When testing the query in the browser I can easily query slices but once in my project, when I try to query Prismic slices it all falls apart.
Packages: apollo-client, apollo-cache-inmemory, apollo-link-prismic
the query looks something like:
{
thepage(uid: "page", lang: "en-gb") {
page_title
page_description
body {
... on ThePageBodyHero {
type
fields {
title
description
button_text
button_link {
_linkType
}
}
}
}
}
}
this works in the interface but as soon as I add the slices section in the project the query returns a 404.
When using Apollo Client with Slices, you need to have a proper cache setup to resolve the slices. Meaning having a fragment matcher setup based on the introspection query to Prismic: https://www.apollographql.com/docs/react/advanced/fragments#fragment-matcher.
We planned to do it in the Prismic library for Apollo so people won't have to care about it no more.
In your case you got a 404 but it would be interesting to see who return a 404 because all the symptoms seem to lead to what I just explained.
Tell me if you got more info on your side ;)
In the meantime, here is a proper implementation: https://github.com/birkir/gatsby-source-prismic-graphql/blob/master/packages/gatsby-source-prismic-graphql/src/utils/getApolloClient.ts#L17

API formation for side loading only required associated data to ember data

Please check my previous question
EMBER JS - Fetch associated model data from back-end only when required
Related to the above question I need help on API formation in ruby on rails(JSON format: jsonapi.org)
how to form the API for sideloading only students.records and link with data already available in ember-data store (school and students)
based on the comments in the other question, I think you're wanting something like
GET /api/students?include=records
But you need that filtered to a school, which is where application-specific code can come in, as { json:api } does not dictate how filtering should happen
but, I've used this: https://github.com/activerecord-hackery/ransack with much success
So, your new query would be something like:
GET /api/students?include=records&q[school_id_eq]=1
to get all students and their records for the school with id 1
and then to make this query in ember:
store.query('student', {
include: 'records',
q: {
['school_id_eq']: 1
}
});
hope this helps

Using Odata to get huge amount of data

I have a data source provider :
public class DSProvider
{
public IQueryable<Product> Products
{
get
{
return _repo.Products.AsQueryable();
}
}
}
The repository in the above example currently gets ALL the records (of Products) from DB and then applies the filters, this just does not sound right if you had 50000 requests/sec from a website.How can you limit the repository to just return required info from DB without converting the service to a tightly coupled request option i.e. opposite of what you try to achieve by using oData?
So to summarize I would like to know if its possible to query the DB on the oData options supplied by the user so that my request does not always have to get all products and then apply filters of oData.
I found out after doing a small POC that Entity framework takes care of building dynamic query based on the request.

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.

REST API Design for Updating Object Graph

I'm designing a REST API and am looking for the recommended best practice for updating object graphs. My question is best explained in an example, so let's say that I have a GET resource as follows:
URI: /people/123
This URI returns an object graph like this:
{
"name":"Johnny",
"country":{"id":100,"name":"Canada"},
"likes":[
{"id":5,"name":"Fruit"},
{"id":100,"name":"Sports"}
]
}
When allowing the API consumer to update this resource, how would you expect the object to be updated via PUT or PATCH? Updating the "name" property is pretty straightforward, but I'm not certain about "country" or "likes", as the consumer can only only change the relationship to other objects and not create new ones.
Here is one way to request the update:
{
"name":"Bob",
"countryId":200
"likeIds":[3,10,22]
}
This update will change the resource to the following:
{
"name":"Bob",
"country":{"id":200,"name":"United States of America"},
"likes":[
{"id":3,"name":"Cars"},
{"id":10,"name":"Planes"},
{"id":22,"name":"Real Estate"}
]
}
This design explicitly and clearly asks the consumer to only update the "IDs" of the "Person", but I'm concerned that the object graph for a PUT/PATCH looks different than the GET, making the API hard to learn and remember. So another option is to request the PUT/PATCH as follows:
{
"name":"Bob",
"country":{"id":100},
"likes":[
{"id":3},
{"id":10},
{"id":22}
]
}
This will yield the same change as the previous update and does not alter the object graph. However, it doesn't make it clear to the API consumer that only the "IDs" can be updated.
In this scenario, which approach is recommended?
In my opinion you should stay with the same structure for both, GET and PUT requests. Why? Because it's quite common to map JSON/XML data into objects, and most (if not all) software that do the actual mapping work best if JSON schema is always the same.
So your webservice should accept a following JSON code:
{
"name":"Joe",
"country":{"id":200,"name":"United States of America"},
"likes":[
{"id":5,"name":"Fruit"}
]
}
However it doesn't have to take into account the country name and may focus only on the country id.