-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrapping a REST API in GraphQL #379
Comments
Seems easier than I expected: Custom network interface |
Yep, that's it! Very similar to the Relay approach. |
Great, I'm currently seeking for this. @dalgard Have you tried it yet? |
By the way, if someone wants to write a post about this it would be awesome! |
@linonetwo Not yet. Don't know whether I'm going to need it within the next couple of months. Still interested, though! |
OK I'm trying it... what can be inferred from apollo's docs is just: import { addQueryMerging } from 'apollo-client';
class REST2GraphQLInterface {
query({ query, variables, debugName }) {
return Promise.resolve({ data: {}, errors: [{ code: 0, msg: 'errorMsg' }] });
}
}
export default addQueryMerging(REST2GraphQLInterface); I need to refer to relay's doc for further implementation examples... |
So I don't need a 「graphql」 package, instead a 「graphql-tool」 at the client side? |
Well, I think writing REST2GraphQL on the client side is much similar to what we usually wrote on the server side. The only difference is that we use the connector to get data from database usually, now we use the connector to get data from REST endpoint. I'm not sure whether I'm on the right path or not. |
@linonetwo you're definitely on the right path. What you are basically doing is writing a "GraphQL server", but on the client, so any of the GraphQL server docs will apply. You don't need |
Thanks for guiding. Another question: One REST endpoint would give me tons of data. Typically if I want to fill in blanks for this type; # /api/account/whoami
type User {
login: Boolean!
username: String!
password: String!
id: Int!
name: String!
companyId: Int
companyName: String
departmentId: Int
departmentName: String
role: String
} I will write resolver functions, each will just getting small piece of data. {
"code": 0,
"data": {
"companyId": 1,
"companyName": "Company1",
"departmentId": 1,
"departmentName": "工程部",
"id": 7,
"name": "用户3",
"role": "Customer",
"username": "Customer3"
}
} which covers many of fields of User type. should I still write resolving functions for every field? I think I can cache data inside connector. {
"code": 0,
"data": {
"companyId": 1,
"companyName": "Company1",
"departmentId": 1,
"departmentName": "工程部",
"id": 7,
"name": "用户3",
"role": "Customer",
"username": "Customer3"
}
} and I only need But it looks redundantly with apollo-client 's client side cache. So my opinion is to simulate the batching again here. If two queries come together within 10ms, second one will hit the cache. Another option is caching at Model level and use graphQL decorator or so, to pass an 'force fetch' argument to this level. In this way, "client side server" 's caching won't be obscure to user. Which way is better still need experiment. |
I will write a post after this... I'm currently using「graphql」package to parse executeableSchema like this: const executableSchema = makeExecutableSchema({
typeDefs: schema,
resolvers,
});
class REST2GraphQLInterface {
query({ query, variables }) {
return graphql(
executableSchema,
query,
undefined, // should be rootValue here, I don'k know what its used for
{
Config: new Config({ connector: serverConnector }),
User: new User({ connector: serverConnector }),
},
variables
);
}
}
export default addQueryMerging(new REST2GraphQLInterface()); And it doesn't work, throwing Maybe executableSchema is not what it wants? |
What is |
Also, you don't need to write resolvers like |
OK, My only reference is GitHunt... Learnt from it :
that Are there any edge case learning material? |
Note that We're probably going to write a complete GraphQL server guide in the future, but it's not our top priority right now. |
I found that there were lots of posts on the Medium written by your team, which are extremely useful for beginners.Thank you guys! But were they be linked or merged to docs, I won't spending so much time learning and experimenting it... Now building a wrapping for RESTful endpoint is a very easy job, I'm almost done. |
I have my try to make it my experiment repo though my writing of resolver is kind of verbose... |
(I record my research path here just for indexing reference, providing help for who need it.) @stubailo You mentioned that I can call executableSchema via the graphql( ) function from the graphql package, I'm doing it like this: // http://dev.apollodata.com/core/network.html#NetworkInterface
class REST2GraphQLInterface {
query({ query, variables }) {
console.log(executableSchema); // GraphQLSchema {_queryType: GraphQLObjectType, _mutationType: GraphQLObjectType, _subscriptionType: null, _directives: Array[3], _typeMap: Object…}
console.log(query); // Object {kind: "Document", definitions: Array[1]}
console.log(variables); // I'm not using it currently
return graphql(
executableSchema,
query,
undefined,
{
Config: new Config({ connector: serverConnector }),
User: new User({ connector: serverConnector }),
PowerEntity: new PowerEntity({ connector: serverConnector }),
FortuneCookie: new FortuneCookie(),
},
variables
);
}
} But query it will throw out Relay have a different NetworkInterface from Apollo, It has sendMutation(mutationRequest), sendQueries(queryRequests), supports(...options) . While Apollo use single query(request: GraphQLRequest): Promise. But I believe @stubailo is right, since graphql( ) receives these arguments... Oh! I found it! The
How I can convert queryTransformer: addTypename,
shouldBatch: true, from |
Ok, I made it on the react-native side, in production! I will link my blog post here later. So, @dalgard Apollo is proved to be capable of wrapping REST endpoint, on the server side, on the client side, and on the react-native side! : D |
@linonetwo I would love to see an English version of that post! |
@Urigo Ok, I'm working on that, please wait for a while. |
@Urigo http://onetwo.ren/wrapping-restful-in-graphql/ Were there any bug or issue please point out. Any question, ask me and I will add some content. But what I want to say is that
|
I've being working on a project with apollo-client/server both on the browser wrapping a rest api. I works smoothly, with File upload support, Apollo client dev tools working properly, etc, etc. I'm working on a post in portuguese, but I guess I can make a copy in english and put in on Medium or similar. Does anyone have a better or more contextualized place to publish it, in case it fits? |
@lucasconstantino Medium sounds great. |
For anyone else stumbling across this you might like to check out https://github.com/mstn/apollo-local-network-interface |
Looks like the approach with Apollo 2.0 is different with the "link" approach replacing network interfaces. Here's how I personally got my plain old import { Observable, ApolloLink, execute, makePromise } from 'apollo-link'
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { graphql, print } from 'graphql'
import schema from './schema' // should be an instance of GraphQLSchema
const link = new ApolloLink(
operation =>
new Observable(observer => {
const { query, variables, operationName } = operation
graphql(schema, print(query), {}, {}, variables, operationName)
.then(result => {
observer.next(result)
observer.complete(result)
})
.catch(e => observer.error(e))
}),
)
const cache = new InMemoryCache()
// Note: if your schema contains interfaces / union types, ApolloClient can't infer possibleTypes out-of-the-box
// You'll have to let it know manually via a fragmentMatcher. For example:
// const cache = new InMemoryCache({
// fragmentMatcher: new IntrospectionFragmentMatcher({
// introspectionQueryResultData: {
// __schema: {
// types: [{
// kind: 'INTERFACE',
// name: 'Either',
// possibleTypes: [
// { name: 'Left' },
// { name: 'Right' },
// ]
// }]
// }
// },
// }),
// })
const client = new ApolloClient({ link, cache }) |
Here's an example for Apollo client 2.0: |
The article Wrapping a REST API in GraphQL describes how to use a client-side schema to resolve queries against a REST endpoint.
The schema is inserted as a network layer in Relay – can something similar be achieved with Apollo Client?
The text was updated successfully, but these errors were encountered: