<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marcos Placona</title>
    <description>The latest articles on DEV Community by Marcos Placona (@marcos_placona).</description>
    <link>https://dev.to/marcos_placona</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2145672%2F6a788d75-0dad-4c64-b855-bb38313bc6af.jpg</url>
      <title>DEV Community: Marcos Placona</title>
      <link>https://dev.to/marcos_placona</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcos_placona"/>
    <language>en</language>
    <item>
      <title>Understanding The Difference Between OpenAPI's 'oneOf', 'allOf', and 'anyOf'</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Wed, 12 Mar 2025 14:53:00 +0000</pubDate>
      <link>https://dev.to/marcos_placona/understanding-the-difference-between-openapis-oneof-allof-and-anyof-3j48</link>
      <guid>https://dev.to/marcos_placona/understanding-the-difference-between-openapis-oneof-allof-and-anyof-3j48</guid>
      <description>&lt;p&gt;Crafting precise and adaptable schemas is paramount in API design. OpenAPI offers several constructs to help define flexible and robust data models, the most powerful and flexible of which are &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, and &lt;code&gt;anyOf&lt;/code&gt;. These keywords provide different ways to validate data against multiple schemas, making them essential for designing APIs that accommodate varied data structures while maintaining type safety.&lt;/p&gt;

&lt;p&gt;Whether you’re designing your API using Laravel, Flask, Nest, &lt;a href="https://liblab.com/docs/howto/django" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, &lt;a href="https://liblab.com/docs/howto/fastapi" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;, &lt;a href="https://liblab.com/docs/howto/spring-boot" rel="noopener noreferrer"&gt;SpringBoot&lt;/a&gt;, &lt;a href="https://liblab.com/docs/howto/express-jsdoc" rel="noopener noreferrer"&gt;Express&lt;/a&gt;, &lt;a href="https://liblab.com/docs/howto/aspnet" rel="noopener noreferrer"&gt;ASP.NET&lt;/a&gt;, or &lt;a href="https://liblab.com/docs/category/framework-guides" rel="noopener noreferrer"&gt;anything else&lt;/a&gt;. Understanding the key differences and how to use OpenAPI &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, and &lt;code&gt;anyOf&lt;/code&gt; will help you design a more maintainable and future-proof API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Key Differences
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;oneOf&lt;/code&gt;&lt;/strong&gt; – The data must validate against exactly one of the subschemas.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allOf&lt;/code&gt;&lt;/strong&gt; – The data must validate against all the subschemas simultaneously.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;anyOf&lt;/code&gt;&lt;/strong&gt; – The data must validate against at least one (or more) of the subschemas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these distinctions is crucial when designing OpenAPI definitions, as they directly impact SDK generation, data validation, and client-side type safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Subschemas
&lt;/h2&gt;

&lt;p&gt;To understand these keywords, it’s first important to understand what a subschema is. At its simplest, a subschema is just a schema referenced in a larger, more complex schema. Take, for example, this basic schema that defines a &lt;code&gt;Dog&lt;/code&gt;, &lt;code&gt;Cat&lt;/code&gt;, and &lt;code&gt;Animal&lt;/code&gt;. They are all schemas, but when &lt;code&gt;Dog&lt;/code&gt; and &lt;code&gt;Cat&lt;/code&gt; are referenced in &lt;code&gt;Animal,&lt;/code&gt; they are subschemas of &lt;code&gt;Animal&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This is similar to classes and subclasses, but the relationships are top-down rather than bottom-up. In this example, &lt;code&gt;Dog&lt;/code&gt; does not inherit or extend from &lt;code&gt;Animal&lt;/code&gt; and does not take on any of &lt;code&gt;Animal&lt;/code&gt;’s attributes. Instead, Animal defines that Dog or Cat as possible subschemas that it can conform to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components:
  schemas:
    Dog: # ...
    Cat: # ...
    Animal:
      oneOf:
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Cat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  OpenAPI &lt;code&gt;oneOf&lt;/code&gt;: Ensuring Exclusive Schema Matching
&lt;/h2&gt;

&lt;p&gt;Use OpenAPI &lt;code&gt;oneOf&lt;/code&gt; when a value should conform to precisely one of the provided schemas. This is particularly useful when defining mutually exclusive options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components:
  schemas:
    Pet:
      type: object
      properties:
        name:
          type: string
        petType:
          type: string
      discriminator:
        propertyName: petType
    Dog:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            bark:
              type: boolean
            dig:
              type: boolean
    Cat:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            meow:
              type: boolean
            scratch:
              type: boolean
    Animal:
      oneOf:
        - $ref: '#/components/schemas/Dog'
        - $ref: '#/components/schemas/Cat'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, an &lt;code&gt;Animal&lt;/code&gt; must be either a &lt;code&gt;Dog&lt;/code&gt; or a &lt;code&gt;Cat&lt;/code&gt;, but not both. This ensures that API consumers provide and receive well-structured data that conforms to differing expectations of &lt;code&gt;Cat&lt;/code&gt; and &lt;code&gt;Dog&lt;/code&gt;. For example, a user can provide a &lt;code&gt;Dog&lt;/code&gt; that can &lt;code&gt;bark&lt;/code&gt; and &lt;code&gt;dig&lt;/code&gt; but cannot &lt;code&gt;meow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; One common issue with &lt;code&gt;oneOf&lt;/code&gt; is its strict validation. &lt;code&gt;oneOf&lt;/code&gt; is exactly one. If none or more than one schema matches, validation will fail. While the “none case” is expected, the “more than one case” can confuse API consumers and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAPI &lt;code&gt;allOf&lt;/code&gt;: Merging Multiple Schemas
&lt;/h2&gt;

&lt;p&gt;Use OpenAPI &lt;code&gt;allOf&lt;/code&gt; to create composite objects that inherit properties from multiple schemas. This is useful when reusing common schema elements while adding specific properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components:
  schemas:
    Address:
      type: object
      properties:
        street:
          type: string
        city:
          type: string
    Person:
      type: object
      properties:
        name:
          type: string
        age:
          type: integer
    Employee:
      allOf:
        - $ref: '#/components/schemas/Person'
        - $ref: '#/components/schemas/Address'
        - type: object
          properties:
            employeeId:
              type: string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;Employee&lt;/code&gt; is a combination of &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Address&lt;/code&gt;, inheriting all their properties while adding &lt;code&gt;employeeId&lt;/code&gt;. This is especially useful when generating SDKs, as the resulting type automatically includes all inherited fields. Any update to the definition of &lt;code&gt;Person&lt;/code&gt; or &lt;code&gt;Address&lt;/code&gt; will be automatically reflected in &lt;code&gt;Employee&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; Overusing &lt;code&gt;allOf&lt;/code&gt; can create deeply nested structures that become difficult to manage and debug, especially when resolving conflicts between inherited properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAPI &lt;code&gt;anyOf&lt;/code&gt;: Flexible Validation Against Multiple Schemas
&lt;/h2&gt;

&lt;p&gt;Use OpenAPI &lt;code&gt;anyOf&lt;/code&gt; when a value should match at least one (but possibly more) of the subschemas. This is useful for handling partial matches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components:
  schemas:
    Contact:
      anyOf:
        - type: object
          properties:
            email:
              type: string
              format: email
        - type: object
          properties:
            phone:
              type: string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, a &lt;code&gt;Contact&lt;/code&gt; object must contain either an &lt;code&gt;email&lt;/code&gt;, a &lt;code&gt;phone&lt;/code&gt;, or both. This is useful for more flexible schemas where multiple data input formats are acceptable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pitfall:&lt;/strong&gt; With &lt;code&gt;anyOf&lt;/code&gt;, partial matches can lead to unintended behaviors if API consumers expect all properties always to be present. Defining required fields can mitigate this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Practices
&lt;/h2&gt;

&lt;p&gt;To effectively use OpenAPI’s &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, and &lt;code&gt;anyOf&lt;/code&gt;, consider these best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document Clearly&lt;/strong&gt;: Provide detailed documentation on how your API behaves to prevent confusion for API consumers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Discriminators with &lt;code&gt;oneOf&lt;/code&gt;&lt;/strong&gt;: Implement a &lt;code&gt;discriminator&lt;/code&gt; property to simplify schema resolution and avoid ambiguous validation errors.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Excessive Nesting with &lt;code&gt;allOf&lt;/code&gt;&lt;/strong&gt;: While &lt;code&gt;allOf&lt;/code&gt; promotes schema reuse, excessive inheritance can lead to deeply nested structures that are difficult to maintain.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define Required Fields for &lt;code&gt;anyOf&lt;/code&gt;&lt;/strong&gt;: If a schema under &lt;code&gt;anyOf&lt;/code&gt; should always have a specific property, explicitly set it as required to avoid unexpected validation issues.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Thoroughly&lt;/strong&gt;: Validate your OpenAPI specification using tools like &lt;code&gt;liblab validate&lt;/code&gt; or Linters to catch misconfigurations early.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implications for SDK Generation
&lt;/h2&gt;

&lt;p&gt;Choosing between &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, and &lt;code&gt;anyOf&lt;/code&gt; has a significant impact on how SDKs handle type definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI &lt;code&gt;oneOf&lt;/code&gt; ensures that only one type is valid at a time, leading to strict type-checking.
&lt;/li&gt;
&lt;li&gt;OpenAPI &lt;code&gt;allOf&lt;/code&gt; merges schemas, making SDKs generate fully composed types with inherited properties.
&lt;/li&gt;
&lt;li&gt;OpenAPI &lt;code&gt;anyOf&lt;/code&gt; allows looser type enforcement, enabling SDKs to accept multiple valid structures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these nuances helps design API contracts that are flexible and well-defined, ensuring a better developer experience and more reliable SDKs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By effectively leveraging &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, and &lt;code&gt;anyOf&lt;/code&gt;, API designers can create expressive and maintainable OpenAPI schemas, enhancing the developer experience across various integrations. Whether building SDKs or validating API responses, choosing the proper construct ensures your API remains robust and easy to consume.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.liblab.com/join" rel="noopener noreferrer"&gt;Sign up for liblab&lt;/a&gt; today and start generating SDKs for your APIs in minutes.&lt;/p&gt;

&lt;p&gt;This article was originally written by Jim Bennett for the liblab blog&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally written for the &lt;a href="https://liblab.com/blog/difference-between-openapis-oneof-allof-and-anyof" rel="noopener noreferrer"&gt;liblab blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>openapi</category>
      <category>devex</category>
      <category>sdk</category>
    </item>
    <item>
      <title>Mastering OpenAPI Types: Best Practices for Data Types and Formats</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Wed, 12 Mar 2025 10:51:50 +0000</pubDate>
      <link>https://dev.to/liblab/mastering-openapi-types-best-practices-for-data-types-and-formats-4ldc</link>
      <guid>https://dev.to/liblab/mastering-openapi-types-best-practices-for-data-types-and-formats-4ldc</guid>
      <description>&lt;p&gt;The OpenAPI Specification is often associated with describing RESTful APIs, but don’t be fooled by the stereotype. Whether you’re designing a REST API or something that leans more toward RPC-based calls, OpenAPI’s data type system is robust enough to capture your API’s behavior precisely. In this post, we’ll dive into recommended practices for working with &lt;strong&gt;OpenAPI types&lt;/strong&gt; and explore all the data types you can leverage, from strings and numbers to objects and arrays.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Precision Matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Clarity is king when your API spec serves as both documentation and a blueprint for SDK generation. Overly loose definitions might be “valid” according to the spec, but they can cause headaches when tooling tries to generate SDKs, server stubs, or even API docs. Here’s what you should keep front-of-mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Be explicit.&lt;/strong&gt; Define your types using the standardized formats.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate ruthlessly.&lt;/strong&gt; Use attributes like &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;readOnly&lt;/code&gt;, &lt;code&gt;writeOnly&lt;/code&gt;, and validations (e.g., &lt;code&gt;minItems&lt;/code&gt;, &lt;code&gt;pattern&lt;/code&gt;) to avoid ambiguity.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan for tooling.&lt;/strong&gt; Clear, explicit definitions make it easier for SDK generators and documentation tools to do their job without guesswork.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s walk through each data type with best practices and real-world examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The OpenAPI Data Types&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. String&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The string type is a workhorse of the OpenAPI spec. It can represent everything from simple text to complex data like encoded binary files. But to unlock its full potential, you must use formats and patterns wisely.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Formats&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Official formats for strings include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;date&lt;/strong&gt;: For RFC3339 dates (e.g., &lt;code&gt;"2025-03-07"&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;date-time&lt;/strong&gt;: For full timestamps (e.g., &lt;code&gt;"2025-03-07T15:26:38Z"&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;password&lt;/strong&gt;: A hint that the string holds sensitive data.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;byte&lt;/strong&gt;: Base64 encoded data.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;binary&lt;/strong&gt;: For raw binary data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outside the official list, you might see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;email&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;uuid&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;uri&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hostname&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ipv4/ipv6&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;full list &lt;a href="https://spec.openapis.org/registry/format/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: string
  format: date-time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Patterns&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When you need to constrain string content further, add a regex pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: string
  pattern: '^[a-zA-Z0-9_]+$'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Best practice:&lt;/em&gt; Always validate input where possible. A well-defined string improves API documentation and makes client-side parsing and generation predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Number &amp;amp; Integer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Numbers are more than just digits on a screen. OpenAPI distinguishes between generic numbers and integers by allowing you to specify formats that align with your target language’s capabilities. &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Formats for Numbers:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;number&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;float&lt;/em&gt;: For 32-bit floating point.
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;double&lt;/em&gt;: For 64-bit floating point.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;integer&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;int32&lt;/em&gt;: 32-bit integer.
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;int64&lt;/em&gt;: 64-bit integer.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Worth noting that JSON Schema defines integers mathematically, which means that both 1 and 1.0 are equivalent and considered integers.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Validation Attributes&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Use attributes like &lt;code&gt;minimum&lt;/code&gt;, &lt;code&gt;maximum&lt;/code&gt;, &lt;code&gt;exclusiveMinimum&lt;/code&gt;, &lt;code&gt;exclusiveMaximum&lt;/code&gt;, and &lt;code&gt;multipleOf&lt;/code&gt; to enforce numeric constraints.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example for a 32-bit float:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: number
  format: float
  minimum: 0
  maximum: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Example for an integer with step constraints:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: integer
  format: int64
  multipleOf: 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Explicitly specifying the format avoids any ambiguity that might arise from the default type handling in various languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Boolean&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Simple but essential, the boolean type only accepts &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;. Unlike some loosely-typed systems, OpenAPI does not let you substitute &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: boolean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Best practice:&lt;/em&gt; Don’t try to be clever. Stick to true booleans to ensure consistent behavior across all consumers.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;4. Array&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Arrays let you define ordered lists of items. The key is to use the &lt;code&gt;items&lt;/code&gt; attribute to specify the type of elements in the array.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Basic examples:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Array of strings
schema:
  type: array
  items:
    type: string

# Array of objects with validations
schema:
  type: array
  items:
    type: object
    properties:
      id:
        type: integer
        format: int32
      name:
        type: string
  minItems: 1
  uniqueItems: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Best practice:&lt;/em&gt; Utilize array-level validations (&lt;code&gt;minItems&lt;/code&gt;, &lt;code&gt;maxItems&lt;/code&gt;, &lt;code&gt;uniqueItems&lt;/code&gt;) to enforce data integrity before it reaches your business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Object&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Objects in OpenAPI can be fully typed, serve as dictionaries, or be completely free-form. The level of detail you include can dramatically affect downstream processes like code generation.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Fully Typed Object&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Define explicit properties with validations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: object
  properties:
    username:
      type: string
    age:
      type: integer
      format: int32
    isActive:
      type: boolean
  required:
    - username
    - isActive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Dictionary (Using additionalProperties)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Use this for flexible key/value pairs where keys are always strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: object
  additionalProperties:
    type: string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Best practice:&lt;/em&gt; When possible, define all properties explicitly. Reserve free-form objects (&lt;code&gt;additionalProperties: true&lt;/code&gt; or &lt;code&gt;{}&lt;/code&gt;) for cases where the structure genuinely cannot be predetermined.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Null&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;OpenAPI 3.0 doesn’t have a separate null type. Instead, you mark a schema as &lt;code&gt;nullable&lt;/code&gt; to indicate that it can be either a valid value or null.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schema:
  type: string
  nullable: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Best practice:&lt;/em&gt; Overusing &lt;code&gt;nullable&lt;/code&gt; can lead to ambiguity. Only mark a property as nullable if null is a valid, intentional state for that property.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Bringing It All Together&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The beauty of OpenAPI lies in its versatility. While it’s renowned for RESTful API descriptions, its design supports the nuances of RPC-based calls and other HTTP paradigms. The secret to leveraging &lt;strong&gt;OpenAPI types&lt;/strong&gt; effectively is to be explicit. By rigorously defining data types, formats, and validations, you enhance your API’s documentation and empower developers with tools that generate robust code and insightful documentation.&lt;/p&gt;

&lt;p&gt;Remember, in the world of API design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity is non-negotiable.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precision saves time down the line.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit definitions lead to better tooling integration.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these practices, you’ll create OpenAPI specs that are as versatile and reliable as the APIs they describe.&lt;/p&gt;

&lt;p&gt;Ready to take your API specifications to the next level? Explore more tips, best practices, and tools for creating bulletproof API documentation and client libraries at liblab.&lt;/p&gt;

&lt;p&gt;Happy spec writing!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.liblab.com/join" rel="noopener noreferrer"&gt;Sign up for liblab&lt;/a&gt; today and start generating SDKs for your APIs in minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally written for &lt;a href="https://liblab.com/blog/openapi-data-types-and-formats" rel="noopener noreferrer"&gt;the liblab blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>openapi</category>
      <category>devex</category>
    </item>
    <item>
      <title>How to build an SDK from scratch: Tutorial &amp; best practices</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Fri, 04 Oct 2024 12:24:06 +0000</pubDate>
      <link>https://dev.to/liblab/how-to-build-an-sdk-from-scratch-tutorial-best-practices-3nh0</link>
      <guid>https://dev.to/liblab/how-to-build-an-sdk-from-scratch-tutorial-best-practices-3nh0</guid>
      <description>&lt;p&gt;Life is too short to spend on writing boilerplate code, or dealing with the complexities of lowest common denominator tooling. I want to focus on the business problem I'm trying to solve, not the plumbing.&lt;/p&gt;

&lt;p&gt;This is why I'm always a fan of a well-crafted &lt;strong&gt;SDK&lt;/strong&gt;, a tool that makes it easy to use a service or API. In this post we look at the process of &lt;strong&gt;creating SDKs&lt;/strong&gt;, from concept to creation, and show how you can automate the process using &lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;liblab&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an SDK?
&lt;/h2&gt;

&lt;p&gt;Let's start with the basic question - what is an SDK? An SDK, short for &lt;strong&gt;Software Development Kit&lt;/strong&gt;, is a set of tools written in one or more programming languages that make it easier to use a service or API. For this post, I will focus on SDKs for APIs, providing a wrapper around the direct REST calls that a user might make against an API.&lt;/p&gt;

&lt;p&gt;An SDK is a great abstraction layer. It is written in the language the developer uses, and provides language idiomatic ways to call the API, managing all the hard stuff for you such as the HTTP calls, the mapping of JSON to objects, authentication, retries, and so on.&lt;/p&gt;

&lt;p&gt;A good SDK drastically reduces the code you have to write.&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of an SDK
&lt;/h2&gt;

&lt;p&gt;SDKs are important to improve the developer experience of using your service or API. They allow your users to focus on the business problem they are trying to solve, rather than the plumbing of calling your API. This is just as important for public facing APIs from SaaS companies, as it is for internal APIs used by your own developers from your corporate microservices.&lt;/p&gt;

&lt;p&gt;Some benefits include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intellisense and code completion&lt;/strong&gt; - you can see the methods and properties available to you, and the parameters they take in your IDE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; - the SDK can handle the authentication process for you, so you don't have to worry about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built in best practices&lt;/strong&gt; - you can embed best practices inside the SDK, such as retry logic, so that if a call fails due to rate limiting, the SDK will automatically retry the call after a short delay.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To learn more about the comparison between SDKs and calling APIs directly, check out our post &lt;a href="https://liblab.com/blog/sdk-vs-api/" rel="noopener noreferrer"&gt;SDK vs API, key distinctions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Build an SDK
&lt;/h2&gt;

&lt;p&gt;Creating SDKs is a multi-step process, and is very time consuming. Not only do you need to design and build the SDK, but you also will want to create SDKs in multiple languages to support your users needs.&lt;/p&gt;

&lt;p&gt;This might be less important if you are building SDKs for internal APIs and you only use a single language - for example if you are a Java shop you may only need a Java SDK. However, if you are building a public facing API, you will want to support as many programming languages as possible, so that your users can use the language they are most comfortable with. You will probably want a TypeScript SDK or JavaScript SDK, a Python SDK, a C# SDK, a Java SDK, and so on depending on the programming language priorities of your users.&lt;/p&gt;

&lt;p&gt;The steps you would take are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Design your SDK&lt;/li&gt;
&lt;li&gt;Build your SDK&lt;/li&gt;
&lt;li&gt;Document your SDK&lt;/li&gt;
&lt;li&gt;Test your SDK&lt;/li&gt;
&lt;li&gt;Publish your SDK&lt;/li&gt;
&lt;li&gt;Maintain your SDK&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Design your SDK
&lt;/h3&gt;

&lt;p&gt;The first step is to design the SDK. A typical pattern is to mimic the &lt;strong&gt;API surface&lt;/strong&gt;, providing functions that act like your API endpoints. This is a great way to build an SDK - it means your documentation and other user guides can be essentially the same for your API and SDKs, with just different sample code to use the SDK rather than make an API call.&lt;/p&gt;

&lt;h4&gt;
  
  
  API specification
&lt;/h4&gt;

&lt;p&gt;To do this you will need to know how your API works, which is why it is important that your API has documentation, ideally an &lt;strong&gt;API specification&lt;/strong&gt; such as an &lt;strong&gt;OpenAPI spec&lt;/strong&gt;. Some API designers will start from an OpenAPI spec, others will start with code and autogenerate the OpenAPI spec from that code. Either way, you need to have a good understanding of your API before you can start to design your SDK.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The act of designing your SDK can also be a great way to validate that you have a good, clean API design. If you find that your SDK is hard to design, or that you have to do a lot of work to make it easy to use, then this is a good sign that your API needs improvement. For some tips, check out our post on &lt;a href="https://liblab.com/blog/why-your-open-api-spec-sucks/" rel="noopener noreferrer"&gt;why your OpenAPI spec sucks&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Paths and components
&lt;/h4&gt;

&lt;p&gt;OpenAPI specs have 2 sections that make designing your SDK easier - &lt;code&gt;paths&lt;/code&gt; and &lt;code&gt;components&lt;/code&gt;. The &lt;code&gt;paths&lt;/code&gt; section defines the &lt;strong&gt;endpoints&lt;/strong&gt; of your API, and the &lt;code&gt;components&lt;/code&gt; section defines reusable components, such as schemas for &lt;strong&gt;request&lt;/strong&gt; and &lt;strong&gt;response&lt;/strong&gt; bodies, or security schemes.&lt;/p&gt;

&lt;p&gt;You want to use &lt;code&gt;components&lt;/code&gt; as much as possible to make it easier to understand the data that is being passed around. Using &lt;code&gt;components&lt;/code&gt; also helps you to them as much as possible between endpoints.&lt;/p&gt;

&lt;p&gt;For example, if you have an endpoint that returns a single user, it is cleaner to have that user defined as a &lt;code&gt;components/schema/user&lt;/code&gt; object. You can then reference that in the endpoint that gets a single user, and wrap it as an array for an endpoint that gets multiple users.&lt;/p&gt;

&lt;h4&gt;
  
  
  From API spec to an SDK design
&lt;/h4&gt;

&lt;p&gt;Once you have your API spec, you can start to design your SDK. A good design is to provide objects that wrap the requests and responses for your API endpoints, and methods that call the API endpoints.&lt;/p&gt;

&lt;p&gt;You will need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What objects will encapsulate the &lt;code&gt;components&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;How &lt;code&gt;paths&lt;/code&gt; will be grouped and wrapped as methods&lt;/li&gt;
&lt;li&gt;The interface to handle authentication&lt;/li&gt;
&lt;li&gt;Each SDK language will have different idioms, libraries and best practices. You will need to decide how to handle these differences. This might be a challenge if you are not familiar with the language.&lt;/li&gt;
&lt;li&gt;How to handle best practices such as retries. Do you implement this yourself, or use a library?&lt;/li&gt;
&lt;li&gt;Naming conventions. It is important to create SDKs that use idiomatic code for the SDK language - for example, if you are building a Python SDK, you want to use Python idioms such as using &lt;code&gt;snake_case&lt;/code&gt; for method names, and &lt;code&gt;PascalCase&lt;/code&gt; for class names, whereas TypeScript would use &lt;code&gt;camelCase&lt;/code&gt; for method names.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Build your SDK
&lt;/h3&gt;

&lt;p&gt;After you have designed your SDK, you can start to build the code implementation. This is a manual process, and is very time consuming, especially if you have SDKs in multiple languages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Components
&lt;/h4&gt;

&lt;p&gt;First you want to create objects to wrap the requests and responses for your API endpoints, defined in the &lt;code&gt;components/schemas&lt;/code&gt; section of your OpenAPI spec. These objects are often referred to as models or DTOs (data transformation objects). These are usually 'simple' objects that have properties that map to the properties on the schema, and allow you to write JSON mapping code (or use a built in library) to automatically map the JSON to the object.&lt;/p&gt;

&lt;p&gt;Sometimes the objects can be more complex. For example if your API specification defines an &lt;code&gt;anyOf&lt;/code&gt; or &lt;code&gt;oneOf&lt;/code&gt; - an endpoint that can return one of a range of possible types. Some languages can support this through a union type, others cannot, so you will need to decide how to handle these types. Remember, you need to do this for every &lt;strong&gt;SDK language&lt;/strong&gt; you want to support.&lt;/p&gt;

&lt;h4&gt;
  
  
  SDK methods
&lt;/h4&gt;

&lt;p&gt;Once you have your models, you can start to build the SDK methods that call your &lt;strong&gt;API endpoints&lt;/strong&gt;. These functions can take models as parameters, and return the models as responses.&lt;/p&gt;

&lt;p&gt;You will need to handle making HTTP requests, and the mapping of JSON to objects. You will also need to handle the authentication process, and any other best practices you want to build in such as persisting the HTTP connection, retries and logging.&lt;/p&gt;

&lt;p&gt;These methods might also need parameters to match the parameters for the endpoint - both path parameters and query parameters.&lt;/p&gt;

&lt;p&gt;For example, if the endpoint is &lt;code&gt;GET /llama/{id}&lt;/code&gt; with the Id as a path parameter, you might have a method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Llama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseService&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_llama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Llama&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the llama Id becomes a method parameter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Grouping methods
&lt;/h4&gt;

&lt;p&gt;A good practice is to group these functions into service classes. You might want to do it based off the endpoint - for example having the GET, POST, and PUT methods for a single endpoint in a single class.&lt;/p&gt;

&lt;p&gt;API specifications can also define groupings of endpoints, such as &lt;strong&gt;OpenAPI tags&lt;/strong&gt;, so you might want to group your functions based on these tags. You know your API, so pick a technique that works for you.&lt;/p&gt;

&lt;p&gt;As you build these methods, you should abstract out as much logic as possible into base service classes, or helper methods. For example, you might want to abstract out the HTTP request logic, the JSON mapping logic, the authentication logic, and the retry logic. This way you can define it once, and share the logic with all your service methods.&lt;/p&gt;

&lt;h4&gt;
  
  
  SDK client
&lt;/h4&gt;

&lt;p&gt;Finally you will want to put some kind of wrapper object, usually referred to as an SDK client, around the endpoints. This will be the single place to surface authentication, setting different URLs if you have a multi-tenant API, or support different API regions or environments. This is your users entry point to the SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Llamastore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The llama service
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llama_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LlamaService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Set a different URL for different environments
&lt;/span&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_base_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;# Set the API access token
&lt;/span&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Document your SDK
&lt;/h3&gt;

&lt;p&gt;An SDK is only as good as its &lt;strong&gt;SDK documentation&lt;/strong&gt;. As you create SDKs, you will also need to write documentation that shows how to install, configure, and use the SDK. You will need to keep the documentation in sync with the SDK, and update it as the SDK evolves. This will then need to be published to a documentation web page, or included in the SDK package.&lt;/p&gt;

&lt;p&gt;OpenAPI specs support inline documentation, from descriptions of &lt;code&gt;paths&lt;/code&gt; and &lt;code&gt;components&lt;/code&gt;, to examples of parameters and responses. This is a great way to document your API, and you can use this to generate &lt;strong&gt;proper documentation&lt;/strong&gt; for your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Test your SDK
&lt;/h3&gt;

&lt;p&gt;Once your SDK is built, you need to ensure that it works as expected. This means writing unit tests that verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The JSON expected by and returned by your API can map to the objects you have created&lt;/li&gt;
&lt;li&gt;The HTTP requests are being made correctly by the SDK methods to the right endpoints&lt;/li&gt;
&lt;li&gt;Authentication is implemented correctly&lt;/li&gt;
&lt;li&gt;The best practices such as retries work as expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should write unit tests that mock the real endpoint, as well as integration tests that call a real endpoint in a sandbox or other test environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Publish your SDK
&lt;/h3&gt;

&lt;p&gt;Your finished SDK needs to be in the hands of your users. This means publishing it to a package manager, such as npm for JavaScript, or PyPi for Python.&lt;/p&gt;

&lt;p&gt;For every SDK language you will need to create the relevant package manifest, with links to your SDK documentation, and publish it to the package manager. For internal SDKs, you might want to publish it to a private package manager, such as GitHub packages, or a private npm registry.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Maintain your SDK
&lt;/h3&gt;

&lt;p&gt;It's not enough to just create SDKs once. As your API evolves, you need to update your both your SDK and SDK documentation to reflect the changes. This is a manual process, and is very time consuming, especially if you have SDKs in multiple languages.&lt;/p&gt;

&lt;p&gt;Your users will expect your SDK to be in sync with your API, ideally releasing new features to your SDK as soon as they are released to the API. As well as the engineering effort to update the SDK and SDK documentation, you also need to ensure that during SDK development, your internal processes track API updates, create tickets for the work to update the SDK, and ensure that the SDK is released at the same time as the API.&lt;/p&gt;

&lt;p&gt;Every new endpoint would mean a new SDK method, or a new class depending on how you have structured your SDK. Every new schema is a new model class. Every change to an existing endpoint or schema is a change to the existing SDK method or model class. You may also need to update any best practices, such as supporting new authentication schemes, or adding new retry logic.&lt;/p&gt;

&lt;p&gt;You will also need to track breaking changes, and update your SDK version as appropriate - a major version bump for breaking changes, a minor version bump for new features, and a patch version bump for bug fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices for building the perfect SDK
&lt;/h2&gt;

&lt;p&gt;When building an SDK, there are a number of best practices you should follow to ensure that your SDK is easy to use, and works well for your users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provide good documentation and examples&lt;/strong&gt; - your API spec should be full of well written descriptions, examples, and other documentation that can be ported to your SDK. This will make it easier for your users to get started quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use idiomatic code&lt;/strong&gt; - your SDK should use the idioms of the language you are building the SDK for. It should match the language's naming conventions, use standard libraries, and follow the language's best practices. For example, using &lt;code&gt;requests&lt;/code&gt; in Python, making all your C# methods &lt;code&gt;async&lt;/code&gt;, using TypeScript's &lt;code&gt;Promise&lt;/code&gt; for asynchronous methods, and so on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed security best practices&lt;/strong&gt; - take advantage of security best practices, from using the latest version of any dependencies with mechanisms to monitor for patches and provide updates, to using the latest security protocols and libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle authentication&lt;/strong&gt; - your SDK should handle authentication for your users. This might be as simple as providing a method to set an API key, or as complex as handling OAuth2. You should also provide a way to handle different environments, such as development, staging, and production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automating the SDK build with liblab
&lt;/h2&gt;

&lt;p&gt;Creating SDKs is a lot of work that only gets bigger as your API grows, or you want to support more languages. This is where automation is your friend. &lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;&lt;strong&gt;liblab&lt;/strong&gt;&lt;/a&gt; is a tool that can take your API specification, such as an OpenAPI spec, and &lt;strong&gt;autogenerate SDKs&lt;/strong&gt; for you in multiple languages.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://liblab.com/blog/sdk-generation/" rel="noopener noreferrer"&gt;SDK generation&lt;/a&gt; process will generate the models and service classes for you, with all the required mapping code. It will also generate your best practices such as authentication and retries, and you can configure these via a &lt;a href="https://developers.liblab.com/cli/config-file-overview" rel="noopener noreferrer"&gt;configuration file&lt;/a&gt;. You can also write code that is injected into the API lifecycle to add additional functionality, such as logging or custom authentication with the &lt;a href="https://developers.liblab.com/concepts/hooks/" rel="noopener noreferrer"&gt;liblab hooks feature&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jzoym5t2um9jihb4bes.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jzoym5t2um9jihb4bes.jpg" alt="The flow for using liblab - an api spec and config file goes in, and an SDK and documentation comes out."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK generation is fast! A typical developer flow is to spend a few hours generating SDKs the first time as you configure the generation process to meet your needs. This is an iterative cycle of generate, check, adjust the configuration, then regenerate. Once you have your configuration the way you need, your SDKs are generated in seconds.&lt;/p&gt;

&lt;p&gt;Adding more &lt;a href="https://developers.liblab.com/cli/config-file-overview-language/" rel="noopener noreferrer"&gt;SDK languages&lt;/a&gt; is also fast - you add the new language to the configuration file, and regenerate.&lt;/p&gt;

&lt;p&gt;liblab can also help you to keep your SDKs in sync with your API. As your API is updated, your SDK can be re-generated to match. For example, if your API spec lives in a git repository, you can &lt;a href="https://developers.liblab.com/tutorials/integrate-with-github-actions/" rel="noopener noreferrer"&gt;set up a GitHub action&lt;/a&gt; to detect any changes, and regenerate your SDK, publishing the new SDK source code to your SDK repositories.&lt;/p&gt;

&lt;p&gt;Finally liblab can &lt;strong&gt;generate your &lt;a href="https://developers.liblab.com/concepts/docs/" rel="noopener noreferrer"&gt;SDK documentation&lt;/a&gt;&lt;/strong&gt; for you, with full code examples and all the documentation you need to get started. This is taken from your API specification, so is always in sync with your API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqqtdxa5pi1w37g474pg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqqtdxa5pi1w37g474pg.jpeg" alt="Screenshot from liblab UI indicating list pets and query attributes with an example of an SDK code and response fields"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SDKs are a powerful way to improve the developer experience of your API. They come with a cost - the amount of work needed to generate them. This is why automation is so important. With &lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;liblab&lt;/a&gt; you can automate the process of generating SDKs, and keep them in sync with your API as it evolves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://liblab.com/join" rel="noopener noreferrer"&gt;Sign up for liblab today&lt;/a&gt; and start generating SDKs for your APIs in minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally written by Jim Bennett for the &lt;a href="https://liblab.com/blog/how-to-build-an-sdk/" rel="noopener noreferrer"&gt;liblab blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>api</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>documentation</category>
    </item>
    <item>
      <title>How to add Retrieval-Augmented Generation (RAG) to your app using generated SDKs</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Thu, 03 Oct 2024 20:20:36 +0000</pubDate>
      <link>https://dev.to/liblab/how-to-add-retrieval-augmented-generation-rag-to-your-app-using-generated-sdks-551l</link>
      <guid>https://dev.to/liblab/how-to-add-retrieval-augmented-generation-rag-to-your-app-using-generated-sdks-551l</guid>
      <description>&lt;p&gt;Everyone has heard of &lt;strong&gt;ChatGPT&lt;/strong&gt;, the popular &lt;strong&gt;large language model&lt;/strong&gt; (LLM) that can generate human like text, answering any question you may have with a certain degree of correctness. However, the biggest problem with these large language models is that they only have a limited amount of 'knowledge' to draw on - they are trained using data from the internet up to a particular date, and that is it.&lt;/p&gt;

&lt;p&gt;For example, if you ask an LLM what todays date is, or what the weather is like in a particular city, it will not be able to answer you - it just doesn't have that data.&lt;/p&gt;

&lt;p&gt;This lack of data also limits an LLMs ability to answer questions, or &lt;strong&gt;reason&lt;/strong&gt;, based off &lt;strong&gt;your own data&lt;/strong&gt;. For example, if you have a database of customer reviews, and you want to ask the LLM a question about the reviews, it will not be able to answer you as it simply doesn't have access to that data. This is where &lt;strong&gt;retrieval augmented generation&lt;/strong&gt; (RAG) comes in, allowing you to retrieve data from your own systems to augment what the LLM can reason over.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RAG?
&lt;/h2&gt;

&lt;p&gt;Retrieval augmented generation, or &lt;strong&gt;RAG&lt;/strong&gt;, is the term for &lt;strong&gt;augmenting&lt;/strong&gt; the data that goes into the LLM by &lt;strong&gt;retrieving&lt;/strong&gt; data from other systems, and use that data to help the LLM &lt;strong&gt;generate&lt;/strong&gt; answers to your questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  RAG example
&lt;/h3&gt;

&lt;p&gt;For example, if you have an app that will prompt an LLM to give you the average sentiment of a particular product, you can use RAG to augment the LLM with the customer reviews of that product by extracting the relevant data from your reviews database, then sending that data to the LLM to reason over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt98wkma0kzm437rdjyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt98wkma0kzm437rdjyi.png" alt="Sequence diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How does your app implement RAG?
&lt;/h3&gt;

&lt;p&gt;If you have a prompt-based app that allows the user to interact using pure text, then your app will start from a prompt that is user generated, such as &lt;code&gt;"What is the average sentiment of the cuddly llama toy"&lt;/code&gt;. Your app will then use some kind of LLM-powered app framework that has plugins - these are add-ons in the app that can retrieve data. This framework will use the LLM to determine which plugins it needs to call to get data, then send that data back to the LLM to reason over with an updated prompt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjxp40jsrusjii4gy7xk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjxp40jsrusjii4gy7xk.png" alt="Sequence Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you add RAG to your LLM app?
&lt;/h2&gt;

&lt;p&gt;One of the best ways to build an LLM app is to use some kind of AI app framework, such as &lt;a href="https://learn.microsoft.com/semantic-kernel/" rel="noopener noreferrer"&gt;Semantic Kernel&lt;/a&gt;, or &lt;a href="https://www.langchain.com" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;. These frameworks support multiple programming languages, and work with your LLM of choice, for example you can build an app in Python using LangChain that uses &lt;a href="https://llama.meta.com" rel="noopener noreferrer"&gt;Llama 2&lt;/a&gt;, or an app in C# using Semantic Kernel that uses &lt;a href="https://openai.com" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;. These frameworks have a range of features built in that you would want for an LLM app, such as memory so that the results of one prompt can be used in the next.&lt;/p&gt;

&lt;p&gt;These frameworks also support plugins - add-ons that you can build to extend the capability of the LLM, supporting tasks such as RAG. These plugins advertise their capabilities to the framework, and the LLM can use this information to decide which plugins to use depending on the prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you build a plugin?
&lt;/h3&gt;

&lt;p&gt;Plugins are built in the same language that you use to build your LLM app with the framework. For example, if you are building a C# app using Semantic Kernel, then you would build your plugin in C#. As part of defining your plugin, you provide a natural language description of what your plugin can do, and the framework will use this to decide which plugins to use.&lt;/p&gt;

&lt;p&gt;Here's an example of the outline of a simple C# plugin for Semantic Kernel that retrieves cat facts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CatFactPlugin&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Gets a cat fact."&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetCatFact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something here to get a cat fact&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where does the data come from?
&lt;/h3&gt;

&lt;p&gt;RAG is &lt;strong&gt;retrieval&lt;/strong&gt; augmented generation, so the data that you use to augment the LLM has to be &lt;strong&gt;retrieved&lt;/strong&gt; from somewhere. This could be a third party system, or ir could be one of your own internal systems. And typically you would access these systems via an API. So although we are in the shiny new world of AI, we are still back to the age old problem - we have to integrate with an API. And this means reading the API docs, worrying about authentication and retry strategies, building some JSON to make the request, and then parsing the JSON response, and all the issues that come with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do SDKs help with RAG?
&lt;/h3&gt;

&lt;p&gt;Let's be honest here - very few developers will interact directly with an API. We all write some kind of layer of abstraction over the API to make it easier to use. We write it, and we have to maintain it, which is a lot of work.&lt;/p&gt;

&lt;p&gt;This is where generated &lt;strong&gt;SDKs&lt;/strong&gt; come in. SDKs are &lt;a href="https://dev.to/blog/sdk-examples/"&gt;&lt;strong&gt;software development kits&lt;/strong&gt;&lt;/a&gt; that wrap the API, and provide a simpler way to interact with the API, the ultimate layer of abstraction. By using an SDK, you have strong typing (depending on your programming language of choice of course), best practices like authentication built in, and you don't have to worry about the JSON parsing. You also get autocomplete in your IDE, the ability for AI coding tools like GitHub copilot to help you, and inline documentation.&lt;/p&gt;

&lt;p&gt;And the best thing about generated SDKs is that they are &lt;strong&gt;automatically&lt;/strong&gt; generated from your &lt;a href="https://dev.to/blog/april-fools-open-api-tips-and-tricks/"&gt;OpenAPI spec&lt;/a&gt;. This means that you don't have to write the SDK, or maintain it - you just generate it, then use it. And once generated, it can be &lt;a href="https://developers.liblab.com/tutorials/integrate-with-github-actions/" rel="noopener noreferrer"&gt;kept up to date automatically inside your CI/CD pipelines&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating SDKs for your RAG plugins
&lt;/h2&gt;

&lt;p&gt;When it comes to generating SDKs, &lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;liblab&lt;/a&gt; is your friend. liblab is a platform that generates SDKs from your OpenAPI spec, so you can use them in your app. Whether you are accessing internal APIs, or third party APIs, all you need is an API spec, and liblab will generate the SDK for you.&lt;/p&gt;

&lt;p&gt;We've recently released a full tutorial that will walk you through how to add retrieval augmented generation (RAG) to your AI app using autogenerated SDKs that wrap your internal APIs. This tutorial uses Semantic Kernel and ChatGPT, along with the C# SDK generation capabilities of liblab, and takes you through the process of building a plugin that retrieves cat facts, and using that plugin in your app. Whilst cat facts are important, I understand you probably want to use your own internal systems, but the same principals apply to any API!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvow3dsfjljw42hjmlrf5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvow3dsfjljw42hjmlrf5.jpeg" alt="A cute plushie cat sitting on a laptop keyboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check it out &lt;a href="https://developers.liblab.com/tutorials/rag-with-sdk/" rel="noopener noreferrer"&gt;on the liblab developer portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, to implement the cat fact plugin mentioned earlier, you could use the &lt;a href="https://catfact.ninja" rel="noopener noreferrer"&gt;Cat Facts API&lt;/a&gt;. Using liblab, you can generate a C# SDK for the Cat Facts API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find a &lt;a href="https://github.com/liblaber/build-a-rag-ai-app-template/blob/main/sdks/cat-facts/liblab.config.json" rel="noopener noreferrer"&gt;liblab config file&lt;/a&gt; to generate the cat facts SDK in a template repo we've published to augment the tutorial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have the cat facts SDK, you can use it in your plugin to retrieve cat facts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;CatFacts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CatFactPlugin&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;CatFactsClient&lt;/span&gt; &lt;span class="n"&gt;_client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Gets a cat fact."&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetCatFact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CatFactPlugin &amp;gt; Getting a cat fact from the Cat Facts API..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRandomFactAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CatFactPlugin &amp;gt; Cat fact: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we just have 2 lines of code to get the cat facts from the SDK — the declaration of a field to hold the SDK client, and the call to the SDK to get the cat fact. The SDK takes care of all the complexity of calling the API, and parsing the response. Much nicer than writing all that code yourself!&lt;/p&gt;

&lt;p&gt;This plugin can then be used in your app to retrieve cat facts, and augment the LLM with the data. For example, having the LLM give you the cat fact in the style of a pirate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User &amp;gt; Give me a fact about cats in the style of a pirate
CatFactPlugin &amp;gt; Getting a cat fact from the Cat Facts API...
CatFactPlugin &amp;gt; Cat fact: A group of cats is called a clowder.
Assistant &amp;gt; Arr matey! Be ye knowin' that a gatherin' of meowin' seafarers,
them cats, be called a clowder? Aye, a fine group of whiskered buccaneers they be!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n7lgf2l0umx6wf2cca1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n7lgf2l0umx6wf2cca1.jpeg" alt="A cute plushie cat dressed as a pirate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, maybe less helpful in the real world, but you get the idea! In the real world you could use the LLM to reason over your own data, for example retrieving data from an internal review system, and providing a list of the most popular products based off the reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Adding retrieval augmented generation (RAG) to your AI app can be a powerful way to help your LLM reason over your own data. Using autogenerated SDKs to wrap your internal APIs makes it easier to add RAG to your app, giving you more time to focus on building the best AI experience for your users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;Get started with liblab today!&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally written by Jim Bennett for the &lt;a href="https://liblab.com/blog/rag-with-sdks/" rel="noopener noreferrer"&gt;liblab blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>api</category>
      <category>programming</category>
      <category>csharp</category>
      <category>rag</category>
    </item>
    <item>
      <title>6 Practical tools for building a great engineering culture</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Wed, 02 Oct 2024 13:13:35 +0000</pubDate>
      <link>https://dev.to/liblab/6-practical-tools-for-building-a-great-engineering-culture-1boe</link>
      <guid>https://dev.to/liblab/6-practical-tools-for-building-a-great-engineering-culture-1boe</guid>
      <description>&lt;p&gt;At &lt;a href="https://liblab.com" rel="noopener noreferrer"&gt;liblab&lt;/a&gt;, we tackle complex engineering problems to build SDKs for our customers and their end users, who are engineers themselves. Our team's extensive knowledge in software, software-as-a-service solutions, and developer tools is critical to our success. Therefore, retaining our talented developers is a priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you care about engineering culture?
&lt;/h2&gt;

&lt;p&gt;While it's often said that people leave managers, not jobs, it's equally true that engineers leave companies with poor culture. Engineering culture, shaped by the attitudes and experiences of software developers and team leaders, influences the working atmosphere. By understanding the importance of engineering culture, we can enhance the positive aspects and minimize the negative ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical tools for fostering a great engineering culture
&lt;/h2&gt;

&lt;p&gt;There's a lot of discussion about building a great engineering culture on the internet. However, I'm focusing on practical tools here. These are concrete steps anyone can take to improve their team's culture and their own contributions.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Coding style and standards
&lt;/h3&gt;

&lt;p&gt;Coding style is an aspect of engineering culture. It's not about specific preferences - we're not engaging in the tabs versus spaces debate! - but how coding style is shared across the team. Often, one "tastemaker" can influence the team's preferred style. If one engineer is the sole torchbearer, the implementation can seem arbitrary, and enforcing that style in code reviews with the wrong tone can alienate coworkers.&lt;/p&gt;

&lt;p&gt;A coding standards document covers basic expectations like naming variables and functions, commit comments, and best practices. Creating these standards with feedback from the team fosters consensus and buy-in. Implementing a corresponding linting solution in the team’s IDEs and code repositories can clarify expectations and allow for early and regular corrections by the system, not a peer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Developer tool choice
&lt;/h3&gt;

&lt;p&gt;Another aspect of coding standards to consider is allowing tool choice. Not every developer likes the same IDE - some even prefer a traditional text editor! Allowing engineers to choose the solutions they’re most comfortable with will improve their satisfaction and productivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Code reviews and pair programming
&lt;/h3&gt;

&lt;p&gt;Code reviews are routine tasks with a significant impact on culture. For engineers who don't pair on projects regularly, this could be their main professional interaction. Establishing a routine for code reviews ensures this important collaboration happens consistently. We recommend engineers spend time at the start of their day and after lunch on reviews to avoid a full-day wait for feedback. Alternatively, regular pair programming can reduce the need for code reviews since multiple engineers have evaluated the code already.&lt;/p&gt;

&lt;p&gt;While experienced engineers analyze the code for style, functionality, and performance, every engineer can contribute. Less experienced engineers should be able to understand the code and changes. Asking for more information on a new function is a great reminder to include detailed comments! Seeing how others solve problems can spark new ideas and questions, leading to mentoring or collaboration. Participating in code reviews fosters relationships between developers, improving collaboration and culture.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Architecture discussions
&lt;/h3&gt;

&lt;p&gt;Architecture discussions are some of my favorite times working in software engineering. Analyzing a problem, freely exchanging ideas, and incorporating elements into a cohesive solution represent the team's collective experience. Experienced engineers are naturally inclined to solve problems quickly, but these sessions are also opportunities to mentor and develop less experienced developers.&lt;/p&gt;

&lt;p&gt;Encouraging experienced engineers to speak last allows the rest of the team to work through the problem together. Making a single engineer responsible for the project and the final decision on technical matters encourages strong ownership. This approach can also encourage participation from less experienced engineers, since they know an experienced engineer is ultimately responsible for the design.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Design reviews
&lt;/h3&gt;

&lt;p&gt;Technical design reviews follow these architecture discussions. The responsible engineer details the proposed solution in a "request for comment" document, which the engineering team reviews asynchronously. If there are comments to consider, then a meeting is scheduled to discuss questions and collect feedback. This process gives every engineer a voice, promoting participation and an inclusive engineering culture.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hiring
&lt;/h3&gt;

&lt;p&gt;Hiring is another area where we can influence culture. New team members bring their own experiences and influence, but how we select them also matters. We at liblab prefer a take-home style coding challenge that closely reflects the daily developer experience. We've extensively discussed and iterated the content of this test, ending up with tests that target each of our engineering teams' focus areas.&lt;/p&gt;

&lt;p&gt;Creating the test, having coworkers take it for a baseline, and evaluating the results is an important part of engineering culture. It establishes a minimum standard for the team, and completing the coding challenge becomes a shared experience and a badge of belonging for those who join.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Here are some practical tools for fostering a great engineering culture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Promoting coding style through tools&lt;/li&gt;
&lt;li&gt;Allow engineers to use their preferred tools&lt;/li&gt;
&lt;li&gt;Setting ground rules for engineering discussions&lt;/li&gt;
&lt;li&gt;Conducting inclusive design reviews&lt;/li&gt;
&lt;li&gt;Regular code reviews and/or pair programming&lt;/li&gt;
&lt;li&gt;Involving engineers in hiring practices&lt;/li&gt;
&lt;li&gt;Anyone can adopt these practices within their own engineering team to enhance their culture. Teams should also experiment; what worked well for us at liblab might differ for your team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If our commitment to a great culture sounds appealing, then come join us! We are hiring for a range of roles, and you can find more details at &lt;a href="https://liblab.com/careers" rel="noopener noreferrer"&gt;liblab.com/careers&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was originally written by Adrian Luff for the &lt;a href="https://liblab.com/blog/tools-for-building-a-great-engineering-culture" rel="noopener noreferrer"&gt;liblab blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>api</category>
      <category>programming</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
