Giter Site home page Giter Site logo

spring-media / graphqlicious Goto Github PK

View Code? Open in Web Editor NEW
76.0 20.0 11.0 344 KB

A swift component with a DSL to declare GraphQL queries and to get string representations out of them

License: MIT License

Swift 90.27% Objective-C 3.32% Ruby 6.41%
graphql graphql-query swift dsl apps

graphqlicious's Introduction

GraphQLicious

GraphQLicious is a swift component that provides an intuitive and convenient way to build GraphQL queries and convert them easily to String representations.

[![iOS 8] (https://img.shields.io/badge/iOS%208%2B%20%7C%20MacOS%20X%2B%20%7C%20TV%20OS%20%7C%20Watch%20OS%202%2B-Compatible-brightgreen.svg)] ()

carthage cocoapods

swift3 license

travis codebeat codecov

Contents

Installation

Carthage

GraphQLicious supports Carthage. To install it, simply add the following line to your Cartfile

github "WeltN24/GraphQLicious"

CocoaPods

GraphQLicious is available through CocoaPods. To install it, simply add the following line to your Podfile

pod "GraphQLicious"

Submodule

If you don't use CocoaPods, you can still add GraphQLicious as a submodule, drag and drop GraphQLicious.xcodeproj into your project, and embed GraphQLicious.framework in your target.

  • Drag GraphQLicious.xcodeproj to your project
  • Select your app target
  • Click the + button on the Embedded binaries section
  • Add GraphQLicious.framework

Manual

You can directly drag and drop the needed files into your project, but keep in mind that this way you won't be able to automatically get all the latest features.
The files are contained in the Sources folder and work for the iOS framework

Usage

Query

Let's assume, we have the id of an article and we want to have the headline, body text and opener image of that article.

Our graphQL query for that will look like this:

query {
	test: content(id: 153082687){
		...contentFields
	}
}
fragment contentFields on Content {
	headline,
	body,
	image(role: "opener", enum: [this, that]){
		...imageContent
	}
}
fragment imageContent on Image {
	id
	url
}
fragment urlFragment on Image {
	 url (ratio: 1, size: 200) 
}

First, let's create a Fragment to fetch the contents of an image, namely the image id and the image url

let imageContent = Fragment(
	withAlias: "imageContent",
	name: "Image",
	fields: [
		"id",
		"url"
	]
)

Next, let's embed the Fragment into a Request that gets the opener image. Note: Argument values that are of type String are automatically represented with quotes. GraphQL also gives us the possibility to have custom enums as argument values. All you have to do is letting your enum implement ArgumentValue and you're good to go.

enum customEnum: String, ArgumentValue {
  case This = "this"
  case That = "that"
  
  private var asGraphQLArgument: String {
    return rawValue // without quotes
  }
}
    
let customEnumArgument = Argument(
  key: "enum",
  values: [
    customEnum.This,
    customEnum.That
  ]
)
let imageContentRequest = Request(
	name: "image",
	arguments: [
		Argument(key: "role", value: "opener"),
		customEnumArgument
	],
	fields: [
		imageContent
	]
)

So now we have a Request with an embedded Fragment. Let's go one step further.
If we want to, we can imbed that Request into another Fragment. (We can also embed Fragments into Fragments)
Additionally to the opener image with its id and url we also want the headline and body text of the article.

let articleContent = Fragment(
	withAlias: "contentFields",
	name: "Content",
	fields: [
		"headline",
		"body",
		imageContentRequest
	]
)

Finally, we put everything together as a Query. A Query always has a top level Request to get everything started, and requires all the Fragments that are used inside.

let query = Query(request: Request(
	withAlias: "test",
	name: "content",
	arguments: [
		Argument(key: "id", values: [153082687])
	],
	fields: [
		articleContent
	]),
	fragments: [articleContent, imageContent]
)

All we have to do now is to call create() on our Query and we're good to go.

print(query.create())

Mutation

Let's assume, we want to change our username and our age in our backend and we want to have the new name and age back to make sure everything went right.

Let's assume further, our server provides a mutating method editMe for exactly that purpose.

Our graphQL query for that will look like this:

mutation myMutation {
	editMe(
		name: "joe",
		age: 99
	)
	{
		name,
		age
	}
}

Let us first create the actual mutating function. We can use a Request for that. As Argument values we give information about which fields should be changed and what's the actual change

let mutatingRequest = Request(
      name: "editMe",
      arguments: [
      	Argument(name: "name", value: "joe"),
        Argument(name: "age", value: 99)
      ],
      fields: [
        "name",
        "age"
      ]
    )

Finally, we put everything together as a Mutation.

Mutations work just like Queries

let mutation = Mutation(
	withAlias: "myMutation",
	mutatingRequest: mutatingRequest
)

After we've done that we can create the request.

print(mutation.create())

Breaking changes

From 0.7 to 0.8

  • ReadingRequest is now simply Request
  • MutatingRequest has been removed, you can use Request instead
  • MutatingArgument has been removed, you can use Argument instead
  • MutatingValue and MutatingField have been removed, you can use Argument, or ObjectValue and ObjectKeyValuePair instead

Authors

GraphQLicious was made in-house by WeltN24

Contributors

Felix Dietz, [email protected], @podboq (@joemcbomb) on Github, @joemcbomb on Twitter

Vittorio Monaco, [email protected], @vittoriom on Github, @Vittorio_Monaco on Twitter

License

GraphQLicious is available under the MIT license. See the LICENSE files for more info.

graphqlicious's People

Contributors

flyingbear66 avatar joemcbomb avatar ludoded avatar podboq avatar toupper avatar vittoriom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphqlicious's Issues

How to do variables?

Hey guys,

I've tried the library and it works well so far. However now I need to build a query with variables. Is there any support for this?

cocoapods seems out of date

Installing through cocoapods and trying to build brings forth a slew of errors, like 'SequenceType' has been renamed to 'Sequence', and 'Use of undeclared type 'Generator''

How to send the query to a GraphQL server?

I'm trying to post a query using AFNetworking to my GraphQL server but i'm wondering how I would go about sending a query to a GraphQL server if it expects a JSON based request like this
{ query: "feed(type: BY_VOTES) { title } " }

Since your library creates a query string like this:
query { feed(type: BY_VOTES) { title } }

Is there someway I could go about this or is there something i'm missing?

Issue while generating the debug description

There seems to be an issue while generating a debug description for a query with fragments inside fragments. The query itself seems to be working fine it is just the debug description what is failing.

So I created a protocol to help me organize better the queries code like:

protocol FragmentProvider {
  var fragment: Fragment { get }
  var subfragments: [Fragment] { get }
}

fragment property contains the fragment itself and subfragments any other fragments used by fragment

A FragmentProvider implement could have fragment like the following:

lazy var fragment: Fragment = { [unowned self] in
    return Fragment(
      withAlias: "articleFragment",
      name: "Content",
      fields: [
        "id"
        self.images
      ])
  }()

where self.images is a Fragment

lazy var fragment: Fragment = { [unowned self] in
    return Fragment(
      withAlias: "imagesFragment",
      name: "Content",
      fields: [
        Request(
          name: "Image",
          arguments: [
            Argument(key: "role", value: "")
          ],
          fields: [
            self.allImagesFragment
          ]
        )
      ])
  }()

The subfragment:

lazy var subfragments: [Fragment] = { [unowned self] in
    return [
      self.fragment,
      self.images,
      self.allImagesFragment
    ]
  }()
lazy var allImagesFragment: Fragment = { [unowned self] in
    return Fragment(
      withAlias: "imageFieldsFragment",
      name: "Image",
      fields: [
        "id",
        Request(
          withAlias: "square",
          name: "url",
          arguments: [
            Argument(key: "ratio", value: "1"),
            Argument(key: "size", value: "500")
          ]
        ),
        Request(
          withAlias: "standard",
          name:"url",
          arguments: [
            Argument(key: "ratio", value:"1.777"),
            Argument(key: "size", value:"500")
          ]
        )
      ])
  }()

And finally the full query:

private let article: FragmentProvider = ...
let query = Query(withRequest: Request(
      name: "search",
      arguments: [
        ...
      ],
      fields: [
        article.fragment
      ]),
      fragments: article.subfragments
    )

The result of the description formatted incorrectly is:

{
     search (section: "/politik/",limit: 10,type: TextArticle) {
        ...articleTeaserFragment
    }
}
fragment videosFragment on Content {
     videos (role: opener) {
        id,
        poster{...imageFieldsFragment}
    }
}
fragment galleriesFragment on Content {
     galleries (role: opener) {
        id,
        images{...imageFieldsFragment}
    }
}
fragment imagesFragment on Content {
     images (role: opener) {
        ...imageFieldsFragment
    }
}
fragment articleTeaserFragment on Content {
    id,
    type,
    topic,
    headline,
    intro,
    publicationDate,
    fragment videosFragment on Content {
     videos (role: opener) {
        id,
        poster{...imageFieldsFragment}
    }
}
,
    fragment galleriesFragment on Content {
     galleries (role: opener) {
        id,
        images{...imageFieldsFragment}
    }
}
,
    fragment imagesFragment on Content {
     images (role: opener) {
        ...imageFieldsFragment
    }
}

}
fragment imageFieldsFragment on Image {
    id,
    caption,
    square: url (ratio: 1,size: 200) ,
    standard: url (ratio: 1.777,size: 500) 
}

Possibility of using this API in an objective-c environment

Currently I have an objective-c based project and i'd like use it in my project. I know I can't work with swift structs and enums (unless it's strictly of type int). So i'm wondering how would I go about using this API in my objective-c project?

Escaping string

For example, content is the user input string,when input Test\n

{
	"query": "mutation {saveMsg(reviewId: \"57c3f20a361345e24de9163f\",content: \"Test\n\")}"
}

Response error:

{
	"errors": [null],
	"msg": "Syntax Error GraphQL request (1:70) Unterminated string.\n\n1: mutation {saveMsg(reviewId: \"57c3f20a361345e24de9163f\",content: \"Test\n                                                                        ^\n2: \")}\n",
	"ok": false
}

Can't import, can't use

Hey,

I can't use the library when I install it. I can't import it even use it

capture d ecran 2016-10-20 a 13 54 22

XCode 8.0 / iOS 10

its not full

please can you add full guide line please

like

  1. add server side link login
  2. registration by mutations

Apollo
let apollo = ApolloClient(url: URL(string: "http://localhost:3000/api")!)

Update Pod to v0.7

Hey,

please update the pod so the implemented mutation functionality from #9 will be available in the latest pod. Currently this is still missing.

Cheers,
David

Is it possible to pass an Array of integers as a mutating field?

I have a GraphQL schema that has a GraphQL input object type that has describes an Array of Integers as part of its fields:

input addSequenceInput {
   userID: ID!
   commandSequenceTitle: String!
   commandSequenceDescription: String
   commands: [Int]
  }

How can I craft a GraphQL mutation query that accepts an array of integers as a mutating field:

func createToDoList(someList: [Int]) -> String{

        let mutatingFieldCommands = MutatingField(name: "commands", value:someList);

        let mutatingRequest = MutatingRequest(
            // Name of the mutation registered at our GraphQL server
            mutationName: "createToDoList",
            // The Argument that our the mutation takes
            mutatingArgument:
            MutatingArgument(
                key: "input",
                mutatingValue: MutatingValue(
                    withFields: [
                        mutatingFieldCommands
                    ] 
                )),
            responseFields: [
                "id",
                "listitem",
            ]
        );

        let mutation = Mutation(
            mutatingRequest: mutatingRequest
        );

        print(mutation.create())
        debugPrint(mutation)

        return mutation.create();
    }
} 

Add support for Bool format

Field.swift
extension Bool: Field { public var asGraphQLString: String { return description } }

ArgumentValue.swift
extension Bool: ArgumentValue { public var asGraphQLArgument: String { return asGraphQLString } }

Syntax Change

Hey, I can't figure out how to do something like this with the new syntax:

mutation myMutation {
    editMe(id: 1, input: {
        name: "joe",
        age: 99
    })
    {
        name,
        age
    }
}

I noticed we were able to do something similar with the old syntax, but I just can't figure out how to do it with the new syntax.

Here's how I'm currently trying to do it:
screen shot 2016-09-03 at 1 58 36 pm

And here's the old way:

let mutatingRequest = MutatingRequest(
      mutationName: "editMe",
      mutatingArgument:
      MutatingArgument(
        key: "input",
        mutatingValue: MutatingValue(
          withFields: [
            MutatingField(name: "name", value: "joe"),
            MutatingField(name: "age", value: 99)
          ]
        )),
      responseFields: [
        "name",
        "age"
      ]
    )

Thanks for the help!

Missing quotes on GraphQLString args

Any query with a string argument would be missing quotations when the graphQL readable string is created.

Example Query

func getSomething (id: String) -> Query {
    return Query(
        withRequest: Request(
            withAlias: "",
            name: "getSomething",
            arguments: [
                Argument(key: "id", value: **id**)
            ],
            fields: [
              _omitted_
            ]
        )
    )
}

Would output

{
  getSomething(id: **idWithoutQuotes**) {
    _omitted_
  }
}

In Argument.swift, changing case 1 of the GraphQLConvertible extension to check if the value[0] is String and returning a string with quotes around the value fixes it for my use cases.

The original line
return "\(key): \(values[0].asGraphQLString)"

The replacement

if values[0] is String {
    return "\(key): \"\(values[0].asGraphQLString)\""
} else {
    return "\(key): \(values[0].asGraphQLString)"
}

Carthage build not working because Sample is requiring provisioning profile

I got this when trying to build with carthage

`** BUILD FAILED **

The following build commands failed:
Check dependencies
(1 failure)
A shell task failed with exit code 65:
** BUILD FAILED **`

I forked your Repo, removed sample in my fork and used Carthage on it and it worked, so the missing provisioning profile is the key,

PS: I'll will soon use your lib in our app Swapcard, that's a really cool lib, would be happy to contribute if I find something useful :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.