Implement graphql server API with springboot and automate test using requests in Python

cuongld2

cuongld2

Posted on January 4, 2020

Implement graphql server API with springboot and automate test using requests in Python

GraphQL is getting more and more attention from development community as it allows us to get only the data we need.

You can find out more about graphql in here

In this post I will walk through how to create a simple graphql API server in spring-boot and how to do automated testing it with requests in Python.

You might want to check my previous post, which I already mentioned how to create a blog app in springboot as in this post, I will continue using that and implemented a graphql server based on that.

I.GraphQL server:
Basically, I will keep all the other APIs from the old posts. I just write some new queries support to get the blog post data.

1.Dependencies:
You will need the below dependencies for implemented graphql in java and graphiql for usage

        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.2.4</version>
        </dependency>
        <dependency>
            <groupId>com.graphql-java</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.0.2</version>
        </dependency>
Enter fullscreen mode Exit fullscreen mode

2.GraphQL Schema:
We need to define the schema for what kind of queries and what kind of objects will be supported.
Below is how we defined the schema:

type Blog {
    id: Int,
    title: String,
    content: String
}

type Query {
    blogs(count: Int):[Blog]
    blog(id: Int):Blog
}
Enter fullscreen mode Exit fullscreen mode

We will support 2 kinds of queries.
1.Get a number of blogs based on the count parameter
2.Get a blog content by its id

3.Blog service:
Define the methods to return the blogs info.


@Service
public class BlogService {

    private final BlogRepository blogRepository;

    public BlogService(final BlogRepository blogRepository){this.blogRepository = blogRepository;}

    @Transactional(readOnly = true)
    public List<Blog> getAllBlogs(final int count){
        return this.blogRepository.findAll().stream().limit(count).collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public Optional<Blog> getBlog(final int id){return this.blogRepository.findById(id);}
}

Enter fullscreen mode Exit fullscreen mode

4.Blog query:
Define the methods to return the blog service info:


@Component
public class BlogQuery implements GraphQLQueryResolver {

    @Autowired
    private BlogService blogService;

    public List<Blog> getBlogs(final int count){
        return this.blogService.getAllBlogs(count);
    }


    public Optional<Blog> getBlog(final int id){return this.blogService.getBlog(id);}

}

Enter fullscreen mode Exit fullscreen mode

5.Security:
As in the previous post, we already defined this:

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.csrf().disable()

                .authorizeRequests().antMatchers("/authenticate","/user").permitAll().

        anyRequest().authenticated().and().

        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()

                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

    }

Enter fullscreen mode Exit fullscreen mode

that means if the endpoint is not start with /authenticate or /user, they will need the header token.

So in order for later to get blogs information by graphql server, we will need to provide the necessary token.

6.Run the graphql server:
As usual run with

mvn spring-boot:run

II.GraphiQL:

GrahpiQL is a way to interact with graphql server.
You can access to the grahqpl server by opening this in browser (exp: Chrome) :

http://localhost:8082/graphql
But remember as I mention earlier, it needs the token to access, so you might want to install another extension into your chrome browser like :
mod header

Or you might want to run a graphiql app like in here which I'm currently using.

1.Add header content:

Alt Text

2.Get a number of blogs with only id and content info:

Alt Text

3.Get a blog post by its id:

Alt Text

III.Automate tests with requests in Python

1.Define method get blogs info by query and its token

class Blogs:

    def get_blog_info(self, query, token):
        request = requests.post(API_SERVER_URL + API_GRAPH_QL_PATH, json={'query': query}, headers={"Authorization": f"Bearer {token}"})
        if request.status_code == 200:
            return request.json()
        else:
            raise Exception("Query failed to run by returning code of {}. {}".format(request.status_code, query))

Enter fullscreen mode Exit fullscreen mode

2.Write test script to create new user, get token and use that token to query the information we need:


class TestGetBlogsInfo:
    user_api = User()
    restapi_query = RestAPIDatabase()
    random_gen = RandomGenerator()
    blog_graphql_api = Blogs()

    @pytestrail.case('C8')
    def test_get_all_blog_id_and_contents_with_count(self, set_up_mysql):
        username = self.random_gen.random_string(8) + '@gmail.com'
        query = """
        {
            blogs(count:1){
                            id,
                            content
                            }
        }
        """
        try:
            response = self.user_api.create_new_user_data_class(username, 'Abcd12345$', 'Le Dinh Cuong')
            assert 200 == response.status_code
            response = self.user_api.authen_user_login(username, 'Abcd12345$')
            assert response.status_code == 200
            token_object = json.loads(response.text)
            assert token_object['token'] is not None
            response_blog = self.blog_graphql_api.get_blog_info(query, token_object['token'])
            print(response_blog)
            assert response_blog['data']['blogs'][0]['id'] == 1
            if 'title' in response_blog['data']['blogs'][0]:
                raise print('Content existed in response')
            assert 'title' not in str(response_blog)
        finally:
            self.restapi_query.delete_user_info_by_username(set_up_mysql, username)

Enter fullscreen mode Exit fullscreen mode

I know it's pretty tough and there might be something you might don't understand, but feel free to ask me in the comment.

Below is the link for source code for implemented the graphql server app and the test repo.

spring-boot-graphql
automate-test-python

Happy coding!

Notes: If you feel this blog help you and want to show the appreciation, feel free to drop by :

This will help me to contributing more valued contents.

💖 💪 🙅 🚩
cuongld2
cuongld2

Posted on January 4, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related