One place for hosting & domains

      Introduction

      An Introduction to GraphQL


      Introduction

      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      As web and mobile applications become more mature and complex, software engineers invent clever new ways of improving the interaction between client and server within an application. One of the biggest paradigm shifts over the last few years in this regard has been GraphQL, an open-source query language and runtime for manipulating APIs. GraphQL was designed by Facebook in 2012 (and released publicly in 2015) to solve various weaknesses with traditional REST architecture by making a new system that is declarative, client-driven, and performant.

      In this article, you will review what GraphQL is, familiarize yourself with important terminology and concepts of GraphQL, and discover how the GraphQL specification compares with the REST architectural style.

      What is GraphQL?

      GraphQL stands for Graph Query Language, but unlike other query languages such as SQL (Structured Query Language), it is not a language for communicating directly with a database, but rather a language that defines a contract through which a client communicates with a API server. The GraphQL specification is an open standard that describes the rules and characteristics of the language. It also provides instructions for executing a GraphQL query.

      Due to the fact that GraphQL is defined by an open standard, there is no official implementation of GraphQL. A GraphQL implementation can be written with any programming language, integrate with any type of database, and support any client (such as mobile or web applications), as long as it follows the rules outlined in the spec. One of the most popular commercial GraphQL implementations is Apollo GraphQL, which touts several GraphQL client and server implementations, but it is not necessary to use Apollo to use or understand GraphQL.

      GraphQL Characteristics

      There are several key characteristics of GraphQL design. GraphQL queries are declarative and hierarchical, and a GraphQL schema is strongly-typed and introspective.

      Declarative

      GraphQL queries are declarative, meaning the client will declare exactly which fields it is interested in, and the response will only include those properties.

      This example GraphQL query for a hypothetical fantasy game API requests a wizard with an ID of "1", and requests the name and race fields on that object.

      {
        wizard(id: "1") {
          name
          race
        }
      }
      

      The response, which is returned in JSON format, will return a data object that contains the found wizard object, with the two fields the query requested.

      {
        "data": {
          "wizard": {
            "name": "Merlin",
            "race": "HUMAN"
          }
        }
      }
      

      Since a GraphQL response only gives you the exact information you want, it results in a more efficient and performant network request than alternatives that always provide a complete set of data.

      Hierarchical

      GraphQL queries are also hierarchical. The data returned follows the shape of the query. In this example, the query has been extended to include spells, and is requesting the name and attack fields of every spell.

      {
        wizard(id: "1") {
          name
          spells {
            name
            attack
          }
        }
      }
      

      The response will now include an array of all the spell objects associated with this particular wizard. Although wizards and spells might be stored in separate database tables, they can be fetched with a single GraphQL request. (However, GraphQL is not opinionated about how the data itself is stored, so that is a presumption.)

      {
        "data": {
          "wizard": {
            "name": "Merlin",
            "spells": [
              {
                "name": "Lightning Bolt",
                "attack": 2
              },
              {
                "name": "Ice Storm",
                "attack": 2
              },
              {
                "name": "Fireball",
                "attack": 3
              }
            ]
          }
        }
      }
      

      Strongly-typed

      GraphQL is strongly-typed, as described by the GraphQL Type system. Types describe the capabilities of the values within a GraphQL server. The GraphQL types will be familiar to most programmers, with scalars (primitive values) like strings, booleans, and numeric integers, as well as more advanced values like objects.

      This example creates a Spell Object type with fields that correspond to String and Int scalar types.

      type Spell {
        name: String!
        attack: Int
        range: Int
      }
      

      A GraphQL schema is defined using the type system, which allows the server to determine whether or not a query is valid before attempting to query the data. GraphQL Validation ensures the request is syntactically correct, unambiguous, and mistake-free.

      Self-documenting

      The Introspection feature allows GraphQL clients and tools to query the GraphQL server for the underlying schema’s shape and data. This allows for the creation of tools like GraphiQL, an in-browser IDE and playground for working with GraphQL queries, and other tools for automatically generating documentation.

      For example, you can find out more about the Spell type through this introspection feature via the __schema.

      {
        __schema {
          types {
            name
            kind
            description
          }
        }
      }
      

      The response will also be JSON like any other GraphQL response:

      {
        "data": {
          "__schema": {
            "types": [
              {
                "name": "Spell",
                "kind": "OBJECT",
                "description": "A powerful spell that a wizard can read from a scroll."
              }
            ]
          }
        }
      }
      

      Client-driven

      The work of developing a GraphQL API happens on the backend, where the schema is defined and implemented. However, since all of the power of the GraphQL API is encompassed in a single endpoint on the server, it is up to the client via declarative queries to decide exactly what data it needs. This empowers developers to iterate quickly, as the front-end developer can continue to query the data the GraphQL API exposes without doing any additional backend work.

      Architecture

      GraphQL exists in the application layer between client and data. The GraphQL server describes the capabilities exposed in the API, and the client describes the requirements of the request.

      Server

      A GraphQL API is defined with a single endpoint, usually the /graphql endpoint, which can access the full capabilities of the GraphQL server. Since GraphQL is an application layer technology and is transport agnostic, it can be served over any protocol, but it is most commonly served over HTTP.

      A GraphQL server implementation can be written with any programming language, such as the express-graphql middleware which allows you to create a GraphQL API on a Node/Express HTTP server. GraphQL is also database agnostic, and the data for the application can be stored in MySQL, PostgreSQL, MongoDB, or any other database. The data can even be supplied by an aggregation of several traditional REST API endpoints. All that matters is that the data is defined in a GraphQL schema, which defines the API by describing the data available to be queried.

      Client

      Requests made to a GraphQL server are called documents and consist of operations such as queries (for read requests) and mutations (for write requests).

      Although there are advanced GraphQL clients, such as Apollo Client or Facebook’s Relay which provide mechanisms for caching as well as additional tools, no special client is required to make a request to a GraphQL server. A simple XMLHttpRequest or fetch from a web browser is sufficient for making requests by sending a GraphQL document to a GraphQL server.

      Below is an example of a fetch request to a /graphql endpoint, which passes the GraphQL document as a string in the body of the POST request.

      async function fetchWizards() {
        const response = await fetch('/graphql', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            query: `{
          wizards {
            id
            name
          },
        }`,
          }),
        })
        const wizards = await response.json()
      
        return wizards
      }
      
      fetchWizards()
      

      This will return a JSON response for the request.

      {
        "data": {
          "wizards": [
            { "id": "1", "name": "Merlin" },
            { "id": "2", "name": "Gandalf" }
          ]
        }
      }
      

      GraphQL vs. REST

      GraphQL and REST are not interchangeable concepts, but they solve similar problems for applications. REST stands for Representational State Transfer, and is a software architectural style for sharing data between different systems. A RESTful API is an API that adheres to the principles and constraints of REST, which includes being stateless, cacheable, enforcing a separation of concerns between the client and server, and having a uniform interface, such as through URIs. GraphQL, as covered previously, is a specification for a query language and runtime for executing queries.

      There are advantages and disadvantages to both systems, and both have their use in modern API development. However, GraphQL was developed to combat some perceived weaknesses with the REST system, and to create a more efficient, client-driven API.

      • Architecture – A REST API is typically defined by multiple endpoints on a server, but GraphQL exchanges data over a single endpoint. A GraphQL endpoint can return a complex graph of data that might require multiple REST queries, reducing the number of requests over the network for a single view.

      • Data fetching – A REST API returns the set of data that was determined on the server. This might be far too much data, such as if the view only requires one property from a response. It also might not be enough, such as a list endpoint that doesn’t return every property that a table requires in the view. GraphQL prevents this over and under fetching of data via declarative queries.

      • Error Handling – Since it is not necessary for GraphQL to be served over HTTP, there is no specification about using HTTP response codes for errors. Typically all GraphQL endpoints will resolve with a 200 HTTP code response, and failed results will include an errors property alongside the data property in the response. RESTful APIs, on the other hand, utilize different 400 level HTTP codes for client errors and 200 level HTTP codes for successful responses.

      • Versioning – GraphQL APIs strive to be backwards compatible and avoid breaking changes, contrasting with the common REST pattern of versioning endpoints, often with a /v1 or /v2 in the URL itself to determine the version. However, it is possible to implement your own versioning with GraphQL, or version via evolution with REST, it’s just less conventional.

      • Caching – Cacheability is an integral part of the REST guiding constraints. Since HTTP-based REST APIs consist of multiple endpoints using different HTTP methods, it can take advantage of existing HTTP conventions for caching and avoiding refetching resource. Since essentially every GraphQL request will be different but use the single endpoint, it cannot take advantage of any of the built-in HTTP caching mechanisms. GraphQL clients can take advantage of Global Object Identification to enable simple caching.

      This list does not cover all the similarities and differences between REST and GraphQL, but summarizes many of the most critical points. Additionally, GraphQL can be used as a gateway that aggregates multiple REST endpoints or services, in which case both technologies can be used in harmony side-by-side.

      Feature GraphQL REST
      Description GraphQL is a query language for APIs, and a server-side runtime An architectural style for designing web services
      Data Fetching A single HTTP endpoint that responds to deterministic queries A set of HTTP endpoints that typically return a predetermined dataset
      Versioning Versioning discouraged Versioning common
      HTTP Status Codes All responses, including errors, are typically 200 Implements HTTP Status codes
      Validation Built-in metadata validation Validation must be manually implemented
      Documentation Built-in via type system and introspection Not self-documenting, tools like OpenAPI available
      Caching No Yes
      Request Methods Queries, mutations, and subscriptions (over POST for HTTP) All HTTP methods utilized (GET, POST, PATCH, PUT, DELETE, etc)
      Response Content-Type JSON Any (JSON, XML, HTML, etc.)

      Conclusion

      GraphQL is an open-source query language and runtime for APIs. GraphQL was invented by developers at Facebook to solve various issues encountered with traditional REST APIs, such as over/under fetching data and inefficient network requests, by making a client-driven, declarative query language for APIs.

      While GraphQL is not an interchangeable concept with REST, they both describe different ways to manage communication between a client and a server. In this article, you learned what GraphQL is, key differences and similarities between GraphQL and REST, and how a GraphQL server exposes data to a client.



      Source link

      Introduction to Kubernetes Patterns: Scaling Your App With Repeatable Architecture


      How to Join

      This Tech Talk is free and open to everyone. Register below to get a link to join the live stream or receive the video recording after it airs.

      Date Time RSVP
      September 27, 2021 11 a.m.–12 p.m. ET / 3–4 p.m. GMT

      About the Talk

      Kubernetes Patterns helps you reuse architecture, offering repeatable design patterns/solutions to recurring events. Instead of creating architecture completely from scratch, you can re-use existing Kubernetes components to ensure that things work the way they’re supposed to, every time.

      What You’ll Learn

      • Repeatable design solutions for container-based applications and services
      • When to use which Kubernetes pattern(s): foundational, behavioral, structural, configuration, advanced, etc.
      • How to use Kubernetes components and pieces to build a complete system that meets your business goals

      This Talk is Designed For

      • Software developers, SysAdmins, and CTOs
      • Anyone looking to save time on “Day 2” Kubernetes operations
      • Anyone looking to enable cloud portability using cloud–native technologies

      Prerequisites

      Basic knowledge of Kubernetes and cloud infrastructure



      Source link

      An Introduction to Document-Oriented Databases


      Introduction

      Although they were first invented decades ago, computer-based databases have become ubiquitous on today’s internet. More and more commonly, websites and applications involve collecting, storing, and retrieving data from a database. For many years the database landscape was dominated by relational databases, which organize data in tables made up of rows. To break free from the rigid structure imposed by the relational model, though, a number of different database types have emerged in recent years.

      These new database models are jointly referred to as NoSQL databases, as they usually do not use Structured Query Language — also known as SQL — which relational databases typically employ to manage and query data. NoSQL databases offer a high level of scalability as well as flexibility in terms of data structure. These features make NoSQL databases useful for handling large volumes of data and fast-paced, agile development.

      This conceptual article outlines the key concepts related to document databases as well as the benefits of using them. Examples used in this article reference MongoDB, a widely-used document-oriented database, but most of the concepts highlighted here are applicable for most other document databases as well.

      What is a Document Database?

      Breaking free from thinking about databases as consisting of rows and columns, as is the case in a table within a relational database, document databases store data as documents. You might think of a document as a self-contained data entry containing everything needed to understand its meaning, similar to documents used in the real world.

      The following is an example of a document that might appear in a document database like MongoDB. This sample document represents a company contact card, describing an employee called Sammy:

      Sammy’s contact card document

      {
          "_id": "sammyshark",
          "firstName": "Sammy",
          "lastName": "Shark",
          "email": "sammy.shark@digitalocean.com",
          "department": "Finance"
      }
      

      Notice that the document is written as a JSON object. JSON is a human-readable data format that has become quite popular in recent years. While many different formats can be used to represent data within a document database, such as XML or YAML, JSON is one of the most common choices. For example, MongoDB adopted JSON as the primary data format to define and manage data.

      All data in JSON documents are represented as field-and-value pairs that take the form of field: value. In the previous example, the first line shows an _id field with the value sammyshark. The example also includes fields for the employee’s first and last names, their email address, as well as what department they work in.

      Field names allow you to understand what kind of data is held within a document with just a glance. Documents in document databases are self-describing, which means they contain both the data values as well as the information on what kind of data is being stored. When retrieving a document from the database, you always get the whole picture.

      The following is another sample document representing a colleague of Sammy’s named Tom, who works in multiple departments and also uses a middle name:

      Tom’s contact card document

      {
          "_id": "tomjohnson",
          "firstName": "Tom",
          "middleName": "William",
          "lastName": "Johnson",
          "email": "tom.johnson@digitalocean.com",
          "department": ["Finance", "Accounting"]
      }
      

      This second document has a few differences from the first example. For instance, it adds a new field called middleName. Also, this document’s department field stores not a single value, but an array of two values: "Finance" and "Accounting".

      Because these documents hold different fields of data, they can be said to have different schemas. A database’s schema is its formal structure, which outlines what kind of data it can hold. In the case of documents, their schemas are reflected in their field names and what kinds of values those fields represent.

      In a relational database, you’d be unable to store both of these example contact cards in the same table, as they differ in structure. You would have to adapt the database schema both to allow storing multiple departments as well as middle names, and you would have to provide a middle name for Sammy or else fill the column for that row with a NULL value. This is not the case with document databases, which offer you the freedom to save multiple documents with different schemas together with no changes to the database itself.

      In document databases, documents are not only self-describing but also their schema is dynamic, which means that you don’t have to define it before you start saving data. Fields can differ between different documents in the same database, and you can modify the document’s structure at will, adding or removing fields as you go. Documents can be also nested — meaning that a field within one document can have a value consisting of another document — making it possible to store complex data within a single document entry.

      Let’s imagine the contact card must store information about social media accounts the employee uses and add them as nested objects to the document:

      Tom’s contact card document with social media accounts information attached

      {
          "_id": "tomjohnson",
          "firstName": "Tom",
          "middleName": "William",
          "lastName": "Johnson",
          "email": "tom.johnson@digitalocean.com",
          "department": ["Finance", "Accounting"],
          "socialMediaAccounts": [
              {
                  "type": "facebook",
                  "username": "tom_william_johnson_23"
              },
              {
                  "type": "twitter",
                  "username": "@tomwilliamjohnson23"
              }
          ]
      }
      

      A new field called socialMediaAccounts appears in the document, but instead of a single value, it refers to an array of nested objects describing individual social media accounts. Each of these accounts could be a document on its own, but here they’re stored directly within the contact card. Once again, there is no need to change the database structure to accommodate this requirement. You can immediately save the new document to the database.

      Note: In MongoDB, it’s customary to name fields and collections using a camelCase notation, with no spaces between words, the first word written entirely in lowercase, and any additional words having their first letters capitalized. That said, you can also use different notations such as snake_case, in which words are all written in lowercase and separated with underscores. Whichever notation you choose, it’s considered bast practice to use it consistently across the whole database.

      All these attributes make it intuitive to work with document databases from the developer’s perspective. The database facilitates storing actual objects describing data within the application, encouraging experimentation and allowing great flexibility when reshaping data as the software grows and evolves.

      Benefits of Document Databases

      While document-oriented databases may not be the right choice for every use case, there are many benefits of choosing one over a relational database. A few of the most important benefits are:

      • Flexibility and adaptability: with a high level of control over the data structure, document databases enable experimentation and adaptation to new emerging requirements. New fields can be added right away and existing ones can be changed any time. It’s up to the developer to decide whether old documents must be amended or the change can be implemented only going forward.

      • Ability to manage structured and unstructured data: as mentioned previously, relational databases are well suited for storing data that conforms to a rigid structure. Document databases can be used to handle structured data as well, but they’re also quite useful for storing unstructured data where necessary. You can imagine structured data as the kind of information you would easily represent in a spreadsheet with rows and columns, whereas unstructured data is everything not as straightforward to frame. Examples of unstructured data are rich social media posts with human-generated texts and multimedia, server logs that don’t follow unified format, or data coming from a multitude of different sensors in smart homes.

      • Scalability by design: relational databases are often write constrained, and increasing their performance requires you to scale vertically (meaning you must migrate their data to more powerful and performant database servers). Conversely, document databases are designed as distributed systems that instead allow you to scale horizontally (meaning that you split a single database up across multiple servers). Because documents are independent units containing both data and schema, it’s relatively trivial to distribute them across server nodes. This makes it possible to store large amounts of data with less operational complexity.

      In real-world applications, both document databases and other NoSQL and relational databases are often used together, each responsible for what it’s best suited for. This paradigm of mixing various types of databases is known as polyglot persistence.

      Grouping Documents Into Collections

      While document databases allow great flexibility in how the documents are structured, having some means of organizing data into categories sharing similar characteristics is crucial for ensuring that a database is healthy and manageable.

      Imagine a database as an individual cabinet in a company archive with many draws. For example, one drawer might keep records of employment contracts, with another keeping agreements with business partners. While it is technically possible to put both kinds of documents into a single drawer, it would be difficult to browse the documents later on.

      In a document database, such drawers are often called collections, logically similar to tables in relational databases. The role of a collection is to group together documents that share a similar logical function, even if individual documents may slightly differ in their schema. For instance, say you have one employment contract for a fixed-term and another that describes a contractor’s additional benefits. Both documents are employment contracts and, as such, it could make sense to group them into a single collection:

      Document collection

      Note: While it’s a popular approach, not all document databases use the concept of collections to organize documents together. Some database systems use tags or tree-like hierarchies, others store documents directly within a database with no further subdivisions. MongoDB is one of the popular document-oriented databases that use collections for document organization.

      Having similar characteristics between documents within a collection also allows you to build indexes in order to allow for more performant retrieval of documents based on queries related to certain fields. Indexes are special data structures that store a portion of a collection’s data in a way that’s faster to traverse and filter.

      As an example, you might have a collection of documents in a database that all share a similar field. Because each document shares the same field, it’s likely you would often use that field when running queries. Without indexes, any query asking the database to retrieve a particular document requires a collection scan — browsing all documents within a collection one by one to find the requested match. By creating an index, however, the database only needs to browse through indexed fields, thereby improving query performance.

      Data Types and Schema Validation

      While we mentioned that document-oriented databases can store documents in different formats, such as XML, YAML or JSON, these are often further extended with additional traits that are specific to a given database system, such as additional data types or structure validation features.

      For example, MongoDB internally uses a binary format called BSON (short for Binary JSON) instead of a pure JSON. This not only allows for better performance, but it also extends the format with data types that JSON does not support natively. Thanks to this, we can reliably store different kinds of data in MongoDB documents without being restricted to standard JSON types and use filtering, sorting, and aggregation features specific to individual data types.

      The following sample document uses several different data types supported by MongoDB:

      {
          "_id": ObjectId("5a934e000102030405000000"),
          "code": NumberLong(2090845886852),
          "image": BinData(0, "TGVhcm5pbmcgTW9uZ29EQg=="),
          "lastPurchased": ISODate("2021-01-19T06:01:17.171Z"),
          "name": "Document database sticker",
          "price": NumberDecimal("13.23"),
          "quantity": 317,
          "tags": [
              "stickers",
              "accessories"
          ]
      }
      

      Notice that some of these data types not typical to JSON, such as decimal numbers with exact precision or dates which are represented as objects, such as NumberDecimal or ISODate. This ensures that these fields will always be interpreted properly and not mistakenly cast to another similar data type, like a decimal number being cast to a regular double.

      This variety of supported data types, combined with schema validation features, makes it possible to implement a set of rules and validity requirements to provide your document database structure. This allows you to model not only unstructured data, but to also create collections of documents following more rigid and precise requirements.

      Conclusion

      Thanks to their flexibility, scalability, and ease of use, document databases are becoming an increasingly popular choice of database for application developers. They are well suited to different applications and work well on their own or as a part of bigger, multi-database ecosystems. The wide array of document-oriented databases has distinct advantages and use cases, making it possible to choose the best database for any given task.

      You can learn more about document-oriented databases and other NoSQL databases from DigitalOcean’s community articles on that topic.

      To learn more about MongoDB in particular, we encourage you to follow this tutorial series covering many topics on using and administering MongoDB and to check the official MongoDB documentation, a vast source of knowledge about MongoDB as well as document databases in general.



      Source link