Tutorial: Transform a REST API to GraphQL

Create a GraphQL API for REST interfaces by letting API Connect for GraphQL introspect the REST endpoint and generate a GraphQL schema.

This tutorial shows how to use the stepzen import curl command on an existing REST API. This command sends a curl request to API Connect for GraphQL and parses the GraphQL types from the JSON response.

Working with GET requests

Use the API Connect for GraphQL CLI to create a GraphQL schema for your new GraphQL API. Complete the following steps to perform this process using our example customers API:

Generate your schemas and resolvers using the following API Connect for GraphQL CLI command:

stepzen import curl https://introspection.apis.stepzen.com/customers --query-name "customers" --query-type "Customer" --name "customers"

Let's take a look at what the stepzen import curl command does:

  1. API Connect for GraphQL issues the curl call (we support most, but not all, curl flags, as explained in the following section).

  2. It converts the returned JSON into a set of GraphQL types.

    The root of the returned JSON was given a special name, in this CustomerEntry, based on the query-type flag. This flag is optional, but it is good to give a meaningful name for the root because otherwise, API Connect for GraphQL will name it RootEntry.

    If you execute two different stepzen import curl commands, the RootEntry will be a type name clash. Other types get fairly good names based on the name in the JSON structure. If you are worried about type name clashes on them, you can use a --prefix flag (more on that later).

  3. It then generates a query with the value of the --query-name flag so that when you execute the query, it will parse the returned JSON into the correct GraphQL structure.

    While this flag is optional, it is highly recommended because otherwise, the default name would be myQuery, and not only is it not a great name, it will clash with any subsequent stepzen import curl commands that you run.

  4. It stores the generated schema in a directory with the name given in name flag. It is optional, and it will create a directory that starts with curl (for the first one, and curl-01 etc., for each subsequent stepzen import curl command).

  5. It creates an index.graphql in the root of your working directory containing the path to which the schema file is generated.

Just one command did all this for you!

Using curl with headers

API Connect for GraphQL stores all headers in a config.yaml file. The following curl command contains a header, so API Connect for GraphQL creates a file named config.yaml:

stepzen import curl https://api.foo.com/bar -H 'Authorization: Bearer 347ack988dkey'

The config.yaml contains an entry for the header, which looks like the following example (there might be other entries in it as well):

configurationset:
  - configuration:
      name: some-auto-generated-name
      Authorization: Bearer 347ack988dkey

API Connect for GraphQL also modifies the generated schema to create a query like the following example:

type Query {
  myQuery: RootEntry
    @rest(
      endpoint: "https://api.foo.com/bar"
      configuration: "some-auto-generated-name"
    )
}

This ensures that your secrets (typically contained in headers) are stored separately from your code (your schema file).

Even if you do not have headers but are sending an apikey or something else in the endpoint, you can move it to the config.yaml file.

Using curl with query parameters

API Connect for GraphQL automatically converts all curl query parameters to arguments in the GraphQL query that is generated. For example, the request:

https://api.foo.com/bar?name=anant&country=US

generates the following query:

type Query {
  myQuery(name: String!, country: String!): RootEntry
    @rest(endpoint: "https://api.foo.com/bar")
}

Where did the query arguments go? In API Connect for GraphQL, GraphQL query arguments are appended to the endpoint URL as query string parameters. The generated query has the same effect as the following query that includes the arguments, but gives you more control:

type Query {
  myQuery(username: String!, country: String!): RootEntry
    @rest(endpoint: "https://api.foo.com/bar?name=$username&country=$country")
}
Preventing query parameters and arguments from being appended to the endpoint

You can specify rules to prevent API Connect for GraphQL from auto-appending the GraphQL query arguments and query string parameters. For example, you might want to suppress the parameters or arguments in the following situations:

  • When there is already a query parameter.

    For example, you can run the following command:

    stepzen import curl "https://api.foo.com/bar?name=anant&country=US"`

    and then edit the SDL to only allow queries on country=US:

      type Query {
        myQuery(name: String!): RootEntry
          @rest(endpoint: "https://api.foo.com/bar?country=US")
    }

    The name will not automatically be added as a query parameter because the endpoint URL does not use the required format of &name=$name

      type Query {
        myQuery(name: String!): RootEntry
          @rest(endpoint: "https://api.foo.com/bar?country=US&name=$name")
    }
  • You want to suppress parameters because they might be used in path or headers.

    In this case, edit the config.yaml as shown in the following example. Add the attribute stepzen.queryextensionguard and set it to true, which instructs API Connect for GraphQL not to automatically append query parameters to the request.

    configurationset:
      - configuration:
          name: "config"
          stepzen.queryextensionguard: true
Using curl with path parameters

API Connect for GraphQL can automatically convert path parameters into arguments. For example,

stepzen import curl https://example.com/users/jane/posts/12 --path-params '/users/$userId/posts/$postId'

generates a query in GraphQL like the following example:

type Query {
  myQuery(userId: String!, postId: Int!): RootEntry
    @rest(endpoint: "https://example.com/users/$userId/posts/$postId")
}
Adding arguments to the generated schema

The @restdirective that is generated from stepzen import curl can be customized with additional arguments to help you shape the REST response to the requested GraphQL type:

  • transforms to modify the response
  • filter to filter the output
  • setters and resultroot to change names of fields, and so on.

For more information on the configuration options, see "Shaping the HTTP response" in Connecting a REST service.

Working with POST requests

When using stepzen import curl for a POST request, parameter substitution gets applied to the body of your request.

Treating all fields in the POST body as query arguments

Consider a simple case:

stepzen import curl 'http://dummy.restapiexample.com/api/v1/create' -d '{"key1":"value1", "key2":"value2"}' -H 'Content-Type: application/json'

The curl request uses a default header that contains -d (or --data-raw) is Content-Type: application/x-www-form-urlencoded.

Because GraphQL APIs rely on JSON, you must append the header -H 'Content-Type: application/json' to use JSON in your post body.

The example stepzen import curl command generates a query in GraphQL like this:

type Query {
  myQuery(key1: String, key2: String): RootEntry
    @rest(
      method: POST
      endpoint: "http://dummy.restapiexample.com/api/v1/create"
    )
}

The argument method with the value POST is included in the @rest directive.

The JSON keys from the body are transformed into query arguments.

Generating a mutation from a POST request

When using stepzen import curl, the default GraphQL operation type is Query. To change the import into a Mutation, manually update the schema. For example, modify the following schema:

type Query {
  myQuery(key1: String, key2: String): RootEntry
    @rest(
      method: POST
      endpoint: "http://dummy.restapiexample.com/api/v1/create"
    )
}
by changing the Query type to a Mutation type:
type Mutation {
  myQuery(key1: String, key2: String): RootEntry
    @rest(
      method: POST
      endpoint: "http://dummy.restapiexample.com/api/v1/create"
    )
}

The stepzen import curl for POST does not handle more complicated parameter substitutions. For an overview of all the configuration options, see "Setting the HTTP request body" in Connecting a REST Service.

Best practices

Working with multiple curl requests
You can issue as many curl requests as you want. As a matter of best practice, use the following parameters to ensure that each request uses unique values:
  • Use --name to specify a unique directories for each imported curl request.
  • Use --query-name to assign unique names to the queries so that you avoid query name clashes.
  • Use --query-type to give the Root unique names to avoid root name clashes.
  • Use --prefix to prefix all non-root types.

    For example, --prefix Cust makes all types have a Cust prefix, and this avoids type conflicts with other schemas.

Undo a stepzen import curl command

To a stepzen import curl command, you should:

  1. Delete the generated directory.

    The directory has the name you specified with --name flag, or with curl or curl-xx.

  2. Edit the index.graphql file in the root of your working directory, and remove the entry for the directory that you deleted in step 1.

That's it. Then run your stepzen import curl command again.